powergrid-engine 1.11.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,11 @@
1
+ // by John and Cici
2
+ import { cloneDeep } from 'lodash';
3
+ import seedrandom from 'seedrandom';
4
+ import { getPowerPlant } from '../engine';
5
+ import { PowerPlant } from '../gamestate';
6
+ import { shuffle } from '../utils';
1
7
  import { GameMap } from './../maps';
8
+ import { powerPlants } from './../powerPlants';
2
9
 
3
10
  export enum Regions {
4
11
  Orange = 'orange',
@@ -9,143 +16,267 @@ export enum Regions {
9
16
  }
10
17
 
11
18
  export enum Cities {
12
- Zimbaswe = 'Zimbaswe',
19
+ Zimbabwe = 'Zimbabwe',
13
20
  Musina = 'Musina',
14
21
  Botswana = 'Botswana',
15
22
  Polokwane = 'Polokwane',
16
- Pretoria1 = 'Pretoria 1',
17
- Pretoria2 = 'Pretoria 2',
18
- Rustenburc = 'Rustenburc',
23
+ PretoriaN = 'Pretoria N',
24
+ PretoriaS = 'Pretoria S',
25
+ Rustenburg = 'Rustenburg',
19
26
  Mozambique = 'Mozambique',
20
27
  Mbombela = 'Mbombela',
21
- Iswaini = 'Iswaini',
28
+ Eswatini = 'Eswatini',
22
29
  Germiston = 'Germiston',
23
- Johannesburg1 = 'Johannesburg 1',
24
- Johannesburg2 = 'Johannesburg 2',
30
+ JohannesburgN = 'Johannesburg N',
31
+ JohannesburgS = 'Johannesburg S',
25
32
  Ladysmith = 'Ladysmith',
26
- Abc = 'Abc',
27
- Def = 'Def',
28
- Ghi1 = 'Ghi 1',
29
- Ghi2 = 'Ghi 2',
30
- Jkl = 'Jkl',
31
- Mno = 'Mno',
32
- Qrs = 'Qrs',
33
- Keerksorp = 'Keerksorp',
34
- Weikom = 'Weikom',
35
- Xuruman = 'Xuruman',
33
+ Newcastle = 'Newcastle',
34
+ Pietermaritzburg = 'Pietermaritzburg',
35
+ DurbanN = 'Durban N',
36
+ DurbanS = 'Durban S',
37
+ Mthatha = 'Mthatha',
38
+ Lesotho = 'Lesotho',
39
+ Bloemfontein = 'Bloemfontein',
40
+ Klerksdorp = 'Klerksdorp',
41
+ Welkom = 'Welkom',
42
+ Kuruman = 'Kuruman',
36
43
  Kimberly = 'Kimberly',
37
- Upincion = 'Upincion',
38
- Sprincbom = 'Sprincbom',
44
+ Upington = 'Upington',
45
+ Springbok = 'Springbok',
39
46
  Namibia = 'Namibia',
40
- Deaar = 'Deaar',
41
- Beaufortwest = 'Beaufort West',
42
- Eastlondon = 'East London',
43
- Portelizabeth = 'Port Elizabeth',
44
- Ceorci = 'Ceorci',
45
- Capetown1 = 'Capetown 1',
46
- Capetown2 = 'Capetown2',
47
+ DeAar = 'De Aar',
48
+ BeaufortWest = 'Beaufort West',
49
+ EastLondon = 'East London',
50
+ PortElizabeth = 'Port Elizabeth',
51
+ George = 'George',
52
+ CapeTownN = 'Cape Town N',
53
+ CapeTownS = 'Cape Town S',
47
54
  }
48
55
 
49
56
  export const map: GameMap = {
50
57
  name: 'South Africa',
51
58
  cities: [
52
- { name: Cities.Zimbaswe, region: Regions.Orange, x: 1060, y: 29 },
53
- { name: Cities.Musina, region: Regions.Orange, x: 1027, y: 125 },
54
- { name: Cities.Botswana, region: Regions.Orange, x: 665, y: 186 },
55
- { name: Cities.Polokwane, region: Regions.Orange, x: 944, y: 188 },
56
- { name: Cities.Pretoria1, region: Regions.Orange, x: 894, y: 271 },
57
- { name: Cities.Pretoria2, region: Regions.Orange, x: 894, y: 306 },
58
- { name: Cities.Rustenburc, region: Regions.Orange, x: 787, y: 327 },
59
- { name: Cities.Mozambique, region: Regions.Green, x: 1184, y: 167 },
60
- { name: Cities.Mbombela, region: Regions.Green, x: 1046, y: 287 },
61
- { name: Cities.Iswaini, region: Regions.Green, x: 1086, y: 375 },
62
- { name: Cities.Germiston, region: Regions.Green, x: 983, y: 375 },
63
- { name: Cities.Johannesburg1, region: Regions.Green, x: 887, y: 365 },
64
- { name: Cities.Johannesburg2, region: Regions.Green, x: 889, y: 398 },
65
- { name: Cities.Ladysmith, region: Regions.Green, x: 968, y: 495 },
66
- { name: Cities.Abc, region: Regions.Yellow, x: 1122, y: 521 },
67
- { name: Cities.Def, region: Regions.Yellow, x: 1000, y: 558 },
68
- { name: Cities.Ghi1, region: Regions.Yellow, x: 1049, y: 618 },
69
- { name: Cities.Ghi2, region: Regions.Yellow, x: 1048, y: 651 },
70
- { name: Cities.Jkl, region: Regions.Yellow, x: 931, y: 733 },
71
- { name: Cities.Mno, region: Regions.Yellow, x: 894, y: 572 },
72
- { name: Cities.Qrs, region: Regions.Yellow, x: 776, y: 556 },
73
- { name: Cities.Keerksorp, region: Regions.Brown, x: 780, y: 387 },
74
- { name: Cities.Weikom, region: Regions.Brown, x: 771, y: 467 },
75
- { name: Cities.Xuruman, region: Regions.Brown, x: 595, y: 415 },
76
- { name: Cities.Kimberly, region: Regions.Brown, x: 670, y: 541 },
77
- { name: Cities.Upincion, region: Regions.Brown, x: 456, y: 492 },
78
- { name: Cities.Sprincbom, region: Regions.Brown, x: 264, y: 580 },
79
- { name: Cities.Namibia, region: Regions.Brown, x: 239, y: 329 },
80
- { name: Cities.Deaar, region: Regions.Red, x: 641, y: 735 },
81
- { name: Cities.Beaufortwest, region: Regions.Red, x: 513, y: 782 },
82
- { name: Cities.Eastlondon, region: Regions.Red, x: 852, y: 833 },
83
- { name: Cities.Portelizabeth, region: Regions.Red, x: 712, y: 903 },
84
- { name: Cities.Ceorci, region: Regions.Red, x: 526, y: 903 },
85
- { name: Cities.Capetown1, region: Regions.Red, x: 290, y: 871 },
86
- { name: Cities.Capetown2, region: Regions.Red, x: 287, y: 904 },
59
+ { name: Cities.Zimbabwe, region: Regions.Orange, x: 903, y: 50, singleOccupancy: true },
60
+ { name: Cities.Musina, region: Regions.Orange, x: 874, y: 134 },
61
+ { name: Cities.Botswana, region: Regions.Orange, x: 560, y: 187, singleOccupancy: true },
62
+ { name: Cities.Polokwane, region: Regions.Orange, x: 802, y: 189 },
63
+ { name: Cities.PretoriaN, region: Regions.Orange, x: 759, y: 261 },
64
+ { name: Cities.PretoriaS, region: Regions.Orange, x: 759, y: 291 },
65
+ { name: Cities.Rustenburg, region: Regions.Orange, x: 666, y: 310 },
66
+ { name: Cities.Mozambique, region: Regions.Green, x: 1011, y: 170, singleOccupancy: true },
67
+ { name: Cities.Mbombela, region: Regions.Green, x: 891, y: 275 },
68
+ { name: Cities.Eswatini, region: Regions.Green, x: 926, y: 351, singleOccupancy: true },
69
+ { name: Cities.Germiston, region: Regions.Green, x: 836, y: 351 },
70
+ { name: Cities.JohannesburgN, region: Regions.Green, x: 753, y: 343 },
71
+ { name: Cities.JohannesburgS, region: Regions.Green, x: 754, y: 371 },
72
+ { name: Cities.Ladysmith, region: Regions.Green, x: 823, y: 456 },
73
+ { name: Cities.Newcastle, region: Regions.Yellow, x: 957, y: 478 },
74
+ { name: Cities.Pietermaritzburg, region: Regions.Yellow, x: 851, y: 511 },
75
+ { name: Cities.DurbanN, region: Regions.Yellow, x: 894, y: 563 },
76
+ { name: Cities.DurbanS, region: Regions.Yellow, x: 893, y: 592 },
77
+ { name: Cities.Mthatha, region: Regions.Yellow, x: 791, y: 663 },
78
+ { name: Cities.Lesotho, region: Regions.Yellow, x: 759, y: 523, singleOccupancy: true },
79
+ { name: Cities.Bloemfontein, region: Regions.Yellow, x: 656, y: 509 },
80
+ { name: Cities.Klerksdorp, region: Regions.Brown, x: 660, y: 362 },
81
+ { name: Cities.Welkom, region: Regions.Brown, x: 652, y: 431 },
82
+ { name: Cities.Kuruman, region: Regions.Brown, x: 499, y: 386 },
83
+ { name: Cities.Kimberly, region: Regions.Brown, x: 564, y: 496 },
84
+ { name: Cities.Upington, region: Regions.Brown, x: 378, y: 453 },
85
+ { name: Cities.Springbok, region: Regions.Brown, x: 211, y: 530 },
86
+ { name: Cities.Namibia, region: Regions.Brown, x: 189, y: 311, singleOccupancy: true },
87
+ { name: Cities.DeAar, region: Regions.Red, x: 539, y: 665 },
88
+ { name: Cities.BeaufortWest, region: Regions.Red, x: 427, y: 705 },
89
+ { name: Cities.EastLondon, region: Regions.Red, x: 722, y: 750 },
90
+ { name: Cities.PortElizabeth, region: Regions.Red, x: 600, y: 811 },
91
+ { name: Cities.George, region: Regions.Red, x: 439, y: 811 },
92
+ { name: Cities.CapeTownN, region: Regions.Red, x: 233, y: 783 },
93
+ { name: Cities.CapeTownS, region: Regions.Red, x: 231, y: 812 },
87
94
  ],
88
95
  connections: [
89
- { nodes: [Cities.Sprincbom, Cities.Namibia], cost: 30 },
90
- { nodes: [Cities.Qrs, Cities.Mno], cost: 30 },
91
- { nodes: [Cities.Germiston, Cities.Iswaini], cost: 30 },
96
+ { nodes: [Cities.Springbok, Cities.Namibia], cost: 30 },
97
+ { nodes: [Cities.Bloemfontein, Cities.Lesotho], cost: 30 },
98
+ { nodes: [Cities.Germiston, Cities.Eswatini], cost: 30 },
92
99
  { nodes: [Cities.Mbombela, Cities.Mozambique], cost: 30 },
93
- { nodes: [Cities.Botswana, Cities.Rustenburc], cost: 30 },
94
- { nodes: [Cities.Zimbaswe, Cities.Musina], cost: 30 },
95
- { nodes: [Cities.Capetown2, Cities.Capetown1], cost: 0 },
96
- { nodes: [Cities.Capetown2, Cities.Ceorci], cost: 16 },
97
- { nodes: [Cities.Ceorci, Cities.Portelizabeth], cost: 12 },
98
- { nodes: [Cities.Portelizabeth, Cities.Eastlondon], cost: 13 },
99
- { nodes: [Cities.Eastlondon, Cities.Jkl], cost: 8 },
100
- { nodes: [Cities.Jkl, Cities.Ghi2], cost: 13 },
101
- { nodes: [Cities.Ghi2, Cities.Ghi1], cost: 0 },
102
- { nodes: [Cities.Ghi1, Cities.Def], cost: 3 },
103
- { nodes: [Cities.Ghi1, Cities.Abc], cost: 9 },
104
- { nodes: [Cities.Abc, Cities.Def], cost: 9 },
105
- { nodes: [Cities.Def, Cities.Ladysmith], cost: 5 },
106
- { nodes: [Cities.Ladysmith, Cities.Abc], cost: 10 },
107
- { nodes: [Cities.Qrs, Cities.Jkl], cost: 18 },
108
- { nodes: [Cities.Qrs, Cities.Eastlondon], cost: 22 },
109
- { nodes: [Cities.Eastlondon, Cities.Deaar], cost: 22 },
110
- { nodes: [Cities.Deaar, Cities.Portelizabeth], cost: 18 },
111
- { nodes: [Cities.Ceorci, Cities.Deaar], cost: 17 },
112
- { nodes: [Cities.Deaar, Cities.Beaufortwest], cost: 10 },
113
- { nodes: [Cities.Beaufortwest, Cities.Ceorci], cost: 8 },
114
- { nodes: [Cities.Beaufortwest, Cities.Capetown1], cost: 22 },
115
- { nodes: [Cities.Capetown1, Cities.Sprincbom], cost: 22 },
116
- { nodes: [Cities.Sprincbom, Cities.Beaufortwest], cost: 24 },
117
- { nodes: [Cities.Deaar, Cities.Sprincbom], cost: 26 },
118
- { nodes: [Cities.Sprincbom, Cities.Upincion], cost: 16 },
119
- { nodes: [Cities.Upincion, Cities.Deaar], cost: 16 },
120
- { nodes: [Cities.Deaar, Cities.Qrs], cost: 13 },
121
- { nodes: [Cities.Qrs, Cities.Kimberly], cost: 6 },
122
- { nodes: [Cities.Kimberly, Cities.Deaar], cost: 10 },
123
- { nodes: [Cities.Kimberly, Cities.Upincion], cost: 14 },
124
- { nodes: [Cities.Kimberly, Cities.Weikom], cost: 9 },
125
- { nodes: [Cities.Weikom, Cities.Qrs], cost: 6 },
126
- { nodes: [Cities.Qrs, Cities.Ladysmith], cost: 19 },
127
- { nodes: [Cities.Jkl, Cities.Def], cost: 12 },
128
- { nodes: [Cities.Upincion, Cities.Xuruman], cost: 11 },
100
+ { nodes: [Cities.Botswana, Cities.Rustenburg], cost: 30 },
101
+ { nodes: [Cities.Zimbabwe, Cities.Musina], cost: 30 },
102
+ { nodes: [Cities.CapeTownS, Cities.CapeTownN], cost: 0 },
103
+ { nodes: [Cities.CapeTownS, Cities.George], cost: 16 },
104
+ { nodes: [Cities.George, Cities.PortElizabeth], cost: 12 },
105
+ { nodes: [Cities.PortElizabeth, Cities.EastLondon], cost: 13 },
106
+ { nodes: [Cities.EastLondon, Cities.Mthatha], cost: 8 },
107
+ { nodes: [Cities.Mthatha, Cities.DurbanS], cost: 13 },
108
+ { nodes: [Cities.DurbanS, Cities.DurbanN], cost: 0 },
109
+ { nodes: [Cities.DurbanN, Cities.Pietermaritzburg], cost: 3 },
110
+ { nodes: [Cities.DurbanN, Cities.Newcastle], cost: 9 },
111
+ { nodes: [Cities.Newcastle, Cities.Pietermaritzburg], cost: 9 },
112
+ { nodes: [Cities.Pietermaritzburg, Cities.Ladysmith], cost: 5 },
113
+ { nodes: [Cities.Ladysmith, Cities.Newcastle], cost: 10 },
114
+ { nodes: [Cities.Bloemfontein, Cities.Mthatha], cost: 18 },
115
+ { nodes: [Cities.Bloemfontein, Cities.EastLondon], cost: 22 },
116
+ { nodes: [Cities.EastLondon, Cities.DeAar], cost: 22 },
117
+ { nodes: [Cities.DeAar, Cities.PortElizabeth], cost: 18 },
118
+ { nodes: [Cities.George, Cities.DeAar], cost: 17 },
119
+ { nodes: [Cities.DeAar, Cities.BeaufortWest], cost: 10 },
120
+ { nodes: [Cities.BeaufortWest, Cities.George], cost: 8 },
121
+ { nodes: [Cities.BeaufortWest, Cities.CapeTownN], cost: 22 },
122
+ { nodes: [Cities.CapeTownN, Cities.Springbok], cost: 22 },
123
+ { nodes: [Cities.Springbok, Cities.BeaufortWest], cost: 24 },
124
+ { nodes: [Cities.DeAar, Cities.Springbok], cost: 26 },
125
+ { nodes: [Cities.Springbok, Cities.Upington], cost: 16 },
126
+ { nodes: [Cities.Upington, Cities.DeAar], cost: 16 },
127
+ { nodes: [Cities.DeAar, Cities.Bloemfontein], cost: 13 },
128
+ { nodes: [Cities.Bloemfontein, Cities.Kimberly], cost: 6 },
129
+ { nodes: [Cities.Kimberly, Cities.DeAar], cost: 10 },
130
+ { nodes: [Cities.Kimberly, Cities.Upington], cost: 14 },
131
+ { nodes: [Cities.Kimberly, Cities.Welkom], cost: 9 },
132
+ { nodes: [Cities.Welkom, Cities.Bloemfontein], cost: 6 },
133
+ { nodes: [Cities.Bloemfontein, Cities.Ladysmith], cost: 19 },
134
+ { nodes: [Cities.Mthatha, Cities.Pietermaritzburg], cost: 12 },
135
+ { nodes: [Cities.Upington, Cities.Kuruman], cost: 11 },
129
136
  { nodes: [Cities.Musina, Cities.Polokwane], cost: 8 },
130
- { nodes: [Cities.Polokwane, Cities.Pretoria1], cost: 11 },
131
- { nodes: [Cities.Pretoria1, Cities.Pretoria2], cost: 0 },
132
- { nodes: [Cities.Pretoria2, Cities.Johannesburg1], cost: 2 },
133
- { nodes: [Cities.Johannesburg1, Cities.Johannesburg2], cost: 0 },
134
- { nodes: [Cities.Johannesburg2, Cities.Germiston], cost: 1 },
135
- { nodes: [Cities.Johannesburg1, Cities.Mbombela], cost: 13 },
137
+ { nodes: [Cities.Polokwane, Cities.PretoriaN], cost: 11 },
138
+ { nodes: [Cities.PretoriaN, Cities.PretoriaS], cost: 0 },
139
+ { nodes: [Cities.PretoriaS, Cities.JohannesburgN], cost: 2 },
140
+ { nodes: [Cities.JohannesburgN, Cities.JohannesburgS], cost: 0 },
141
+ { nodes: [Cities.JohannesburgS, Cities.Germiston], cost: 1 },
142
+ { nodes: [Cities.JohannesburgN, Cities.Mbombela], cost: 13 },
136
143
  { nodes: [Cities.Mbombela, Cities.Germiston], cost: 13 },
137
- { nodes: [Cities.Pretoria1, Cities.Mbombela], cost: 13 },
144
+ { nodes: [Cities.PretoriaN, Cities.Mbombela], cost: 13 },
138
145
  { nodes: [Cities.Mbombela, Cities.Polokwane], cost: 10 },
139
146
  { nodes: [Cities.Musina, Cities.Mbombela], cost: 15 },
140
- { nodes: [Cities.Pretoria1, Cities.Rustenburc], cost: 4 },
141
- { nodes: [Cities.Rustenburc, Cities.Johannesburg1], cost: 4 },
142
- { nodes: [Cities.Johannesburg1, Cities.Keerksorp], cost: 7 },
143
- { nodes: [Cities.Keerksorp, Cities.Weikom], cost: 5 },
144
- { nodes: [Cities.Qrs, Cities.Johannesburg2], cost: 16 },
145
- { nodes: [Cities.Xuruman, Cities.Rustenburc], cost: 18 },
146
- { nodes: [Cities.Keerksorp, Cities.Xuruman], cost: 12 },
147
- { nodes: [Cities.Xuruman, Cities.Kimberly], cost: 8 },
148
- { nodes: [Cities.Johannesburg2, Cities.Ladysmith], cost: 13 },
147
+ { nodes: [Cities.PretoriaN, Cities.Rustenburg], cost: 4 },
148
+ { nodes: [Cities.Rustenburg, Cities.JohannesburgN], cost: 4 },
149
+ { nodes: [Cities.JohannesburgN, Cities.Klerksdorp], cost: 7 },
150
+ { nodes: [Cities.Klerksdorp, Cities.Welkom], cost: 5 },
151
+ { nodes: [Cities.Bloemfontein, Cities.JohannesburgS], cost: 16 },
152
+ { nodes: [Cities.Kuruman, Cities.Rustenburg], cost: 18 },
153
+ { nodes: [Cities.Klerksdorp, Cities.Kuruman], cost: 12 },
154
+ { nodes: [Cities.Kuruman, Cities.Kimberly], cost: 8 },
155
+ { nodes: [Cities.JohannesburgS, Cities.Ladysmith], cost: 13 },
149
156
  { nodes: [Cities.Ladysmith, Cities.Germiston], cost: 13 },
150
157
  ],
158
+
159
+ // Resupply per South Africa refill summary cards. Indexed as
160
+ // [resource][playerCount-2][step-1]. Note: 2P and 3P rows are intentionally
161
+ // identical on the printed cards (same pattern as North America).
162
+ resupply: [
163
+ // Coal
164
+ [
165
+ [4, 7, 5], // 2P
166
+ [4, 7, 5], // 3P
167
+ [5, 8, 6], // 4P
168
+ [6, 9, 7], // 5P
169
+ [7, 10, 8], // 6P
170
+ ],
171
+ // Oil
172
+ [
173
+ [1, 2, 1], // 2P
174
+ [1, 2, 1], // 3P
175
+ [2, 3, 2], // 4P
176
+ [2, 4, 3], // 5P
177
+ [4, 5, 4], // 6P
178
+ ],
179
+ // Garbage
180
+ [
181
+ [1, 3, 3], // 2P
182
+ [1, 3, 3], // 3P
183
+ [2, 4, 4], // 4P
184
+ [3, 4, 5], // 5P
185
+ [3, 6, 6], // 6P
186
+ ],
187
+ // Uranium
188
+ [
189
+ [1, 1, 2], // 2P
190
+ [1, 1, 2], // 3P
191
+ [2, 2, 3], // 4P
192
+ [2, 3, 3], // 5P
193
+ [2, 3, 4], // 6P
194
+ ],
195
+ ],
196
+ layout: 'Landscape',
197
+ // Cities authored at photo-coord scale (~1200x863). First-pass fit into the
198
+ // standard 1500x800 landscape viewBox — tune after first render.
199
+ adjustRatio: [0.9, 0.75],
200
+ mapPosition: [70, 50],
201
+ mapRotation: 0,
202
+ // SA uses the engine default 8-price market (24 coal / 24 oil / 24 garbage
203
+ // slots + 12 uranium 1–8 + 10/12/14/16), so we don't override coal/oil/
204
+ // garbage/uranium Prices. Only the starting fill differs:
205
+ // coal 1–8 full = 24
206
+ // oil 4–8 = 15
207
+ // garbage 5–8 = 12
208
+ // uranium 12–16 only = 3
209
+ startingResources: [24, 15, 12, 3],
210
+ // Total cubes in the game (used cubes return here; refill draws from here).
211
+ // For SA, USED coal goes to the separate coalStorage pool instead — see
212
+ // GameState.coalStorage and the UsePowerPlant/resupply branches in engine.ts.
213
+ startingSupply: [24, 24, 24, 12],
214
+ // SA removes oil power plant 07 from the deck; the rest follows the standard
215
+ // recharged/original deck setup. With 07 gone the "starter pool" is one
216
+ // plant shorter (12 instead of 13 for recharged; future market shifts to
217
+ // 8/9/10/11 instead of 7/8/9/10 for original).
218
+ setupDeck(numPlayers: number, variant: string, rng: seedrandom.prng) {
219
+ let powerPlantsDeck = cloneDeep(powerPlants).filter((pp) => pp.number !== 7);
220
+ let actualMarket: PowerPlant[];
221
+ let futureMarket: PowerPlant[];
222
+
223
+ if (variant == 'original') {
224
+ powerPlantsDeck = powerPlantsDeck.slice(8);
225
+ const powerPlant13Idx = powerPlantsDeck.findIndex((pp) => pp.number == 13);
226
+ const powerPlant13 = powerPlantsDeck.splice(powerPlant13Idx, 1)[0];
227
+ const step3 = powerPlantsDeck.pop()!;
228
+
229
+ powerPlantsDeck = shuffle(powerPlantsDeck, rng() + '');
230
+ if (numPlayers == 2 || numPlayers == 3) {
231
+ powerPlantsDeck = powerPlantsDeck.slice(8);
232
+ } else if (numPlayers == 4) {
233
+ powerPlantsDeck = powerPlantsDeck.slice(4);
234
+ }
235
+
236
+ powerPlantsDeck.unshift(powerPlant13);
237
+ powerPlantsDeck.push(step3);
238
+
239
+ actualMarket = [getPowerPlant(3), getPowerPlant(4), getPowerPlant(5), getPowerPlant(6)];
240
+ futureMarket = [getPowerPlant(8), getPowerPlant(9), getPowerPlant(10), getPowerPlant(11)];
241
+ } else {
242
+ let initialPowerPlants = shuffle(powerPlantsDeck.splice(0, 12), rng() + '');
243
+ let initialPlantMarket = initialPowerPlants.splice(0, 8);
244
+ initialPlantMarket = initialPlantMarket.sort((a, b) => a.number - b.number);
245
+ actualMarket = initialPlantMarket.slice(0, 4);
246
+ futureMarket = initialPlantMarket.slice(4);
247
+
248
+ const first = initialPowerPlants.shift()!;
249
+ const step3 = powerPlantsDeck.pop()!;
250
+
251
+ powerPlantsDeck = shuffle(powerPlantsDeck, rng() + '');
252
+ if (numPlayers == 2 || numPlayers == 3) {
253
+ initialPowerPlants = initialPowerPlants.slice(2);
254
+ powerPlantsDeck = shuffle(powerPlantsDeck.slice(6).concat(initialPowerPlants), rng() + '');
255
+ } else if (numPlayers == 4) {
256
+ initialPowerPlants = initialPowerPlants.slice(1);
257
+ powerPlantsDeck = shuffle(powerPlantsDeck.slice(3).concat(initialPowerPlants), rng() + '');
258
+ } else {
259
+ powerPlantsDeck = shuffle(powerPlantsDeck.concat(initialPowerPlants), rng() + '');
260
+ }
261
+
262
+ powerPlantsDeck.unshift(first);
263
+ powerPlantsDeck.push(step3);
264
+ }
265
+
266
+ return { actualMarket, futureMarket, powerPlantsDeck };
267
+ },
268
+ mapSpecificRules:
269
+ 'Coal storage: there is a separate storage space below the resource market, ' +
270
+ 'empty at game start. Coal used to power plants returns to this storage space ' +
271
+ '(not the main supply). The resource-market refill draws coal from storage ' +
272
+ 'first, then from the main supply. Players can always buy coal for $8 from ' +
273
+ 'the storage space (in addition to the standard market price). ' +
274
+ 'Metropolises: Cape Town, Durban, Johannesburg and Pretoria each consist of ' +
275
+ 'two cities (N and S) connected by a 0-cost edge. ' +
276
+ 'Cross-border connections: the six 30-Elektro connections to neighboring ' +
277
+ 'countries (Namibia, Botswana, Zimbabwe, Mozambique, Eswatini, Lesotho) are ' +
278
+ 'available from the start of the game. The 30 Elektro is the complete cost ' +
279
+ '— no house-base cost is added on top. Only a single player can build on ' +
280
+ 'each cross-border space (cap of 1 instead of the standard 3). ' +
281
+ 'Power plant 07 is removed from the deck.',
151
282
  };
@@ -1,4 +1,11 @@
1
+ // by John and Cici
2
+ import { cloneDeep } from 'lodash';
3
+ import seedrandom from 'seedrandom';
4
+ import { getPowerPlant } from '../engine';
5
+ import { PowerPlant } from '../gamestate';
6
+ import { shuffle } from '../utils';
1
7
  import { GameMap } from './../maps';
8
+ import { powerPlants } from './../powerPlants';
2
9
 
3
10
  export enum Regions {
4
11
  Red = 'red',
@@ -55,46 +62,46 @@ export enum Cities {
55
62
  export const map: GameMap = {
56
63
  name: 'UK & Ireland',
57
64
  cities: [
58
- { name: Cities.Norwich, region: Regions.Red, x: 646, y: 702 },
59
- { name: Cities.London1, region: Regions.Red, x: 554, y: 756 },
60
- { name: Cities.London2, region: Regions.Red, x: 550, y: 780 },
61
- { name: Cities.Brighton, region: Regions.Red, x: 537, y: 837 },
62
- { name: Cities.Southampton, region: Regions.Red, x: 451, y: 805 },
63
- { name: Cities.Plymouth, region: Regions.Red, x: 312, y: 814 },
64
- { name: Cities.Leicester, region: Regions.Red, x: 540, y: 680 },
65
- { name: Cities.Bristol, region: Regions.Red, x: 425, y: 762 },
66
- { name: Cities.Newcastleupontyne, region: Regions.Pink, x: 550, y: 414 },
67
- { name: Cities.Leeds, region: Regions.Pink, x: 559, y: 541 },
68
- { name: Cities.Sheffield, region: Regions.Pink, x: 530, y: 590 },
69
- { name: Cities.Nottingham, region: Regions.Pink, x: 531, y: 632 },
70
- { name: Cities.Birmingham, region: Regions.Pink, x: 465, y: 663 },
71
- { name: Cities.Manchester, region: Regions.Pink, x: 479, y: 543 },
72
- { name: Cities.Liverpool, region: Regions.Pink, x: 433, y: 576 },
73
- { name: Cities.Newportcasnewydd, region: Regions.Yellow, x: 425, y: 722 },
74
- { name: Cities.Bangor, region: Regions.Yellow, x: 348, y: 574 },
75
- { name: Cities.Aberystwyth, region: Regions.Yellow, x: 357, y: 639 },
76
- { name: Cities.Swanseaabertawe, region: Regions.Yellow, x: 346, y: 706 },
77
- { name: Cities.Cardiffcaerdydd, region: Regions.Yellow, x: 357, y: 741 },
78
- { name: Cities.Haverfordwesthwlffordd, region: Regions.Yellow, x: 303, y: 673 },
79
- { name: Cities.Invernessinbhirnis, region: Regions.Brown, x: 479, y: 208 },
80
- { name: Cities.Aberdeenobardheathain, region: Regions.Brown, x: 588, y: 245 },
81
- { name: Cities.Dundeedundeach, region: Regions.Brown, x: 552, y: 286 },
82
- { name: Cities.Perthpeairt, region: Regions.Brown, x: 489, y: 307 },
83
- { name: Cities.Edinburgh, region: Regions.Brown, x: 494, y: 350 },
84
- { name: Cities.Dumfries, region: Regions.Brown, x: 441, y: 417 },
85
- { name: Cities.Glasgow, region: Regions.Brown, x: 422, y: 335 },
86
- { name: Cities.Coleraine, region: Regions.Orange, x: 330, y: 367 },
87
- { name: Cities.Derry, region: Regions.Orange, x: 256, y: 362 },
88
- { name: Cities.Belfast, region: Regions.Orange, x: 342, y: 421 },
89
- { name: Cities.Newry, region: Regions.Orange, x: 298, y: 462 },
90
- { name: Cities.Omagh, region: Regions.Orange, x: 260, y: 403 },
91
- { name: Cities.Sligo, region: Regions.Green, x: 181, y: 411 },
92
- { name: Cities.Dublin, region: Regions.Green, x: 274, y: 530 },
93
- { name: Cities.Waterford, region: Regions.Green, x: 210, y: 611 },
94
- { name: Cities.Cork, region: Regions.Green, x: 114, y: 626 },
95
- { name: Cities.Athlone, region: Regions.Green, x: 200, y: 489 },
96
- { name: Cities.Galway, region: Regions.Green, x: 112, y: 486 },
97
- { name: Cities.Limerick, region: Regions.Green, x: 122, y: 546 },
65
+ { name: Cities.Norwich, region: Regions.Red, island: 'gb', x: 646, y: 702 },
66
+ { name: Cities.London1, region: Regions.Red, island: 'gb', x: 554, y: 756 },
67
+ { name: Cities.London2, region: Regions.Red, island: 'gb', x: 550, y: 780 },
68
+ { name: Cities.Brighton, region: Regions.Red, island: 'gb', x: 537, y: 837 },
69
+ { name: Cities.Southampton, region: Regions.Red, island: 'gb', x: 451, y: 805 },
70
+ { name: Cities.Plymouth, region: Regions.Red, island: 'gb', x: 312, y: 814 },
71
+ { name: Cities.Leicester, region: Regions.Red, island: 'gb', x: 540, y: 680 },
72
+ { name: Cities.Bristol, region: Regions.Red, island: 'gb', x: 425, y: 762 },
73
+ { name: Cities.Newcastleupontyne, region: Regions.Pink, island: 'gb', x: 550, y: 414 },
74
+ { name: Cities.Leeds, region: Regions.Pink, island: 'gb', x: 559, y: 541 },
75
+ { name: Cities.Sheffield, region: Regions.Pink, island: 'gb', x: 530, y: 590 },
76
+ { name: Cities.Nottingham, region: Regions.Pink, island: 'gb', x: 531, y: 632 },
77
+ { name: Cities.Birmingham, region: Regions.Pink, island: 'gb', x: 465, y: 663 },
78
+ { name: Cities.Manchester, region: Regions.Pink, island: 'gb', x: 479, y: 543 },
79
+ { name: Cities.Liverpool, region: Regions.Pink, island: 'gb', x: 433, y: 576 },
80
+ { name: Cities.Newportcasnewydd, region: Regions.Yellow, island: 'gb', x: 425, y: 722 },
81
+ { name: Cities.Bangor, region: Regions.Yellow, island: 'gb', x: 348, y: 574 },
82
+ { name: Cities.Aberystwyth, region: Regions.Yellow, island: 'gb', x: 357, y: 639 },
83
+ { name: Cities.Swanseaabertawe, region: Regions.Yellow, island: 'gb', x: 346, y: 706 },
84
+ { name: Cities.Cardiffcaerdydd, region: Regions.Yellow, island: 'gb', x: 357, y: 741 },
85
+ { name: Cities.Haverfordwesthwlffordd, region: Regions.Yellow, island: 'gb', x: 303, y: 673 },
86
+ { name: Cities.Invernessinbhirnis, region: Regions.Brown, island: 'gb', x: 479, y: 208 },
87
+ { name: Cities.Aberdeenobardheathain, region: Regions.Brown, island: 'gb', x: 588, y: 245 },
88
+ { name: Cities.Dundeedundeach, region: Regions.Brown, island: 'gb', x: 552, y: 286 },
89
+ { name: Cities.Perthpeairt, region: Regions.Brown, island: 'gb', x: 489, y: 307 },
90
+ { name: Cities.Edinburgh, region: Regions.Brown, island: 'gb', x: 494, y: 350 },
91
+ { name: Cities.Dumfries, region: Regions.Brown, island: 'gb', x: 441, y: 417 },
92
+ { name: Cities.Glasgow, region: Regions.Brown, island: 'gb', x: 422, y: 335 },
93
+ { name: Cities.Coleraine, region: Regions.Orange, island: 'ie', x: 330, y: 367 },
94
+ { name: Cities.Derry, region: Regions.Orange, island: 'ie', x: 256, y: 362 },
95
+ { name: Cities.Belfast, region: Regions.Orange, island: 'ie', x: 342, y: 421 },
96
+ { name: Cities.Newry, region: Regions.Orange, island: 'ie', x: 298, y: 462 },
97
+ { name: Cities.Omagh, region: Regions.Orange, island: 'ie', x: 260, y: 403 },
98
+ { name: Cities.Sligo, region: Regions.Green, island: 'ie', x: 181, y: 411 },
99
+ { name: Cities.Dublin, region: Regions.Green, island: 'ie', x: 274, y: 530 },
100
+ { name: Cities.Waterford, region: Regions.Green, island: 'ie', x: 210, y: 611 },
101
+ { name: Cities.Cork, region: Regions.Green, island: 'ie', x: 114, y: 626 },
102
+ { name: Cities.Athlone, region: Regions.Green, island: 'ie', x: 200, y: 489 },
103
+ { name: Cities.Galway, region: Regions.Green, island: 'ie', x: 112, y: 486 },
104
+ { name: Cities.Limerick, region: Regions.Green, island: 'ie', x: 122, y: 546 },
98
105
  ],
99
106
  connections: [
100
107
  { nodes: [Cities.Nottingham, Cities.Leicester], cost: 4 },
@@ -172,4 +179,127 @@ export const map: GameMap = {
172
179
  { nodes: [Cities.Omagh, Cities.Derry], cost: 5 },
173
180
  { nodes: [Cities.Omagh, Cities.Sligo], cost: 10 },
174
181
  ],
182
+ layout: 'Portrait',
183
+ // Stub coords are at photo scale (x range ~110-650, y range ~200-840 — taller
184
+ // than wide). First-pass fit into the default portrait viewBox — tune after
185
+ // first render against the printed board.
186
+ adjustRatio: [1.1, 1.1],
187
+ mapPosition: [10, -75],
188
+ mapRotation: 0,
189
+ // Resupply table read from the printed UK & Ireland refill summary cards.
190
+ // Indexed [resource][playerCount-2][step-1]. Note: 2P and 3P rows are NOT
191
+ // identical on this map (unlike NA / SA), except for the Garbage row.
192
+ resupply: [
193
+ // Coal
194
+ [
195
+ [3, 4, 3], // 2P
196
+ [3, 5, 3], // 3P
197
+ [4, 6, 4], // 4P
198
+ [4, 7, 5], // 5P
199
+ [6, 8, 6], // 6P
200
+ ],
201
+ // Oil
202
+ [
203
+ [2, 3, 2], // 2P
204
+ [2, 4, 2], // 3P
205
+ [3, 5, 3], // 4P
206
+ [4, 6, 4], // 5P
207
+ [5, 7, 5], // 6P
208
+ ],
209
+ // Garbage
210
+ [
211
+ [1, 2, 2], // 2P
212
+ [1, 2, 2], // 3P
213
+ [2, 3, 3], // 4P
214
+ [3, 3, 5], // 5P
215
+ [3, 5, 5], // 6P
216
+ ],
217
+ // Uranium
218
+ [
219
+ [1, 1, 1], // 2P
220
+ [1, 2, 1], // 3P
221
+ [1, 3, 1], // 4P
222
+ [2, 4, 2], // 5P
223
+ [2, 4, 3], // 6P
224
+ ],
225
+ ],
226
+ // Standard 8-price market (no overrides). Starting fill from the rulebook:
227
+ // coal 1-8 full = 24
228
+ // oil 3-8 = 18
229
+ // garbage 5-8 = 12
230
+ // uranium none = 0
231
+ startingResources: [24, 18, 12, 0],
232
+ startingSupply: [24, 24, 24, 12],
233
+ // Two-network mechanic: 20 Elektro surcharge to start a network on an
234
+ // island where the player has no city. The cross-island build skips the
235
+ // dijkstra path (there is no sea edge) and pays house base + 20.
236
+ crossIslandSurcharge: 20,
237
+ // Step 3 is placed 3rd from last in the deck (two plants below it) so Step
238
+ // 3 starts earlier than on most maps. Otherwise standard recharged/original
239
+ // deck prep.
240
+ setupDeck(numPlayers: number, variant: string, rng: seedrandom.prng) {
241
+ let powerPlantsDeck = cloneDeep(powerPlants);
242
+ let actualMarket: PowerPlant[];
243
+ let futureMarket: PowerPlant[];
244
+
245
+ if (variant == 'original') {
246
+ powerPlantsDeck = powerPlantsDeck.slice(8);
247
+ const powerPlant13Idx = powerPlantsDeck.findIndex((pp) => pp.number == 13);
248
+ const powerPlant13 = powerPlantsDeck.splice(powerPlant13Idx, 1)[0];
249
+ const step3 = powerPlantsDeck.pop()!;
250
+
251
+ powerPlantsDeck = shuffle(powerPlantsDeck, rng() + '');
252
+ if (numPlayers == 2 || numPlayers == 3) {
253
+ powerPlantsDeck = powerPlantsDeck.slice(8);
254
+ } else if (numPlayers == 4) {
255
+ powerPlantsDeck = powerPlantsDeck.slice(4);
256
+ }
257
+
258
+ powerPlantsDeck.unshift(powerPlant13);
259
+ // UK&I: Step 3 sits 3rd from last (two plants below it).
260
+ powerPlantsDeck.splice(powerPlantsDeck.length - 2, 0, step3);
261
+
262
+ actualMarket = [getPowerPlant(3), getPowerPlant(4), getPowerPlant(5), getPowerPlant(6)];
263
+ futureMarket = [getPowerPlant(7), getPowerPlant(8), getPowerPlant(9), getPowerPlant(10)];
264
+ } else {
265
+ let initialPowerPlants = shuffle(powerPlantsDeck.splice(0, 13), rng() + '');
266
+ let initialPlantMarket = initialPowerPlants.splice(0, 8);
267
+ initialPlantMarket = initialPlantMarket.sort((a, b) => a.number - b.number);
268
+ actualMarket = initialPlantMarket.slice(0, 4);
269
+ futureMarket = initialPlantMarket.slice(4);
270
+
271
+ const first = initialPowerPlants.shift()!;
272
+ const step3 = powerPlantsDeck.pop()!;
273
+
274
+ powerPlantsDeck = shuffle(powerPlantsDeck, rng() + '');
275
+ if (numPlayers == 2 || numPlayers == 3) {
276
+ initialPowerPlants = initialPowerPlants.slice(2);
277
+ powerPlantsDeck = shuffle(powerPlantsDeck.slice(6).concat(initialPowerPlants), rng() + '');
278
+ } else if (numPlayers == 4) {
279
+ initialPowerPlants = initialPowerPlants.slice(1);
280
+ powerPlantsDeck = shuffle(powerPlantsDeck.slice(3).concat(initialPowerPlants), rng() + '');
281
+ } else {
282
+ powerPlantsDeck = shuffle(powerPlantsDeck.concat(initialPowerPlants), rng() + '');
283
+ }
284
+
285
+ powerPlantsDeck.unshift(first);
286
+ // UK&I: Step 3 sits 3rd from last (two plants below it). The engine's
287
+ // standard Step 3 trigger already reshuffles plants below + discard
288
+ // into the new face-down deck, so we only need the placement here.
289
+ powerPlantsDeck.splice(powerPlantsDeck.length - 2, 0, step3);
290
+ }
291
+
292
+ return { actualMarket, futureMarket, powerPlantsDeck };
293
+ },
294
+ mapSpecificRules:
295
+ 'Two networks: Ireland (Green and Orange regions) and Great Britain ' +
296
+ '(Red, Pink, Yellow, Brown) have no sea connection. A player may run ' +
297
+ 'one network on each island. Starting a second network on the other ' +
298
+ 'island costs an extra 20 Elektro on top of the normal first-house cost. ' +
299
+ 'Nuclear restriction: a player whose network is entirely in the Republic ' +
300
+ 'of Ireland (Green region) cannot bid on or auction a nuclear power plant ' +
301
+ 'until they build a city in Scotland, Wales, England, or Northern Ireland. ' +
302
+ 'Early Step 3: the Step 3 card is placed 3rd from last in the deck (two ' +
303
+ 'plants below it). Step 2 begins when a player connects their 7th city ' +
304
+ '(6th for 6 players).',
175
305
  };