diff --git a/src/constants.ts b/src/engine/constants.ts similarity index 100% rename from src/constants.ts rename to src/engine/constants.ts diff --git a/src/rules-board.ts b/src/engine/rules-board.ts similarity index 100% rename from src/rules-board.ts rename to src/engine/rules-board.ts diff --git a/src/rules-initiative.ts b/src/engine/rules-initiative.ts similarity index 100% rename from src/rules-initiative.ts rename to src/engine/rules-initiative.ts diff --git a/src/rules-scoring.ts b/src/engine/rules-scoring.ts similarity index 87% rename from src/rules-scoring.ts rename to src/engine/rules-scoring.ts index 7de49cd..7ecc645 100644 --- a/src/rules-scoring.ts +++ b/src/engine/rules-scoring.ts @@ -41,6 +41,14 @@ function getColumnPresence(state: GameState, column: number) { return [...owners]; } +function addRoundedHalfBonus(scores: number[], counts: number[]) { + counts.forEach((count, playerId) => { + if (count > 0) { + scores[playerId] += Math.ceil(count * 0.5); + } + }); +} + function applyColumnBaseEnergy(state: GameState, scores: number[], ownerId: PlayerId, playersPresent: PlayerId[]) { const contested = playersPresent.length > 1; @@ -105,11 +113,25 @@ function applyWeatherEffects(state: GameState, scores: number[], energySimulatio } if (effectId === "tall_reward") { - tallestLeaves.forEach((row, playerId) => { - if (row !== null) { - scores[playerId] += 2; + const bestRow = tallestLeaves.reduce((currentBest, row) => { + if (row === null) { + return currentBest; } - }); + + if (currentBest === null || row < currentBest) { + return row; + } + + return currentBest; + }, null); + + if (bestRow !== null) { + tallestLeaves.forEach((row, playerId) => { + if (row === bestRow) { + scores[playerId] += 2; + } + }); + } return; } @@ -123,25 +145,39 @@ function applyWeatherEffects(state: GameState, scores: number[], energySimulatio return; } + const westLightCounts = state.players.map(() => 0); + const eastLightCounts = state.players.map(() => 0); + const highNoonCounts = state.players.map(() => 0); + energySimulation.columns.forEach((column) => { if (!column.intercepted || column.ownerId === null) { return; } const region = getColumnRegion(state, column.column); - if (effectId === "west_light" && region === "left") { - scores[column.ownerId] += 1; + if (region === "left") { + westLightCounts[column.ownerId] += 1; } - if (effectId === "east_light" && region === "right") { - scores[column.ownerId] += 1; + if (region === "right") { + eastLightCounts[column.ownerId] += 1; } - if (effectId === "high_noon" && region === "center") { - scores[column.ownerId] += 1; + if (region === "center") { + highNoonCounts[column.ownerId] += 1; } if (effectId === "edge_bloom" && (column.column === 0 || column.column === state.config.columns - 1)) { scores[column.ownerId] += 1; } }); + + if (effectId === "west_light") { + addRoundedHalfBonus(scores, westLightCounts); + } + if (effectId === "east_light") { + addRoundedHalfBonus(scores, eastLightCounts); + } + if (effectId === "high_noon") { + addRoundedHalfBonus(scores, highNoonCounts); + } }); } diff --git a/src/rules-weather.ts b/src/engine/rules-weather.ts similarity index 84% rename from src/rules-weather.ts rename to src/engine/rules-weather.ts index 6b28576..d6a293a 100644 --- a/src/rules-weather.ts +++ b/src/engine/rules-weather.ts @@ -6,12 +6,12 @@ export const WEATHER_CARDS: WeatherCardDefinition[] = [ { id: "branching_season", title: "Branching Season", description: "Each leaf after your first gives +1." }, { id: "storehouse", title: "Storehouse", description: "Banking is enabled this round." }, { id: "sun_ladder", title: "Sun Ladder", description: "Your first 3 vertical growths cost 0." }, - { id: "west_light", title: "West Light", description: "Left third columns give +1." }, - { id: "east_light", title: "East Light", description: "Right third columns give +1." }, - { id: "high_noon", title: "High Noon", description: "Center third columns give +1." }, + { id: "west_light", title: "West Light", description: "Left third energy gets +50%, rounded up." }, + { id: "east_light", title: "East Light", description: "Right third energy gets +50%, rounded up." }, + { id: "high_noon", title: "High Noon", description: "Center third energy gets +50%, rounded up." }, { id: "edge_bloom", title: "Edge Bloom", description: "Edge columns give +1." }, { id: "wide_reach", title: "Wide Reach", description: "Most columns gets +2." }, - { id: "tall_reward", title: "Tall Reward", description: "Your tallest leaf gives +2." }, + { id: "tall_reward", title: "Tall Reward", description: "Tallest leaf on the board gives +2." }, { id: "stalemate", title: "Stalemate", description: "Contested columns give no energy." }, { id: "split_light", title: "Split Light", description: "Contested columns give half to each player there." }, ]; @@ -38,6 +38,7 @@ export function createWeatherDraft(state: GameState): WeatherDraftState { offers: shuffleArray(WEATHER_OFFER_PAIRS).slice(0, rowSize), drafted: [], banned: [], + locked: [], }; } @@ -51,7 +52,10 @@ export function isWeatherCardAvailable(draft: WeatherDraftState, offerId: string return false; } - return offer.options.includes(cardId) && !draft.banned.includes(cardId) && !draft.drafted.includes(cardId); + return offer.options.includes(cardId) + && !draft.banned.includes(cardId) + && !draft.drafted.includes(cardId) + && !draft.locked.includes(cardId); } export function isWeatherOfferResolved(draft: WeatherDraftState, offerId: string) { @@ -60,7 +64,7 @@ export function isWeatherOfferResolved(draft: WeatherDraftState, offerId: string return true; } - return offer.options.every((cardId) => draft.banned.includes(cardId) || draft.drafted.includes(cardId)); + return offer.options.some((cardId) => draft.banned.includes(cardId) || draft.drafted.includes(cardId)); } export function getWeatherCard(cardId: WeatherCardId) { diff --git a/src/state.ts b/src/engine/state.ts similarity index 100% rename from src/state.ts rename to src/engine/state.ts diff --git a/src/types.ts b/src/engine/types.ts similarity index 99% rename from src/types.ts rename to src/engine/types.ts index 9b2195f..08c6960 100644 --- a/src/types.ts +++ b/src/engine/types.ts @@ -222,6 +222,7 @@ export type WeatherDraftState = { offers: WeatherOfferPair[]; drafted: WeatherCardId[]; banned: WeatherCardId[]; + locked: WeatherCardId[]; }; export type GameState = { diff --git a/src/utils.ts b/src/engine/utils.ts similarity index 100% rename from src/utils.ts rename to src/engine/utils.ts diff --git a/src/main.ts b/src/main.ts index e56c0a1..d50decc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1404,24 +1404,33 @@ function renderSidebar() { return `