From a64246a8df40773167afd6820a3c7ae54acf1a68 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 16 Oct 2024 21:30:07 +0200 Subject: place hussars --- play.js | 13 ++++--- rules.js | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 18 deletions(-) diff --git a/play.js b/play.js index 60b1690..1c08fbd 100644 --- a/play.js +++ b/play.js @@ -41,8 +41,9 @@ const ELIMINATED_TRAIN_DX = 33 const ELIMINATED_GENERAL_X = 340 const ELIMINATED_GENERAL_Y = 110 const ELIMINATED_GENERAL_DX = 50 -const ELIMINATED_DISC_X = 340 + 75 -const ELIMINATED_DISC_Y = 240 + +const HUSSAR_X = 2190 +const HUSSAR_Y = 1630 const power_class = [ "france", "bavaria", "prussia", "saxony", "pragmatic", "austria" ] const power_name = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic", "Austria" ] @@ -726,16 +727,16 @@ function layout_hussar(id, s) { ui.pieces_element.appendChild(e) if (s === ELIMINATED) { - x = ELIMINATED_DISC_X - y = ELIMINATED_DISC_Y + x = HUSSAR_X + y = HUSSAR_Y n = id - 30 } else { x = data.cities.x[s] y = data.cities.y[s] } - e.style.left = (x - 21) + "px" - e.style.top = (y - 29 + 7 - n * 8) + "px" + e.style.left = (x - 21 + n * ELIMINATED_GENERAL_DX) + "px" + e.style.top = (y - 29 + 7) + "px" e.classList.toggle("selected", set_has(view.selected, id)) } diff --git a/rules.js b/rules.js index 0c602ad..28415a6 100644 --- a/rules.js +++ b/rules.js @@ -1,5 +1,11 @@ "use strict" +// TODO: game.selected - singleton instead of array + +// TODO: austria/pragmatic action step - show both sides cards and interleave movement on flanders map +// PLAN: move all austria on bohemia first, then alternate pragmatic and austria activations on flanders map +// TODO: confirm mixed stack creation on flanders map (force "undo" to previous location if denied?) + const R_LOUIS_XV = "Louis XV" const R_FREDERICK = "Frederick" const R_MARIA_THERESA = "Maria Theresa" @@ -16,6 +22,18 @@ var states = {} const data = require("./data") +function is_bohemia_space(s) { + return s >= 0 && s <= 401 +} + +function is_flanders_space(s) { + return s >= 402 && s <= 618 +} + +function is_map_space(s) { + return s >= 0 && s <= 618 +} + function find_city(city) { let n = data.cities.name.length let x = -1 @@ -218,6 +236,20 @@ function all_non_coop_powers(pow) { } } +function all_coop_generals(pow) { + switch (pow) { + case P_FRANCE: + case P_BAVARIA: + return all_france_bavaria_generals + case P_PRUSSIA: + case P_SAXONY: + return all_prussia_saxony_generals + case P_PRAGMATIC: + case P_AUSTRIA: + return all_austria_pragmatic_generals + } +} + function all_controlled_generals(pow) { switch (pow) { case P_FRANCE: @@ -662,7 +694,7 @@ function goto_start_turn() { // MARIA: politics // MARIA: hussars - goto_action_stage() + goto_place_hussars() } function goto_action_stage() { @@ -693,6 +725,83 @@ function check_victory() { return false } +/* HUSSARS */ + +function goto_place_hussars() { + set_active_to_power(P_AUSTRIA) + game.state = "place_hussars" +} + +function end_place_hussars() { + set_clear(game.moved) + goto_action_stage() +} + +states.place_hussars = { + inactive: "place Hussars", + prompt() { + prompt("Place the Hussars.") + for (let p of all_hussars) + if (!set_has(game.moved, p)) + gen_action_piece(p) + view.actions.next = 1 + }, + piece(p) { + push_undo() + set_add(game.moved, p) + game.selected = p + game.state = "place_hussars_where" + }, + next() { + end_place_hussars() + }, +} + +states.place_hussars_where = { + inactive: "place Hussars", + prompt() { + prompt("Place the Hussar in a city.") + view.selected = game.selected + + // bohemia + // within 4 of an austrian general + // not occupied by any piece + for (let p of all_power_generals[P_AUSTRIA]) { + let s = game.pos[p] + if (is_bohemia_space(s)) + for (let x of search_hussar_bfs(s)) + gen_action_space(x) + } + }, + space(to) { + game.state = "place_hussars" + game.pos[game.selected] = to + game.selected = -1 + }, +} + +function search_hussar_bfs(from) { + let seen = [ from ] + let queue = [ from << 4 ] + while (queue.length > 0) { + let item = queue.shift() + let here = item >> 4 + let dist = (item & 15) + 1 + for (let next of data.cities.adjacent[here]) { + if (set_has(seen, next)) + continue + if (!is_bohemia_space(next)) + continue + if (!has_any_piece(next)) + set_add(seen, next) + if (dist < 4) + queue.push((next << 4) | dist) + } + } + set_delete(seen, from) + return seen +} + /* TACTICAL CARDS */ function find_largest_discard(u) { @@ -1071,16 +1180,6 @@ function move_general_to(to) { game.pos[p] = to } - // uniting stacks (turn all oos if one is oos) - let oos = false - for (let p of all_controlled_generals(game.power)) - if (game.pos[p] === to && is_out_of_supply(p)) - oos = true - if (oos) - for (let p of all_controlled_generals(game.power)) - if (game.pos[p] === to) - set_out_of_supply(p) - // conquer space if (is_conquest_space(pow, from) && !set_has(game.conquest, from)) { if (is_protected_from_conquest(from)) { @@ -1113,13 +1212,23 @@ function move_general_to(to) { } // uniting stacks: flag all as moved and stop moving - for (let p of all_controlled_generals(pow)) { + for (let p of all_coop_generals(pow)) { if (game.pos[p] === to && !set_has(game.selected, p)) { set_add(game.moved, p) stop = true } } + // remove hussars + for (let p of all_hussars) { + if (game.pos[p] === to) { + if (!game.move_elim) + game.move_elim = [] + set_add(game.move_elim, p) + game.pos[p] = ELIMINATED + } + } + return stop } -- cgit v1.2.3