diff options
-rw-r--r-- | rules.js | 270 |
1 files changed, 237 insertions, 33 deletions
@@ -173,6 +173,8 @@ const NORTHERN_COLONIAL_MILITIAS = 142 const SOUTHERN_COLONIAL_MILITIAS = 143 const ST_LAWRENCE_CANADIAN_MILITIAS = 144 +// MISC DATA + // Patch up leader/box associations. const box_from_leader = [] const leader_from_box = [] @@ -196,6 +198,8 @@ for (let s = first_space; s <= last_space; ++s) { // Make non-breaking names. spaces.forEach(ss => ss.nb_name = ss.name.replace(/ /g, '\xa0')) + +// GLOBALS pieces.forEach(pp => { if (pp.desc) pp.nb_desc = pp.desc.replace(/ /g, '\xa0') if (pp.rdesc) pp.nb_rdesc = pp.rdesc.replace(/ /g, '\xa0') @@ -224,14 +228,14 @@ let last_friendly_leader let last_friendly_piece let last_friendly_unit +// UTILITY FUNCTIONS + function abs(x) { return x < 0 ? -x : x } function random(n) { clear_undo() - if (game.rng === 1) - return ((game.seed = game.seed * 69621 % 0x7fffffff) / 0x7fffffff) * n | 0 return (game.seed = game.seed * 200105 % 34359738337) % n } @@ -351,6 +355,8 @@ function flush_go_home_summary() { } } +// CURRENT PLAYER ALIASES + function enemy() { return game.active === FRANCE ? BRITAIN : FRANCE } @@ -9797,11 +9803,6 @@ exports.setup = function (seed, scenario, options) { // ACTION HANDLERS -function clear_undo() { - if (game.undo && game.undo.length > 0) - game.undo.length = 0 -} - function push_undo() { if (game.undo) { let copy = {} @@ -10006,21 +10007,80 @@ exports.view = function(state, current) { // COMMON LIBRARY -// remove item at index (faster than splice) +function clear_undo() { + if (game.undo) { + game.undo.length = 0 + } +} + +// 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 + } +} + +// Array remove and insert (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_remove_item(array, item) { + let n = array.length + for (let i = 0; i < n; ++i) + if (array[i] === item) + return array_remove(array, i) +} + 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 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 +} + +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 +} + +// Set as plain sorted array + +function set_clear(set) { + set.length = 0 } function set_has(set, item) { @@ -10050,9 +10110,9 @@ function set_add(set, item) { else if (item > x) a = m + 1 else - return set + return } - return array_insert(set, a, item) + array_insert(set, a, item) } function set_delete(set, item) { @@ -10065,36 +10125,180 @@ function set_delete(set, item) { b = m - 1 else if (item > x) a = m + 1 + else { + array_remove(set, m) + return + } + } +} + +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 { + array_remove(set, m) + return + } + } + array_insert(set, a, item) +} + +// Map as plain sorted array of key/value pairs + +function map_clear(map) { + map.length = 0 +} + +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 array_remove(set, m) + return true } - return set + return false } -// 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) +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, 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 { + array_remove_pair(map, m<<1) + return + } + } +} + +function map_for_each(map, f) { + for (let i = 0; i < map.length; i += 2) + f(map[i], map[i+1]) +} + +function object_diff(a, b) { + if (a === b) + return false + if (a !== null && b !== null && typeof a === "object" && typeof b === "object") { + if (Array.isArray(a)) { + if (!Array.isArray(b)) + return true + let a_length = a.length + if (b.length !== a_length) + return true + for (let i = 0; i < a_length; ++i) + if (object_diff(a[i], b[i])) + return true + return false + } + for (let key in a) + if (object_diff(a[key], b[key])) + return true + for (let key in b) + if (!(key in a)) + return true + return false + } + return true +} + +// same as Object.groupBy +function object_group_by(items, callback) { + let groups = {} + if (typeof callback === "function") { + for (let item of items) { + let key = callback(item) + if (key in groups) + groups[key].push(item) else - copy[i] = v + groups[key] = [ item ] } - 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) + for (let item of items) { + let key = item[callback] + if (key in groups) + groups[key].push(item) else - copy[i] = v + groups[key] = [ item ] + } + } + return groups +} + +function map_group_by(items, callback) { + let groups = [] + if (typeof callback === "function") { + for (let item of items) { + let key = callback(item) + let arr = map_get(groups, key) + if (arr) + arr.push(item) + else + map_set(groups, key, [ item ]) + } + } else { + for (let item of items) { + let key = item[callback] + let arr = map_get(groups, key) + if (arr) + arr.push(item) + else + map_set(groups, key, [ item ]) } - return copy } + return groups } /* ASSERTS */ |