From 0cee28075504d3354e5c327200d472c760452b94 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sun, 12 Nov 2023 14:34:56 +0100 Subject: Show border limits. --- rules.js | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 122 insertions(+), 20 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index 5efce8c..9bca996 100644 --- a/rules.js +++ b/rules.js @@ -27,6 +27,9 @@ const ENEMY = { Lancaster: "York", York: "Lancaster" } const OBSERVER = "Observer" const BOTH = "Both" +const PLAYER_ID = { "": 0, Lancaster: 1, York: 2 } +const ID_PLAYER = [ "", "Lancaster", "York" ] + // areas const NOWHERE = 0 const POOL = 1 @@ -608,11 +611,11 @@ function border_id(a, b) { } function border_was_last_used_by_enemy(from, to) { - return game.last_used[border_id(from, to)] === ENEMY[game.active] + return map_get(game.last_used, border_id(from, to), 0) === PLAYER_ID[ENEMY[game.active]] } function border_was_last_used_by_active(from, to) { - return game.last_used[border_id(from, to)] === game.active + return map_get(game.last_used, border_id(from, to), 0) === PLAYER_ID[game.active] } function border_type(a, b) { @@ -620,11 +623,15 @@ function border_type(a, b) { } function border_limit(a, b) { - return game.border_limit[border_id(a,b)] || 0 + return map_get(game.border_limit, border_id(a,b), 0) +} + +function set_border_limit(a, b, n) { + map_set(game.border_limit, border_id(a,b), n) } function reset_border_limits() { - game.border_limit = {} + game.border_limit.length = 0 } function count_friendly(where) { @@ -1399,7 +1406,7 @@ function start_game_turn() { // Reset movement and attack tracking state reset_border_limits() - game.last_used = {} + game.last_used = [] game.attacker = {} set_clear(game.reserves) set_clear(game.moved) @@ -1733,7 +1740,7 @@ states.muster_move_2 = { // ACTION PHASE function use_border(from, to) { - game.border_limit[border_id(from, to)] = border_limit(from, to) + 1 + set_border_limit(from, to, border_limit(from, to) + 1) } function move_block(who, from, to) { @@ -1741,12 +1748,12 @@ function move_block(who, from, to) { use_border(from, to) game.distance ++ if (is_contested_area(to)) { - game.last_used[border_id(from, to)] = game.active + map_set(game.last_used, border_id(from, to), PLAYER_ID[game.active]) if (!game.attacker[to]) { game.attacker[to] = game.active - game.main_border[to] = from + map_set(game.main_border, to, from) } else { - if (game.attacker[to] !== game.active || game.main_border[to] !== from) { + if (game.attacker[to] !== game.active || map_get(game.main_border, to, 0) !== from) { set_add(game.reserves, who) return RESERVE_MARK } @@ -1760,8 +1767,8 @@ function goto_action_phase(moves) { game.state = 'action_phase' game.moves = moves game.activated = [] - game.move_port = {} - game.main_border = {} + game.move_port = [] + game.main_border = [] game.turn_log = [] game.recruit_log = [] clear_undo() @@ -1812,7 +1819,7 @@ states.action_phase = { } if (can_block_sea_move(b)) { if (game.moves === 0) { - if (game.move_port[game.location[b]] !== undefined) + if (map_has(game.move_port, game.location[b])) gen_action(view, 'block', b) } else { gen_action(view, 'block', b) @@ -1892,7 +1899,7 @@ states.move_to = { let has_destination_port = false if (game.moves === 0) { for (let port of AREAS[to].exits) - if (game.move_port[game.origin] === port) + if (map_get(game.move_port, game.origin) === port) has_destination_port = true } else { if (game.active === game.piracy) @@ -1923,6 +1930,7 @@ states.move_to = { log_move_start(from) game.last_from = from if (is_sea_area(to)) { + // XXX use_border(from, to) // if displaying sea moves log_move_continue(to) game.location[game.who] = to game.state = 'sea_move_to' @@ -1953,7 +1961,7 @@ states.sea_move_to = { continue if (is_friendly_or_vacant_area(to)) { if (game.moves === 0) { - if (game.move_port[game.origin] === to) + if (map_get(game.move_port, game.origin) === to) gen_action(view, 'area', to) } else { gen_action(view, 'area', to) @@ -1965,6 +1973,8 @@ states.sea_move_to = { } }, area: function (to) { + // XXX use_border(game.location[game.who], to) // if displaying sea moves + game.location[game.who] = to set_add(game.moved, game.who) @@ -1979,13 +1989,13 @@ states.sea_move_to = { } else { // Can sea move two blocks between same major ports for 1 AP. log_move_continue(to) - if (game.move_port[game.origin] === to) { - delete game.move_port[game.origin] + if (map_get(game.move_port, game.origin) === to) { + map_delete(game.move_port, game.origin) } else { logp("sea moved.") --game.moves if (is_major_port(game.origin) && is_major_port(to)) - game.move_port[game.origin] = to + map_set(game.move_port, game.origin, to) } } @@ -2020,6 +2030,7 @@ function end_action() { // BATTLE PHASE function goto_battle_phase() { + reset_border_limits() if (have_contested_areas()) { game.active = game.p1 game.state = 'battle_phase' @@ -3463,9 +3474,9 @@ exports.setup = function (seed, scenario, options) { reserves: [], attacker: {}, - border_limit: {}, - last_used: {}, - main_border: {}, + border_limit: [], + last_used: [], + main_border: [], } // Old RNG for ancient replays @@ -3537,10 +3548,18 @@ exports.view = function(state, current) { steps: game.steps, moved: game.moved, dead: game.dead, + last_used: game.last_used, + border_limit: game.border_limit, battle: null, prompt: null, } + if (game.main_border && game.main_border.length > 0) { + view.main_border = [] + for (let i = 0; i < game.main_border.length; i += 2) + set_add(view.main_border, border_id(game.main_border[i+0], game.main_border[i+1])) + } + states[game.state].prompt(view, current) if (states[game.state].show_battle) @@ -3560,6 +3579,13 @@ function array_remove(array, index) { return array } +function array_remove_pair(array, index) { + let n = array.length + for (let i = index + 2; i < n; ++i) + array[i - 2] = array[i] + array.length = n - 2 +} + // insert item at index (faster than splice) function array_insert(array, index, item) { for (let i = array.length; i > index; --i) @@ -3568,6 +3594,15 @@ function array_insert(array, index, item) { return array } +function array_insert_pair(array, index, key, value) { + for (let i = array.length; i > index; i -= 2) { + array[i] = array[i-2] + array[i+1] = array[i-1] + } + array[index] = key + array[index+1] = value +} + function set_clear(set) { set.length = 0 } @@ -3620,6 +3655,73 @@ function set_delete(set, item) { return set } +function map_has(map, key) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m<<1] + if (key < x) + b = m - 1 + else if (key > x) + a = m + 1 + else + return true + } + return false +} + +function map_get(map, key, missing) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m<<1] + if (key < x) + b = m - 1 + else if (key > x) + a = m + 1 + else + return map[(m<<1)+1] + } + return missing +} + +function map_set(map, key, value) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m<<1] + if (key < x) + b = m - 1 + else if (key > x) + a = m + 1 + else { + map[(m<<1)+1] = value + return + } + } + array_insert_pair(map, a<<1, key, value) +} + +function map_delete(map, item) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m<<1] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove_pair(map, m<<1) + return + } + } +} + // Fast deep copy for objects without cycles function object_copy(original) { if (Array.isArray(original)) { -- cgit v1.2.3