diff options
author | Tor Andersson <tor@ccxvii.net> | 2023-10-10 14:09:30 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2023-12-10 18:16:55 +0100 |
commit | f15c978b76f57cd27303f2860d4329a86e407d93 (patch) | |
tree | 5e7e2ab158b6b5557383791bdcdeb8270738f734 | |
parent | c5d44d711751f8bf8d668648161e74bcc7bad975 (diff) | |
download | plantagenet-f15c978b76f57cd27303f2860d4329a86e407d93.tar.gz |
Use map structures instead of arrays and bit packing.
There are 28 lords, so packing multiple bits per lord into one word won't work.
Most lords will never be on the map, so carrying around their asset/force/routed data
is wasteful. Use map structures instead, since at most 6 lords will be on the map
at once, and at most 13 on the map + calendar.
-rw-r--r-- | play.js | 85 | ||||
-rw-r--r-- | rules.js | 102 |
2 files changed, 130 insertions, 57 deletions
@@ -6,6 +6,30 @@ function toggle_pieces() { // === COMMON LIBRARY === +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_get_pack4(map, lord, k) { + return pack4_get(map_get(map, lord, 0), k) +} + +function map2_get(map, x, y, v) { + return map_get(map, (x << 1) + y, v) +} + function set_has(set, item) { let a = 0 let b = set.length - 1 @@ -36,11 +60,6 @@ function pack4_get(word, n) { return (word >>> n) & 15 } -function pack8_get(word, n) { - n = n << 3 - return (word >>> n) & 255 -} - // === CONSTANTS (matching those in rules.js) === function find_lord(name) { return data.lords.findIndex((x) => x.name === name) } @@ -349,12 +368,32 @@ function is_lord_ambushed(lord) { return false } +function get_lord_locale(lord) { + return map_get(view.pieces.locale, lord, -1) +} + function get_lord_moved(lord) { - return pack2_get(view.pieces.moved, lord) + return map_get(view.pieces.moved, lord, 0) +} + +function get_lord_assets(lord, n) { + return map_get_pack4(view.pieces.assets, lord, n, 0) } function get_lord_forces(lord, n) { - return pack4_get(view.pieces.forces[lord], n) + return map_get_pack4(view.pieces.forces, lord, n, 0) +} + +function get_lord_routed(lord, n) { + return map_get_pack4(view.pieces.routed, lord, n, 0) +} + +function get_lord_capability(lord, n) { + return map2_get(view.pieces.capabilities, lord, n, -1) +} + +function is_lord_in_exile(ix) { + return pack1_get(view.pieces.in_exile, ix) } function count_lord_all_forces(lord) { @@ -406,10 +445,6 @@ function is_lancaster_locale(loc) { return loc >= first_lancaster_locale && loc <= last_lancaster_locale } -function get_lord_locale(lord) { - return view.pieces.locale[lord] -} - function is_lord_on_map(lord) { let loc = get_lord_locale(lord) return loc !== NOWHERE && loc < CALENDAR @@ -451,14 +486,6 @@ function is_lord_selected(ix) { return false } -function is_lord_in_exile(ix) { - return pack1_get(view.pieces.in_exile, ix) -} - -function get_lord_capability(lord, n) { - return view.pieces.capabilities[(lord << 1) + n] -} - function lord_has_capability_card(lord, c) { let name = data.cards[c].capability let c1 = get_lord_capability(lord, 0) @@ -1114,7 +1141,7 @@ function update_forces(parent, forces, lord_ix, routed) { } }) } else { - let n = pack4_get(forces, i) + let n = map_get_pack4(forces, lord_ix, i, 0) for (let k = 0; k < n; ++k) { add_force(parent, i, lord_ix, routed) } @@ -1122,26 +1149,26 @@ function update_forces(parent, forces, lord_ix, routed) { } } -function update_assets(id, parent, assets) { +function update_assets(parent, assets, lord_ix) { parent.replaceChildren() for (let i = 0; i < asset_type_count; ++i) { - let n = pack4_get(assets, i) + let n = map_get_pack4(assets, lord_ix, i, 0) if (asset_type_x34[i]) { while (n >= 4) { - add_asset(parent, i, 4, id) + add_asset(parent, i, 4, lord_ix) n -= 4 } while (n >= 3) { - add_asset(parent, i, 3, id) + add_asset(parent, i, 3, lord_ix) n -= 3 } } while (n >= 2) { - add_asset(parent, i, 2, id) + add_asset(parent, i, 2, lord_ix) n -= 2 } while (n >= 1) { - add_asset(parent, i, 1, id) + add_asset(parent, i, 1, lord_ix) n -= 1 } } @@ -1168,9 +1195,9 @@ function update_valour(lord, parent, battle) { function update_lord_mat(ix) { if (view.reveal & (1 << ix)) { ui.lord_mat[ix].classList.remove("hidden") - update_assets(ix, ui.assets[ix], view.pieces.assets[ix]) - update_forces(ui.forces[ix], view.pieces.forces[ix], ix, false) - update_forces(ui.routed[ix], view.pieces.routed[ix], ix, true) + update_assets(ui.assets[ix], view.pieces.assets, ix) + update_forces(ui.forces[ix], view.pieces.forces, ix, false) + update_forces(ui.routed[ix], view.pieces.routed, ix, true) ui.lord_feed[ix].classList.toggle("hide", count_lord_all_forces(ix) <= 6) } else { ui.lord_mat[ix].classList.add("hidden") @@ -887,27 +887,30 @@ function set_lord_calendar(lord, turn) { } function get_lord_locale(lord) { - return game.pieces.locale[lord] + return map_get(game.pieces.locale, lord, NOWHERE) } function get_lord_capability(lord, n) { - return game.pieces.capabilities[(lord << 1) + n] + return map2_get(game.pieces.capabilities, lord, n, NOTHING) } function set_lord_capability(lord, n, x) { - game.pieces.capabilities[(lord << 1) + n] = x + if (x === NOTHING) + map2_delete(game.pieces.capabilities, lord, n) + else + map2_set(game.pieces.capabilities, lord, n, x) } function get_lord_assets(lord, n) { - return pack4_get(game.pieces.assets[lord], n) + return map_get_pack4(game.pieces.assets, lord, n) } function get_lord_forces(lord, n) { - return pack4_get(game.pieces.forces[lord], n) + return map_get_pack4(game.pieces.forces, lord, n) } function get_lord_routed_forces(lord, n) { - return pack4_get(game.pieces.routed[lord], n) + return map_get_pack4(game.pieces.routed, lord, n) } function lord_has_unrouted_units(lord) { @@ -939,7 +942,10 @@ function rout_vassal(lord, vassal) { } function set_lord_locale(lord, locale) { - game.pieces.locale[lord] = locale + if (locale === NOWHERE) + map_delete(game.pieces.locale, lord) + else + map_set(game.pieces.locale, lord, locale) } function get_force_name(lord, n, x) { @@ -960,7 +966,7 @@ function set_lord_assets(lord, n, x) { x = 0 if (x > 40) x = 40 - game.pieces.assets[lord] = pack4_set(game.pieces.assets[lord], n, x) + map_set_pack4(game.pieces.assets, lord, n, x) } function add_lord_assets(lord, n, x) { @@ -972,7 +978,7 @@ function set_lord_forces(lord, n, x) { x = 0 if (x > 15) x = 15 - game.pieces.forces[lord] = pack4_set(game.pieces.forces[lord], n, x) + map_set_pack4(game.pieces.forces, lord, n, x) } function add_lord_forces(lord, n, x) { @@ -984,7 +990,7 @@ function set_lord_routed_forces(lord, n, x) { x = 0 if (x > 15) x = 15 - game.pieces.routed[lord] = pack4_set(game.pieces.routed[lord], n, x) + map_set_pack4(game.pieces.routed, lord, n, x) } function add_lord_routed_forces(lord, n, x) { @@ -992,15 +998,15 @@ function add_lord_routed_forces(lord, n, x) { } function clear_lords_moved() { - game.pieces.moved = 0 + map_clear(game.pieces.moved) } function get_lord_moved(lord) { - return pack2_get(game.pieces.moved, lord) + return map_get(game.pieces.moved, lord, 0) } function set_lord_moved(lord, x) { - game.pieces.moved = pack2_set(game.pieces.moved, lord, x) + map_set(game.pieces.moved, lord, x) } function set_lord_fought(lord) { @@ -1221,7 +1227,7 @@ function is_card_in_use(c) { return true if (set_has(game.events, c)) return true - if (game.pieces.capabilities.includes(c)) + if (map_has_value(game.pieces.capabilities, c)) return true return false } @@ -1253,7 +1259,7 @@ function can_discard_card(c) { return true if (set_has(game.hand_l, c)) return true - if (game.pieces.capabilities.includes(c)) + if (map_has_value(game.pieces.capabilities, c)) return true } @@ -1853,18 +1859,23 @@ exports.setup = function (seed, scenario, options) { events: [], // this levy/this campaign cards pieces: { - locale: Array(lord_count).fill(NOWHERE), - assets: Array(lord_count).fill(0), - forces: Array(lord_count).fill(0), - routed: Array(lord_count).fill(0), - capabilities: Array(lord_count << 1).fill(NOTHING), - moved: 0, + // per lord data + locale: [], + assets: [], + forces: [], + routed: [], + capabilities: [], // TODO map card -> lord instead of lord+slot -> card + moved: [], + in_exile: 0, + + // per vassal data vassals: Array(vassal_count).fill(VASSAL_UNAVAILABLE), + + // per locale data depleted: [], exhausted: [], favourl: [], favoury: [], - in_exile: 0, }, flags: { @@ -5167,7 +5178,7 @@ function resume_battle_events() { function could_play_card(c) { if (!game.hidden) { // TODO: check capabilities on lords revealed in battle if hidden - if (game.pieces.capabilities.includes(c)) + if (map_has_value(game.pieces.capabilities, c)) return false } if (set_has(game.events, c)) @@ -8041,6 +8052,11 @@ function pack4_get(word, n) { return (word >>> n) & 15 } +function pack8_get(word, n) { + n = n << 3 + return (word >>> n) & 255 +} + function pack1_set(word, n, x) { return (word & ~(1 << n)) | (x << n) } @@ -8055,11 +8071,6 @@ function pack4_set(word, n, x) { return (word & ~(15 << n)) | (x << n) } -function pack8_get(word, n) { - n = n << 3 - return (word >>> n) & 255 -} - function pack8_set(word, n, x) { n = n << 3 return (word & ~(255 << n)) | (x << n) @@ -8245,6 +8256,41 @@ function set_toggle(set, item) { // Map as plain sorted array of key/value pairs +function map_get_pack4(map, lord, k) { + return pack4_get(map_get(map, lord, 0), k) +} + +function map_set_pack4(map, lord, k, v) { + let val = pack4_set(map_get(map, lord, 0), k, v) + if (val === 0) + map_delete(map, lord) + else + map_set(map, lord, val) +} + +function map2_get(map, x, y, v) { + return map_get(map, (x << 1) + y, v) +} + +function map2_set(map, x, y, v) { + return map_set(map, (x << 1) + y, v) +} + +function map2_delete(map, x, y) { + return map_delete(map, (x << 1) + y) +} + +function map_has_value(map, value) { + for (let i = 1; i < map.length; i += 2) + if (map[i] === value) + return true + return false +} + +function map_clear(map) { + map.length = 0 +} + function map_has(map, key) { let a = 0 let b = (map.length >> 1) - 1 |