Skip to content

Commit

Permalink
Merge pull request terraforming-mars#2360 from kberg/moon7
Browse files Browse the repository at this point in the history
Moon 7: Fix Board.getAdjacentSpaces to work properly with the Moon.
  • Loading branch information
kberg authored Jan 14, 2021
2 parents 20a12cd + fe15f25 commit b3ffa9c
Show file tree
Hide file tree
Showing 22 changed files with 383 additions and 59 deletions.
28 changes: 21 additions & 7 deletions src/boards/Board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,20 @@ import {TileType} from '../TileType';
import {AresHandler} from '../ares/AresHandler';
import {SerializedBoard, SerializedSpace} from './SerializedBoard';

/**
* A representation of any hex board. This is normally Mars (Tharsis, Hellas, Elysium) but can also be The Moon.
*
* It also includes additional spaces, known as Colonies, that are not adjacent to other spaces.
*/
export abstract class Board {
public abstract spaces: Array<ISpace>;
private maxX: number = 0;
private maxY: number = 0;
protected constructor(public spaces: Array<ISpace>) {
spaces.forEach((space) => {
this.maxX = Math.max(this.maxX, space.x);
this.maxY = Math.max(this.maxY, space.y);
});
};

public abstract getVolcanicSpaceIds(): Array<string>;

Expand All @@ -21,24 +33,26 @@ export abstract class Board {
return space;
}

// getAdjacentSpaces expects an odd number of rows. If a funny shape appears, it can be addressed.
public getAdjacentSpaces(space: ISpace): Array<ISpace> {
const middleRow = this.maxY / 2;
if (space.spaceType !== SpaceType.COLONY) {
if (space.y < 0 || space.y > 8) {
throw new Error('Unexpected space y value');
if (space.y < 0 || space.y > this.maxY) {
throw new Error('Unexpected space y value: ' + space.y);
}
if (space.x < 0 || space.x > 8) {
throw new Error('Unexpected space x value');
if (space.x < 0 || space.x > this.maxX) {
throw new Error('Unexpected space x value: ' + space.x);
}
const leftSpace: Array<number> = [space.x - 1, space.y];
const rightSpace: Array<number> = [space.x + 1, space.y];
const topLeftSpace: Array<number> = [space.x, space.y - 1];
const topRightSpace: Array<number> = [space.x, space.y - 1];
const bottomLeftSpace: Array<number> = [space.x, space.y + 1];
const bottomRightSpace: Array<number> = [space.x, space.y + 1];
if (space.y < 4) {
if (space.y < middleRow) {
bottomLeftSpace[0]--;
topRightSpace[0]++;
} else if (space.y === 4) {
} else if (space.y === middleRow) {
bottomRightSpace[0]++;
topRightSpace[0]++;
} else {
Expand Down
5 changes: 0 additions & 5 deletions src/boards/ElysiumBoard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {ISpace} from './ISpace';
import {SpaceBonus} from '../SpaceBonus';
import {SpaceName} from '../SpaceName';
import {Board} from './Board';
Expand All @@ -8,10 +7,6 @@ import {Player} from '../Player';
import {Random} from '../Random';

export class ElysiumBoard extends Board {
private constructor(public spaces: Array<ISpace>) {
super();
}

public static newInstance(shuffle: boolean, rng: Random, includeVenus: boolean): ElysiumBoard {
const builder = new BoardBuilder(includeVenus);

Expand Down
4 changes: 0 additions & 4 deletions src/boards/HellasBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import {SerializedBoard} from './SerializedBoard';
import {Random} from '../Random';

export class HellasBoard extends Board {
private constructor(public spaces: Array<ISpace>) {
super();
}

public static newInstance(shuffle: boolean, rng: Random, includeVenus: boolean): HellasBoard {
const builder = new BoardBuilder(includeVenus);

Expand Down
4 changes: 0 additions & 4 deletions src/boards/OriginalBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import {SerializedBoard} from './SerializedBoard';
import {Random} from '../Random';

export class OriginalBoard extends Board {
private constructor(public spaces: Array<ISpace>) {
super();
}

public static newInstance(shuffle: boolean, rng: Random, includeVenus: boolean): OriginalBoard {
const builder = new BoardBuilder(includeVenus);

Expand Down
6 changes: 6 additions & 0 deletions src/cards/base/RoboticWorkforce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export class RoboticWorkforce extends Card implements IProjectCard {
CardName.MAGNETIC_FIELD_DOME,
CardName.MAGNETIC_FIELD_GENERATORS,
CardName.MAGNETIC_FIELD_GENERATORS_PROMO,
CardName.MARE_IMBRIUM_MINE,
CardName.MARE_NECTARIS_MINE,
CardName.MARE_NUBIUM_MINE,
// CardName.MARE_SERENITATIS_MINE,
CardName.MARTIAN_INDUSTRIES,
CardName.MARTIAN_MEDIA_CENTER,
CardName.MEDICAL_LAB,
Expand Down Expand Up @@ -307,7 +310,10 @@ export class RoboticWorkforce extends Card implements IProjectCard {
new Updater(CardName.MAGNETIC_FIELD_GENERATORS, -4, 0, 0, 0, 2, 0),
new Updater(CardName.MAGNETIC_FIELD_GENERATORS_PROMO, -4, 0, 0, 0, 2, 0),
new Updater(CardName.MANUTECH, 0, 0, 1, 0, 0, 0),
new Updater(CardName.MARE_IMBRIUM_MINE, 0, 0, 1, 1, 0, 0),
new Updater(CardName.MARE_NECTARIS_MINE, 0, 0, 1, 0, 0, 0),
new Updater(CardName.MARE_NUBIUM_MINE, 0, 0, 0, 1, 0, 0),
// new Updater(CardName.MARE_SERENITATIS_MINE, 0, 0, 1, 1, 0, 0),
new Updater(CardName.MARTIAN_INDUSTRIES, 1, 0, 1, 0, 0, 0),
new Updater(CardName.MARTIAN_MEDIA_CENTER, 0, 2, 0, 0, 0, 0),
new Updater(CardName.MEDICAL_LAB, 0, Math.floor(player.getTagCount(Tags.BUILDING) / 2), 0, 0, 0, 0),
Expand Down
43 changes: 43 additions & 0 deletions src/cards/moon/MareImbriumMine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {CardName} from '../../CardName';
import {Player} from '../../Player';
import {CardType} from '../CardType';
import {IProjectCard} from '../IProjectCard';
import {Tags} from '../Tags';
import {CardRenderer} from '../render/CardRenderer';
import {Resources} from '../../Resources';
import {MoonSpaces} from '../../moon/MoonSpaces';
import {MoonExpansion} from '../../moon/MoonExpansion';
import {Card} from '../Card';
import {Units} from '../../Units';

export class MareImbriumMine extends Card implements IProjectCard {
constructor() {
super({
name: CardName.MARE_IMBRIUM_MINE,
cardType: CardType.AUTOMATED,
tags: [Tags.MOON, Tags.BUILDING],
cost: 19,

metadata: {
description: 'Spend 1 titanium. Increase your steel production 1 step and your titanium production 1 step. Place a mine ON THE RESERVED AREA and raise Mining Rate 1 step.',
cardNumber: 'M03',
renderData: CardRenderer.builder((b) => {
b.minus().titanium(1);
b.production((pb) => pb.steel(1).titanium(1)).br;
b.moonMine().asterix();
}),
},
});
}

public reserveUnits = Units.of({titanium: 1});

public play(player: Player) {
Units.deductUnits(this.reserveUnits, player);
player.addProduction(Resources.STEEL, 1);
player.addProduction(Resources.TITANIUM, 1);
MoonExpansion.addMineTile(player, MoonSpaces.MARE_IMBRIUM, this.name);
MoonExpansion.raiseMiningRate(player);
return undefined;
}
}
41 changes: 41 additions & 0 deletions src/cards/moon/MareNubiumMine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {CardName} from '../../CardName';
import {Player} from '../../Player';
import {CardType} from '../CardType';
import {IProjectCard} from '../IProjectCard';
import {Tags} from '../Tags';
import {CardRenderer} from '../render/CardRenderer';
import {Resources} from '../../Resources';
import {MoonSpaces} from '../../moon/MoonSpaces';
import {MoonExpansion} from '../../moon/MoonExpansion';
import {Card} from '../Card';
import {Units} from '../../Units';

export class MareNubiumMine extends Card implements IProjectCard {
constructor() {
super({
name: CardName.MARE_NUBIUM_MINE,
cardType: CardType.AUTOMATED,
tags: [Tags.MOON, Tags.BUILDING],
cost: 17,

metadata: {
description: 'Spend 1 titanium. Increase your titanium production 1 step. Place a mine ON THE RESERVED AREA and raise Mining Rate 1 step.',
cardNumber: 'M02',
renderData: CardRenderer.builder((b) => {
b.minus().titanium(1);
b.production((pb) => pb.titanium(1)).moonMine().asterix();
}),
},
});
}

public reserveUnits = Units.of({titanium: 1});

public play(player: Player) {
Units.deductUnits(this.reserveUnits, player);
player.addProduction(Resources.TITANIUM, 1);
MoonExpansion.addMineTile(player, MoonSpaces.MARE_NUBIUM, this.name);
MoonExpansion.raiseMiningRate(player);
return undefined;
}
}
12 changes: 6 additions & 6 deletions src/cards/moon/MoonCardManifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ import {CardManifest} from '../CardManifest';
// import {LunaTradeFederation} from './LunaTradeFederation';
// import {LunaTradeStation} from './LunaTradeStation';
// import {LunaTrainStation} from './LunaTrainStation';
// import {MareImbriumMine} from './MareImbriumMine';
import {MareImbriumMine} from './MareImbriumMine';
import {MareNectarisMine} from './MareNectarisMine';
// import {MareNubiumMine} from './MareNubiumMine';
import {MareNubiumMine} from './MareNubiumMine';
// import {MareSerenitatisMine} from './MareSerenitatisMine';
// import {MicrosingularityPlant} from './MicrosingularityPlant';
// import {MiningComplex} from './MiningComplex';
Expand Down Expand Up @@ -100,11 +100,11 @@ export const MOON_CARD_MANIFEST = new CardManifest({
module: GameModule.Moon,
projectCards: [
// These cards are done.
// // These cards have behavior and rendering.
{cardName: CardName.MARE_NECTARIS_MINE, Factory: MareNectarisMine},
// {cardName: CardName.MARE_NUBIUM_MINE, Factory: MareNubiumMine},
// {cardName: CardName.MARE_IMBRIUM_MINE, Factory: MareImbriumMine},
// {cardName: CardName.MARE_SERENITATIS_MINE, Factory: MareSerenitatisMine},
// // These cards have behavior and rendering.
{cardName: CardName.MARE_NUBIUM_MINE, Factory: MareNubiumMine},
{cardName: CardName.MARE_IMBRIUM_MINE, Factory: MareImbriumMine},
// {cardName: CardName.MARE_SERENITATIS_MINE, Factory: MareSerenitatisMine},
// {cardName: CardName.HABITAT_14, Factory: Habitat14},
// {cardName: CardName.GEODESIC_TENTS, Factory: GeodesicTents},
// {cardName: CardName.SPHERE_HABITATS, Factory: SphereHabitats},
Expand Down
4 changes: 0 additions & 4 deletions src/moon/MoonBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ class Space implements ISpace {
}

export class MoonBoard extends Board {
private constructor(public spaces: Array<ISpace>) {
super();
}

public getNoctisCitySpaceIds() {
return [];
}
Expand Down
28 changes: 14 additions & 14 deletions src/moon/MoonExpansion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ export class MoonExpansion {
// MoonExpansion.addTile(player, spaceId, {tileType: TileType.MOON_COLONY, card: cardName});
// }

// public static addRoadTile(
// player: Player, spaceId: string, cardName: CardName | undefined = undefined): void {
// MoonExpansion.addTile(player, spaceId, {tileType: TileType.MOON_ROAD, card: cardName});
// }
public static addRoadTile(
player: Player, spaceId: string, cardName: CardName | undefined = undefined): void {
MoonExpansion.addTile(player, spaceId, {tileType: TileType.MOON_ROAD, card: cardName});
}

// Having a custom addTile isn't ideal, but game.addTile is pretty specific, and this
// isn't.
Expand Down Expand Up @@ -125,16 +125,16 @@ export class MoonExpansion {
// });
// }

// public static raiseLogisticRate(player: Player) {
// MoonExpansion.ifMoon(player.game, (moonData) => {
// if (moonData.logisticRate < 8) {
// moonData.logisticRate++;
// player.game.log('${0} raised the logistic rate 1 step', (b) => b.player(player));
// player.increaseTerraformRatingSteps(1, game);
// this.activateLunaFirst(player, player.game);
// }
// });
// }
public static raiseLogisticRate(player: Player) {
MoonExpansion.ifMoon(player.game, (moonData) => {
if (moonData.logisticRate < 8) {
moonData.logisticRate++;
player.game.log('${0} raised the logistic rate 1 step', (b) => b.player(player));
player.increaseTerraformRatingSteps(1, player.game);
this.activateLunaFirst(player, player.game);
}
});
}

private static activateLunaFirst(_sourcePlayer: Player | undefined, _game: Game) {
// const lunaFirstPlayer = MoonExpansion.moonData(game).lunaFirstPlayer;
Expand Down
30 changes: 30 additions & 0 deletions src/moon/PlaceMoonRoadTile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {DeferredAction} from '../deferredActions/DeferredAction';
import {SelectSpace} from '../inputs/SelectSpace';
import {Player} from '../Player';
import {Resources} from '../Resources';
import {MoonExpansion} from './MoonExpansion';

export class PlaceMoonRoadTile implements DeferredAction {
constructor(
public player: Player,
public title: string = 'Select a space on the Moon for a road tile.',
) {}

public execute() {
const moonData = MoonExpansion.moonData(this.player.game);
const spaces = moonData.moon.getAvailableSpacesOnLand(this.player);

if (spaces.length === 0) {
return undefined;
}
return new SelectSpace(
this.title,
spaces,
(space) => {
MoonExpansion.addRoadTile(this.player, space.id);
MoonExpansion.raiseLogisticRate(this.player);
this.player.addProduction(Resources.MEGACREDITS, 1, this.player.game);
return undefined;
});
}
}
2 changes: 1 addition & 1 deletion tests/ares/AresHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('AresHandler', function() {
player = TestPlayers.BLUE.newPlayer();
otherPlayer = TestPlayers.RED.newPlayer();
game = Game.newInstance('foobar', [player, otherPlayer], player, ARES_OPTIONS_NO_HAZARDS);
game.board = new EmptyBoard();
game.board = EmptyBoard.newInstance();
});


Expand Down
9 changes: 2 additions & 7 deletions tests/ares/EmptyBoard.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import {Board} from '../../src/boards/Board';
import {BoardBuilder} from '../../src/boards/BoardBuilder';
import {ISpace} from '../../src/boards/ISpace';

export class EmptyBoard extends Board {
public spaces: Array<ISpace>;
constructor() {
super();

public static newInstance() {
const builder = new BoardBuilder(false);

// y=0
Expand All @@ -28,9 +24,8 @@ export class EmptyBoard extends Board {
// y=8
builder.land().land().land().land().land();

this.spaces = builder.build();
return new EmptyBoard(builder.build());
}

public getVolcanicSpaceIds(): Array<string> {
return [];
}
Expand Down
Loading

0 comments on commit b3ffa9c

Please sign in to comment.