diff options
-rw-r--r-- | rules.js | 284 |
1 files changed, 164 insertions, 120 deletions
@@ -1,5 +1,11 @@ "use strict" +// TODO: retreat withdraw co-exist with disrupted enemy - hexside control (wait for Craig) +// TODO: buildup steps in friendly battle hex +// TODO: rout during probe combat? +// TODO: allow one-hex regroup moves? (failed forced march abuse) +// TODO: rewrite regroup to group if only one hex moved (failed forced march abuse) + const max = Math.max const min = Math.min const abs = Math.abs @@ -8,6 +14,11 @@ var states = {} var game = null var view = null +const { + all_hexes, hex_exists, hex_road, side_road, side_limit, hex_name, regions, + unit_name, unit_appearance, unit_elite, unit_class, unit_speed, unit_max_steps, +} = require("./data.js") + var after_rout_table = { end_battle: end_battle, end_refuse_battle_move_2: end_refuse_battle_move_2, @@ -18,11 +29,6 @@ var after_rout_table = { goto_initial_supply_check_rout: goto_initial_supply_check_rout, } -const { - all_hexes, hex_exists, hex_road, side_road, side_limit, hex_name, regions, - unit_name, unit_appearance, unit_elite, unit_class, unit_speed, unit_max_steps, -} = require("./data") - function debug_hexes3(n, list) { console.log("--", n, "--") list = list.map((x,i) => hex_exists[i] ? x : "") @@ -2965,8 +2971,8 @@ states.select_moves = { view.prompt = `Movement: Designate ${game.turn_option} move.` } - let can_group_move = has_valid_group_move_left() - let can_regroup_move = has_valid_regroup_move_left() + let can_group_move = has_valid_group_move_left() ? 1 : 0 + let can_regroup_move = has_valid_regroup_move_left() ? 1 : 0 if (game.phasing === AXIS && game.scenario !== "1940" && game.rommel === 0) { if (game.turn_option === 'offensive' || game.turn_option === 'blitz') { @@ -3850,8 +3856,7 @@ states.forced_marches = { set_unit_disrupted(who) } } - game.forced.splice(ix, 1) - + array_remove(game.forced, ix) resume_forced_marches() } } @@ -7152,122 +7157,11 @@ function gen_action_forced_march(x) { // === COMMON TEMPLATE === -function random(range) { - // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf - return (game.seed = game.seed * 200105 % 34359738337) % range -} - function roll_die() { clear_undo() return random(6) + 1 } -// Sorted array treated as Set (for JSON) -function set_index(set, item) { - let a = 0 - let b = set.length - 1 - while (a <= b) { - let m = (a + b) >> 1 - let x = set[m] - if (item < x) - b = m - 1 - else if (item > x) - a = m + 1 - else - return m - } - return -1 -} - -function set_has(set, item) { - return set_index(set, item) >= 0 -} - -function set_add(set, item) { - let a = 0 - let b = set.length - 1 - while (a <= b) { - let m = (a + b) >> 1 - let x = set[m] - if (item < x) - b = m - 1 - else if (item > x) - a = m + 1 - else - return - } - set.splice(a, 0, item) -} - -function set_delete(set, item) { - let i = set_index(set, item) - if (i >= 0) - set.splice(i, 1) -} - -function set_clear(set) { - set.length = 0 -} - -function set_toggle(set, item) { - if (set_has(set, item)) - set_delete(set, item) - else - set_add(set, item) -} - -function deep_copy(original) { - if (Array.isArray(original)) { - let n = original.length - let copy = new Array(n) - for (let i = 0; i < n; ++i) { - let v = original[i] - if (typeof v === "object" && v !== null) - copy[i] = deep_copy(v) - else - copy[i] = v - } - return copy - } else { - let copy = {} - for (let i in original) { - let v = original[i] - if (typeof v === "object" && v !== null) - copy[i] = deep_copy(v) - else - copy[i] = v - } - return copy - } -} - -function push_undo() { - let copy = {} - for (let k in game) { - let v = game[k] - if (k === "undo") continue - else if (k === "log") v = v.length - else if (typeof v === "object" && v !== null) v = deep_copy(v) - copy[k] = v - } - game.undo.push(copy) -} - -function pop_undo() { - let save_log = game.log - let save_undo = game.undo - let state = save_undo.pop() - save_log.length = state.log - state.log = save_log - state.undo = save_undo - load_state(state) -} - -function clear_undo() { - if (game.undo.length > 0) - game.undo = [] -} - function log_br() { if (game.log.length > 0 && game.log[game.log.length-1] !== "") game.log.push("") @@ -7382,3 +7276,153 @@ function common_view(current) { } return view } + +// === COMMON LIBRARY === + +function random(range) { + // An MLCG using integer arithmetic with doubles. + // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf + // m = 2**35 − 31 + return (game.seed = game.seed * 200105 % 34359738337) % range +} + +// remove item at index (faster than splice) +function array_remove(array, index) { + let n = array.length + for (let i = index + 1; i < n; ++i) + array[i - 1] = array[i] + array.length = n - 1 + return array +} + +// insert item at index (faster than splice) +function array_insert(array, index, item) { + for (let i = array.length; i > index; --i) + array[i] = array[i - 1] + array[index] = item + return array +} + +function set_clear(set) { + set.length = 0 +} + +function set_has(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return true + } + return false +} + +function set_add(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return set + } + return array_insert(set, a, item) +} + +function set_delete(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return array_remove(set, m) + } + return set +} + +function set_toggle(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return array_remove(set, m) + } + return array_insert(set, a, item) +} + +// Fast deep copy for objects without cycles +function object_copy(original) { + if (Array.isArray(original)) { + let n = original.length + let copy = new Array(n) + for (let i = 0; i < n; ++i) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } else { + let copy = {} + for (let i in original) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } +} + +function clear_undo() { + if (game.undo.length > 0) + game.undo = [] +} + +function push_undo() { + let copy = {} + for (let k in game) { + let v = game[k] + if (k === "undo") + continue + else if (k === "log") + v = v.length + else if (typeof v === "object" && v !== null) + v = object_copy(v) + copy[k] = v + } + game.undo.push(copy) +} + +function pop_undo() { + let save_log = game.log + let save_undo = game.undo + let state = save_undo.pop() + save_log.length = state.log + state.log = save_log + state.undo = save_undo + load_state(state) +} |