powergrid-engine 1.10.0 → 1.12.0

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.
@@ -0,0 +1,391 @@
1
+ // by John and Cici
2
+ import { cloneDeep } from 'lodash';
3
+ import seedrandom from 'seedrandom';
4
+ import { PowerPlantType } from '../gamestate';
5
+ import { shuffle } from '../utils';
6
+ import { GameMap } from './../maps';
7
+ import { powerPlants } from './../powerPlants';
8
+
9
+ export enum Regions {
10
+ Pink = 'pink', // UK / Ireland / Low Countries
11
+ Red = 'red', // France / Iberia
12
+ Brown = 'brown', // Central North (Germany / Czech / Poland-south)
13
+ Yellow = 'yellow', // Alpine / Italy / Hungary
14
+ Orange = 'orange', // Scandinavia / Baltic
15
+ Blue = 'blue', // Eastern Europe (incl. Bucureşti)
16
+ Green = 'green', // Balkans / Turkey
17
+ }
18
+
19
+ export enum Cities {
20
+ // Pink — UK / Ireland / Low Countries
21
+ Glasgow = 'Glasgow',
22
+ Dublin = 'Dublin',
23
+ Birmingham = 'Birmingham',
24
+ London = 'London',
25
+ Randstad = 'Randstad',
26
+ Vlaanderen = 'Vlaanderen',
27
+ RheinRuhr = 'Rhein-Ruhr',
28
+
29
+ // Red — France / Iberia
30
+ Paris = 'Paris',
31
+ Bordeaux = 'Bordeaux',
32
+ Lyon = 'Lyon',
33
+ Marseille = 'Marseille',
34
+ Lisboa = 'Lisboa',
35
+ Madrid = 'Madrid',
36
+ Barcelona = 'Barcelona',
37
+
38
+ // Brown — Central North
39
+ Bremen = 'Bremen',
40
+ Berlin = 'Berlin',
41
+ RheinMain = 'Rhein-Main',
42
+ Stuttgart = 'Stuttgart',
43
+ Praha = 'Praha',
44
+ Katowice = 'Katowice',
45
+ München = 'München',
46
+
47
+ // Yellow — Alpine / Italy / Hungary
48
+ Zürich = 'Zürich',
49
+ Milano = 'Milano',
50
+ Roma = 'Roma',
51
+ Napoli = 'Napoli',
52
+ Wien = 'Wien',
53
+ Budapest = 'Budapest',
54
+ Zagreb = 'Zagreb',
55
+
56
+ // Orange — Scandinavia / Baltic
57
+ Oslo = 'Oslo',
58
+ Stockholm = 'Stockholm',
59
+ Helsinki = 'Helsinki',
60
+ Tallinn = 'Tallinn',
61
+ Kobenhavn = 'København',
62
+ Riga = 'Riga',
63
+ StPetersburg = 'St. Petersburg',
64
+
65
+ // Blue — Eastern Europe
66
+ Minsk = 'Minsk',
67
+ Moskwa = 'Moskwa',
68
+ Warszawa = 'Warszawa',
69
+ Kyjiv = 'Kyjiv',
70
+ Kharkiv = 'Kharkiv',
71
+ Odessa = 'Odessa',
72
+ Bucuresti = 'Bucureşti',
73
+
74
+ // Green — Balkans / Turkey
75
+ Beograd = 'Beograd',
76
+ Sofia = 'Sofia',
77
+ Tirana = 'Tirana',
78
+ Athina = 'Athina',
79
+ Istanbul = 'Istanbul',
80
+ Izmir = 'Izmir',
81
+ Ankara = 'Ankara',
82
+ }
83
+
84
+ export const map: GameMap = {
85
+ name: 'Europe',
86
+ cities: [
87
+ // Pink — UK / Ireland / Low Countries
88
+ { name: Cities.Glasgow, region: Regions.Pink, x: 490, y: 510 },
89
+ { name: Cities.Dublin, region: Regions.Pink, x: 390, y: 660 },
90
+ { name: Cities.Birmingham, region: Regions.Pink, x: 485, y: 695 },
91
+ { name: Cities.London, region: Regions.Pink, x: 545, y: 800 },
92
+ { name: Cities.Randstad, region: Regions.Pink, x: 770, y: 770 },
93
+ { name: Cities.Vlaanderen, region: Regions.Pink, x: 700, y: 830 },
94
+ { name: Cities.RheinRuhr, region: Regions.Pink, x: 845, y: 860 },
95
+
96
+ // Red — France / Iberia
97
+ { name: Cities.Paris, region: Regions.Red, x: 730, y: 920 },
98
+ { name: Cities.Bordeaux, region: Regions.Red, x: 655, y: 1095 },
99
+ { name: Cities.Lyon, region: Regions.Red, x: 785, y: 1100 },
100
+ { name: Cities.Marseille, region: Regions.Red, x: 815, y: 1240 },
101
+ { name: Cities.Barcelona, region: Regions.Red, x: 650, y: 1280 },
102
+ { name: Cities.Madrid, region: Regions.Red, x: 435, y: 1335 },
103
+ { name: Cities.Lisboa, region: Regions.Red, x: 255, y: 1335 },
104
+
105
+ // Brown — Central North (Germany / Czech / Poland-south)
106
+ { name: Cities.Bremen, region: Regions.Brown, x: 1010, y: 770 },
107
+ { name: Cities.Berlin, region: Regions.Brown, x: 1180, y: 800 },
108
+ { name: Cities.RheinMain, region: Regions.Brown, x: 970, y: 920 },
109
+ { name: Cities.Stuttgart, region: Regions.Brown, x: 995, y: 1000 },
110
+ { name: Cities.München, region: Regions.Brown, x: 1100, y: 1050 },
111
+ { name: Cities.Praha, region: Regions.Brown, x: 1235, y: 940 },
112
+ { name: Cities.Katowice, region: Regions.Brown, x: 1380, y: 940 },
113
+
114
+ // Yellow — Alpine / Italy / Hungary
115
+ { name: Cities.Zürich, region: Regions.Yellow, x: 1010, y: 1100 },
116
+ { name: Cities.Milano, region: Regions.Yellow, x: 1075, y: 1180 },
117
+ { name: Cities.Roma, region: Regions.Yellow, x: 1180, y: 1310 },
118
+ { name: Cities.Napoli, region: Regions.Yellow, x: 1235, y: 1430 },
119
+ { name: Cities.Wien, region: Regions.Yellow, x: 1265, y: 1080 },
120
+ { name: Cities.Budapest, region: Regions.Yellow, x: 1390, y: 1080 },
121
+ { name: Cities.Zagreb, region: Regions.Yellow, x: 1300, y: 1180 },
122
+
123
+ // Orange — Scandinavia / Baltic
124
+ { name: Cities.Oslo, region: Regions.Orange, x: 1015, y: 365 },
125
+ { name: Cities.Stockholm, region: Regions.Orange, x: 1170, y: 415 },
126
+ { name: Cities.Helsinki, region: Regions.Orange, x: 1395, y: 360 },
127
+ { name: Cities.Tallinn, region: Regions.Orange, x: 1410, y: 470 },
128
+ { name: Cities.Riga, region: Regions.Orange, x: 1395, y: 575 },
129
+ { name: Cities.Kobenhavn, region: Regions.Orange, x: 1180, y: 660 },
130
+ { name: Cities.StPetersburg, region: Regions.Orange, x: 1620, y: 460 },
131
+
132
+ // Blue — Eastern Europe
133
+ { name: Cities.Warszawa, region: Regions.Blue, x: 1500, y: 815 },
134
+ { name: Cities.Minsk, region: Regions.Blue, x: 1610, y: 815 },
135
+ { name: Cities.Moskwa, region: Regions.Blue, x: 1830, y: 600 },
136
+ { name: Cities.Kyjiv, region: Regions.Blue, x: 1690, y: 980 },
137
+ { name: Cities.Kharkiv, region: Regions.Blue, x: 1860, y: 980 },
138
+ { name: Cities.Odessa, region: Regions.Blue, x: 1720, y: 1100 },
139
+ { name: Cities.Bucuresti, region: Regions.Blue, x: 1610, y: 1175 },
140
+
141
+ // Green — Balkans / Turkey
142
+ { name: Cities.Beograd, region: Regions.Green, x: 1390, y: 1175 },
143
+ { name: Cities.Sofia, region: Regions.Green, x: 1505, y: 1240 },
144
+ { name: Cities.Tirana, region: Regions.Green, x: 1370, y: 1330 },
145
+ { name: Cities.Athina, region: Regions.Green, x: 1480, y: 1450 },
146
+ { name: Cities.Istanbul, region: Regions.Green, x: 1665, y: 1335 },
147
+ { name: Cities.Izmir, region: Regions.Green, x: 1730, y: 1430 },
148
+ { name: Cities.Ankara, region: Regions.Green, x: 1850, y: 1380 },
149
+ ],
150
+ connections: [
151
+ // Pink — UK / Ireland / Low Countries
152
+ { nodes: [Cities.Dublin, Cities.Glasgow], cost: 17 },
153
+ { nodes: [Cities.Glasgow, Cities.Birmingham], cost: 13 },
154
+ { nodes: [Cities.Dublin, Cities.Birmingham], cost: 15 },
155
+ { nodes: [Cities.Birmingham, Cities.London], cost: 4 },
156
+ { nodes: [Cities.London, Cities.Vlaanderen], cost: 15 },
157
+ { nodes: [Cities.London, Cities.Randstad], cost: 18 },
158
+ { nodes: [Cities.Randstad, Cities.Vlaanderen], cost: 4 },
159
+ { nodes: [Cities.Vlaanderen, Cities.RheinRuhr], cost: 4 },
160
+ { nodes: [Cities.Randstad, Cities.RheinRuhr], cost: 4 },
161
+
162
+ // Red — France / Iberia (internal)
163
+ { nodes: [Cities.Paris, Cities.Bordeaux], cost: 12 },
164
+ { nodes: [Cities.Paris, Cities.Lyon], cost: 11 },
165
+ { nodes: [Cities.Bordeaux, Cities.Lyon], cost: 12 },
166
+ { nodes: [Cities.Lyon, Cities.Marseille], cost: 8 },
167
+ { nodes: [Cities.Bordeaux, Cities.Marseille], cost: 12 },
168
+ { nodes: [Cities.Marseille, Cities.Barcelona], cost: 11 },
169
+ { nodes: [Cities.Bordeaux, Cities.Barcelona], cost: 15 },
170
+ { nodes: [Cities.Bordeaux, Cities.Madrid], cost: 15 },
171
+ { nodes: [Cities.Madrid, Cities.Barcelona], cost: 14 },
172
+ { nodes: [Cities.Madrid, Cities.Lisboa], cost: 13 },
173
+
174
+ // Red ↔ Pink
175
+ { nodes: [Cities.Paris, Cities.London], cost: 16 },
176
+ { nodes: [Cities.Paris, Cities.Vlaanderen], cost: 7 },
177
+ { nodes: [Cities.Paris, Cities.RheinRuhr], cost: 10 },
178
+
179
+ // Brown — Central North (internal)
180
+ { nodes: [Cities.Bremen, Cities.Berlin], cost: 6 },
181
+ { nodes: [Cities.Bremen, Cities.RheinMain], cost: 9 },
182
+ { nodes: [Cities.Berlin, Cities.RheinMain], cost: 10 },
183
+ { nodes: [Cities.Berlin, Cities.Praha], cost: 7 },
184
+ { nodes: [Cities.RheinMain, Cities.Praha], cost: 10 },
185
+ { nodes: [Cities.RheinMain, Cities.München], cost: 6 },
186
+ { nodes: [Cities.RheinMain, Cities.Stuttgart], cost: 3 },
187
+ { nodes: [Cities.Stuttgart, Cities.München], cost: 5 },
188
+ { nodes: [Cities.München, Cities.Praha], cost: 6 },
189
+ { nodes: [Cities.Praha, Cities.Katowice], cost: 8 },
190
+
191
+ // Brown ↔ Pink
192
+ { nodes: [Cities.Bremen, Cities.Randstad], cost: 8 },
193
+ { nodes: [Cities.Bremen, Cities.Vlaanderen], cost: 10 },
194
+ { nodes: [Cities.RheinMain, Cities.Vlaanderen], cost: 6 },
195
+ { nodes: [Cities.RheinMain, Cities.RheinRuhr], cost: 3 },
196
+
197
+ // Brown ↔ Red
198
+ { nodes: [Cities.Stuttgart, Cities.Paris], cost: 14 },
199
+
200
+ // Yellow — Alpine / Italy / Hungary (internal)
201
+ { nodes: [Cities.Zürich, Cities.Milano], cost: 11 },
202
+ { nodes: [Cities.Milano, Cities.Zagreb], cost: 17 },
203
+ { nodes: [Cities.Milano, Cities.Roma], cost: 19 },
204
+ { nodes: [Cities.Roma, Cities.Napoli], cost: 7 },
205
+ { nodes: [Cities.Wien, Cities.Budapest], cost: 5 },
206
+ { nodes: [Cities.Wien, Cities.Zagreb], cost: 8 },
207
+ { nodes: [Cities.Budapest, Cities.Zagreb], cost: 7 },
208
+
209
+ // Yellow ↔ Red
210
+ { nodes: [Cities.Paris, Cities.Zürich], cost: 14 },
211
+ { nodes: [Cities.Lyon, Cities.Zürich], cost: 14 },
212
+ { nodes: [Cities.Lyon, Cities.Milano], cost: 11 },
213
+ { nodes: [Cities.Marseille, Cities.Milano], cost: 13 },
214
+
215
+ // Yellow ↔ Brown
216
+ { nodes: [Cities.Zürich, Cities.München], cost: 8 },
217
+ { nodes: [Cities.Zürich, Cities.Stuttgart], cost: 5 },
218
+ { nodes: [Cities.München, Cities.Wien], cost: 9 },
219
+ { nodes: [Cities.Praha, Cities.Wien], cost: 7 },
220
+ { nodes: [Cities.Wien, Cities.Katowice], cost: 8 },
221
+ { nodes: [Cities.Budapest, Cities.Katowice], cost: 11 },
222
+
223
+ // Orange — Scandinavia / Baltic (internal)
224
+ { nodes: [Cities.Oslo, Cities.Kobenhavn], cost: 17 },
225
+ { nodes: [Cities.Oslo, Cities.Stockholm], cost: 13 },
226
+ { nodes: [Cities.Stockholm, Cities.Kobenhavn], cost: 18 },
227
+ { nodes: [Cities.Stockholm, Cities.Helsinki], cost: 21 },
228
+ { nodes: [Cities.Helsinki, Cities.StPetersburg], cost: 11 },
229
+ { nodes: [Cities.Tallinn, Cities.StPetersburg], cost: 9 },
230
+ { nodes: [Cities.Tallinn, Cities.Riga], cost: 7 },
231
+ { nodes: [Cities.Riga, Cities.StPetersburg], cost: 13 },
232
+
233
+ // Orange ↔ Brown
234
+ { nodes: [Cities.Kobenhavn, Cities.Bremen], cost: 12 },
235
+ { nodes: [Cities.Kobenhavn, Cities.Berlin], cost: 15 },
236
+
237
+ // Blue — Eastern Europe (internal)
238
+ { nodes: [Cities.Warszawa, Cities.Minsk], cost: 10 },
239
+ { nodes: [Cities.Warszawa, Cities.Kyjiv], cost: 14 },
240
+ { nodes: [Cities.Minsk, Cities.Moskwa], cost: 14 },
241
+ { nodes: [Cities.Minsk, Cities.Kyjiv], cost: 10 },
242
+ { nodes: [Cities.Moskwa, Cities.Kharkiv], cost: 16 },
243
+ { nodes: [Cities.Kyjiv, Cities.Kharkiv], cost: 9 },
244
+ { nodes: [Cities.Kyjiv, Cities.Odessa], cost: 9 },
245
+ { nodes: [Cities.Kharkiv, Cities.Odessa], cost: 13 },
246
+ { nodes: [Cities.Odessa, Cities.Bucuresti], cost: 10 },
247
+
248
+ // Blue ↔ Brown
249
+ { nodes: [Cities.Berlin, Cities.Warszawa], cost: 11 },
250
+ { nodes: [Cities.Praha, Cities.Warszawa], cost: 11 },
251
+ { nodes: [Cities.Katowice, Cities.Warszawa], cost: 5 },
252
+
253
+ // Blue ↔ Orange
254
+ { nodes: [Cities.Kobenhavn, Cities.Warszawa], cost: 25 },
255
+ { nodes: [Cities.Riga, Cities.Warszawa], cost: 12 },
256
+ { nodes: [Cities.Riga, Cities.Minsk], cost: 8 },
257
+ { nodes: [Cities.Riga, Cities.Moskwa], cost: 18 },
258
+ { nodes: [Cities.StPetersburg, Cities.Moskwa], cost: 14 },
259
+
260
+ // Blue ↔ Yellow
261
+ { nodes: [Cities.Kyjiv, Cities.Budapest], cost: 21 },
262
+ { nodes: [Cities.Odessa, Cities.Budapest], cost: 25 },
263
+ { nodes: [Cities.Bucuresti, Cities.Budapest], cost: 16 },
264
+
265
+ // Green — Balkans / Turkey (internal)
266
+ { nodes: [Cities.Beograd, Cities.Sofia], cost: 11 },
267
+ { nodes: [Cities.Beograd, Cities.Tirana], cost: 15 },
268
+ { nodes: [Cities.Sofia, Cities.Tirana], cost: 13 },
269
+ { nodes: [Cities.Sofia, Cities.Athina], cost: 17 },
270
+ { nodes: [Cities.Sofia, Cities.Istanbul], cost: 13 },
271
+ { nodes: [Cities.Tirana, Cities.Athina], cost: 16 },
272
+ { nodes: [Cities.Istanbul, Cities.Izmir], cost: 8 },
273
+ { nodes: [Cities.Istanbul, Cities.Ankara], cost: 9 },
274
+ { nodes: [Cities.Izmir, Cities.Ankara], cost: 10 },
275
+
276
+ // Green ↔ Blue
277
+ { nodes: [Cities.Bucuresti, Cities.Beograd], cost: 12 },
278
+ { nodes: [Cities.Bucuresti, Cities.Sofia], cost: 9 },
279
+ { nodes: [Cities.Bucuresti, Cities.Istanbul], cost: 13 },
280
+
281
+ // Green ↔ Yellow
282
+ { nodes: [Cities.Beograd, Cities.Zagreb], cost: 9 },
283
+ { nodes: [Cities.Beograd, Cities.Napoli], cost: 18 },
284
+ { nodes: [Cities.Beograd, Cities.Budapest], cost: 10 },
285
+ { nodes: [Cities.Tirana, Cities.Napoli], cost: 25 },
286
+ ],
287
+ layout: 'Landscape',
288
+ // Coords were authored against the printed board (~1860x1450). The map area
289
+ // in the default landscape viewBox is roughly 0..1100 x 0..720 (player boards
290
+ // start at x=1105, resource market at y=720). Shrink uniformly to fit and
291
+ // shift up-left so the map sits in the top-left of that area.
292
+ adjustRatio: [0.5, 0.5],
293
+ mapPosition: [-30, -50],
294
+ // Slight clockwise tilt — fits the map's NW-tall / SE-tall extents into the
295
+ // available area better than the un-rotated layout.
296
+ mapRotation: 10,
297
+ // Resupply table verified with John from the Europe refill summary cards.
298
+ // Indexed [resource][playerCount-2][step-1].
299
+ resupply: [
300
+ // Coal
301
+ [
302
+ [2, 6, 2], // 2P
303
+ [2, 6, 2], // 3P
304
+ [3, 7, 4], // 4P
305
+ [3, 8, 4], // 5P
306
+ [5, 10, 5], // 6P
307
+ ],
308
+ // Oil
309
+ [
310
+ [2, 2, 3], // 2P
311
+ [2, 2, 3], // 3P
312
+ [3, 3, 4], // 4P
313
+ [4, 3, 5], // 5P
314
+ [4, 5, 6], // 6P
315
+ ],
316
+ // Garbage
317
+ [
318
+ [2, 3, 5], // 2P
319
+ [2, 3, 5], // 3P
320
+ [3, 4, 5], // 4P
321
+ [3, 5, 7], // 5P
322
+ [4, 6, 8], // 6P
323
+ ],
324
+ // Uranium
325
+ [
326
+ [1, 1, 2], // 2P
327
+ [1, 1, 2], // 3P
328
+ [1, 2, 2], // 4P
329
+ [2, 3, 3], // 5P
330
+ [2, 3, 4], // 6P
331
+ ],
332
+ ],
333
+ // Europe uses price spaces 1–9 (not the standard 1–8 with uranium ending at 16);
334
+ // every resource — including uranium — caps at price 9.
335
+ //
336
+ // Per-price slot counts (verified with John from the board):
337
+ // Coal [4,4,4,2,2,2,2,2,2] total 24 market slots
338
+ // Oil [2,2,2,2,2,2,2,2,4] total 20 market slots
339
+ // Garbage [3,3,3,3,3,3,3,3,0] total 24 market slots
340
+ // Uranium [1,1,1,1,1,1,2,2,2] total 12 market slots
341
+ //
342
+ // Oil note: market capacity is 20 but we keep the total cube count at 24 for now
343
+ // (per Mike's guidance while he tries to reach 2F-Spiele). This means oil can
344
+ // overflow back to the supply pile and a player holding 1–2 oil on power plants
345
+ // can briefly leave the market with oil still available at price 1. If the
346
+ // publisher confirms otherwise, drop startingSupply oil from 24 to 20.
347
+ coalPrices: [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9],
348
+ oilPrices: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9],
349
+ garbagePrices: [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8],
350
+ uraniumPrices: [1, 2, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9],
351
+ // Initial market fill from the rules (coal 2–9, oil 3–9, garbage 3–8, uranium 8–9):
352
+ // coal = 4+4+2+2+2+2+2+2 = 20
353
+ // oil = 2+2+2+2+2+2+4 = 16
354
+ // garbage = 3+3+3+3+3+3 = 18
355
+ // uranium = 2+2 = 4
356
+ startingResources: [20, 16, 18, 4],
357
+ // Total cubes in the game (used cubes return here; refill draws from here).
358
+ startingSupply: [24, 24, 24, 12],
359
+ // Europe market setup: shuffle the deck, draw 9 plants, place the 4 lowest in
360
+ // the current market and the 5 next in the future market, with the Step 3 card
361
+ // buried at the bottom of the deck.
362
+ //
363
+ // The rules call for the New Power Plants Set 2 deck ("plug-back" cards) and a
364
+ // rule against placing a plug-back card on top of the deck — both are no-ops
365
+ // here since this engine ships only one power-plant set. Revisit if/when Set 2
366
+ // is added.
367
+ //
368
+ // The Step 2 trigger for Europe is handled in engine.ts (special branch): it
369
+ // removes the lowest plant from the current market once, then re-sorts the
370
+ // remaining 8 plants into 4 actual + 4 future without drawing from the deck.
371
+ setupDeck(numPlayers: number, variant: string, rng: seedrandom.prng) {
372
+ let powerPlantsDeck = cloneDeep(powerPlants);
373
+
374
+ const step3Index = powerPlantsDeck.findIndex((p) => p.type === PowerPlantType.Step3);
375
+ const step3 = powerPlantsDeck.splice(step3Index, 1)[0];
376
+
377
+ powerPlantsDeck = shuffle(powerPlantsDeck, rng() + '');
378
+
379
+ const initialPlants = powerPlantsDeck.splice(0, 9).sort((a, b) => a.number - b.number);
380
+ const actualMarket = initialPlants.slice(0, 4);
381
+ const futureMarket = initialPlants.slice(4); // 5 plants
382
+
383
+ powerPlantsDeck.push(step3);
384
+
385
+ return { actualMarket, futureMarket, powerPlantsDeck };
386
+ },
387
+ mapSpecificRules:
388
+ 'Europe uses the New Power Plants Set 2 deck (cards with a plug on the back). ' +
389
+ 'The power plant market starts as 4 current + 5 future power plants (9 total). ' +
390
+ 'When Step 2 begins, remove the lowest-numbered plant from the current market from the game once and do not replace it; the future market then has 4 plants instead of 5.',
391
+ };
package/src/maps/korea.ts CHANGED
@@ -1,3 +1,4 @@
1
+ // by John and Cici
1
2
  import { GameMap } from './../maps';
2
3
 
3
4
  export enum Regions {
@@ -182,4 +183,112 @@ export const map: GameMap = {
182
183
  { nodes: [Cities.Seongjin, Cities.Hamheung], cost: 17 },
183
184
  { nodes: [Cities.Hamheung, Cities.Hyesan], cost: 23 },
184
185
  ],
186
+ layout: 'Portrait',
187
+ adjustRatio: [0.22, 0.22],
188
+ mapPosition: [80, 30],
189
+ // Taller than the default Portrait viewBox to make room for Korea's stacked
190
+ // dual resource markets (North above South).
191
+ viewBox: [1480, 1180],
192
+ supplyPosition: [675, 1040],
193
+ // South-side resource market.
194
+ // Indexed [resource][playerCount-2][step-1].
195
+ // Verified from the Korea Recharged rulebook resource table (S rows).
196
+ resupply: [
197
+ // Coal (S)
198
+ [
199
+ [2, 2, 2], // 2P
200
+ [2, 3, 2], // 3P
201
+ [3, 3, 2], // 4P
202
+ [3, 4, 3], // 5P
203
+ [4, 5, 3], // 6P
204
+ ],
205
+ // Oil (S)
206
+ [
207
+ [1, 1, 3],
208
+ [1, 2, 3],
209
+ [2, 3, 3],
210
+ [3, 3, 4],
211
+ [3, 4, 4],
212
+ ],
213
+ // Garbage (S)
214
+ [
215
+ [1, 1, 2],
216
+ [1, 1, 2],
217
+ [1, 2, 2],
218
+ [2, 2, 3],
219
+ [2, 3, 3],
220
+ ],
221
+ // Uranium (S only — North bans nuclear resupply)
222
+ [
223
+ [1, 1, 1],
224
+ [1, 1, 1],
225
+ [1, 2, 2],
226
+ [2, 3, 2],
227
+ [2, 3, 3],
228
+ ],
229
+ ],
230
+ // North-side resource market. Three resources only (no uranium row).
231
+ // Verified from the Korea Recharged rulebook resource table (N rows).
232
+ resupplyNorth: [
233
+ // Coal (N)
234
+ [
235
+ [1, 2, 1],
236
+ [2, 2, 1],
237
+ [2, 3, 2],
238
+ [2, 3, 2],
239
+ [3, 4, 3],
240
+ ],
241
+ // Oil (N)
242
+ [
243
+ [1, 1, 1],
244
+ [1, 1, 1],
245
+ [1, 1, 2],
246
+ [1, 2, 2],
247
+ [2, 2, 3],
248
+ ],
249
+ // Garbage (N)
250
+ [
251
+ [0, 1, 1],
252
+ [0, 1, 1],
253
+ [1, 1, 2],
254
+ [1, 1, 2],
255
+ [1, 2, 3],
256
+ ],
257
+ ],
258
+ // Korea has custom slot counts per price space, different per side.
259
+ // Total resources (across both markets + supply) match standard Power Grid:
260
+ // 24 coal, 24 oil, 24 garbage, 12 uranium.
261
+ //
262
+ // North slots per price [1..8]:
263
+ // coal [2,2,2,2,1,1,1,1] = 12 total
264
+ // oil [1,1,1,1,1,1,1,1] = 8 total
265
+ // garbage [1,1,1,1,1,1,1,1] = 8 total
266
+ //
267
+ // South slots per price [1..8] (uranium prices [1..8,10,12,14,16]):
268
+ // coal [1,1,1,1,2,2,2,2] = 12 total
269
+ // oil [2,2,2,2,2,2,2,2] = 16 total
270
+ // garbage [2,2,2,2,2,2,2,2] = 16 total
271
+ // uranium [1,1,1,1,1,1,1,1,1,1,1,1] = 12 total
272
+ //
273
+ // Initial market fill per rulebook:
274
+ // North: coal 1–8 (12), oil 3–8 (6), garbage 7–8 (2).
275
+ // South: coal 1–8 (12), oil 3–8 (12), garbage 7–8 (4), uranium 14–16 (2).
276
+ startingResources: [12, 12, 4, 2], // South initial market: coal, oil, garbage, uranium
277
+ startingResourcesNorth: [12, 6, 2], // North initial market: coal, oil, garbage
278
+ // Total cubes in the game across BOTH markets + shared supply.
279
+ // Used cubes return to the shared supply; on bureaucracy, North restocks
280
+ // first, then South from whatever remains.
281
+ startingSupply: [24, 24, 24, 12],
282
+ coalPrices: [1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8],
283
+ oilPrices: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8],
284
+ garbagePrices: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8],
285
+ uraniumPrices: [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16],
286
+ coalPricesNorth: [1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8],
287
+ oilPricesNorth: [1, 2, 3, 4, 5, 6, 7, 8],
288
+ garbagePricesNorth: [1, 2, 3, 4, 5, 6, 7, 8],
289
+ mapSpecificRules:
290
+ 'Korea has two separate resource markets: North and South.\n' +
291
+ 'On your buying turn, choose one side — all resources you buy that turn must come from that side. The next turn you may choose the other side.\n' +
292
+ 'The North market has no uranium track; uranium is only available from the South.\n' +
293
+ 'Both markets share a single supply pool. During bureaucracy, North restocks first, then South from whatever remains.',
185
294
  };