From fdbe7f2b30ed3d88be9ef0b4cbc17e66a8c07eeb Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 20 Jun 2022 22:11:54 +0200 Subject: Optimize loops. Use for (let x of list) instead of for (let x in object). This gives a ~100% speed-up. --- rules.js | 110 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/rules.js b/rules.js index 8e67ff6..a0175cc 100644 --- a/rules.js +++ b/rules.js @@ -13,6 +13,9 @@ exports.roles = [ const { CARDS, SPACES, EDGES, BLOCKS } = require('./data') +const BLOCKLIST = Object.keys(BLOCKS) +const SPACELIST = Object.keys(SPACES) + const APOLLO = 1 const JUPITER = 2 const MARS = 3 @@ -310,28 +313,44 @@ function enemy_player() { function count_friendly(where) { let count = 0 let p = game.active - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where && block_owner(b) === p) ++count } return count } +function has_friendly(where) { + let p = game.active + for (let b of BLOCKLIST) + if (game.location[b] === where && block_owner(b) === p) + return true + return false +} + function count_enemy(where) { let count = 0 let p = enemy_player() - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where && block_owner(b) === p) ++count } return count } +function has_enemy(where) { + let p = enemy_player() + for (let b of BLOCKLIST) + if (game.location[b] === where && block_owner(b) === p) + return true + return false +} + function count_pinning(where) { let count = 0 if (game.active === game.p2) { let p = enemy_player() - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where && block_owner(b) === p) if (!game.reserves.includes(b)) ++count @@ -342,7 +361,7 @@ function count_pinning(where) { function count_pinned(where) { let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where && block_owner(b) === game.active) if (!game.reserves.includes(b)) ++count @@ -381,10 +400,10 @@ function is_navis(b) { return BLOCKS[b].type === 'navis' } -function is_friendly_space(where) { return count_friendly(where) > 0 && count_enemy(where) === 0 } -function is_enemy_space(where) { return count_friendly(where) === 0 && count_enemy(where) > 0 } +function is_friendly_space(where) { return has_friendly(where) && count_enemy(where) === 0 } +function is_enemy_space(where) { return count_friendly(where) === 0 && has_enemy(where) } function is_vacant_space(where) { return count_friendly(where) === 0 && count_enemy(where) === 0 } -function is_contested_space(where) { return count_friendly(where) > 0 && count_enemy(where) > 0 } +function is_contested_space(where) { return has_friendly(where) && has_enemy(where) } function is_friendly_city(where) { return is_city(where) && is_friendly_space(where) } function is_enemy_city(where) { return is_city(where) && is_enemy_space(where) } @@ -395,10 +414,7 @@ function is_vacant_sea(where) { return is_sea(where) && is_vacant_space(where) } function is_contested_sea(where) { return is_sea(where) && is_contested_space(where) } function have_contested_spaces() { - for (let where in SPACES) - if (is_map_space(where) && is_contested_space(where)) - return true - return false + return SPACELIST.some(where => is_map_space(where) && is_contested_space(where)) } function supply_limit(where) { @@ -409,7 +425,7 @@ function supply_limit(where) { function is_over_supply_limit(where) { let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where) ++count } @@ -422,7 +438,7 @@ function count_vp() { game.c_vp = 0 game.p_vp = 0 game.active = CAESAR - for (let s in SPACES) { + for (let s of SPACELIST) { if (is_friendly_city(s)) game.c_vp += SPACES[s].value if (is_enemy_city(s)) @@ -695,7 +711,7 @@ function can_levy(b) { if (block_owner(b) !== game.active) return false if (location === LEVY) { - for (let to in SPACES) + for (let to of SPACELIST) if (can_levy_to(b, to)) return true return false @@ -712,7 +728,7 @@ let states = {} function start_free_deployment() { game.active = CAESAR game.setup_limit = {} - for (let space in SPACES) { + for (let space of SPACELIST) { if (is_map_space(space)) { let n = count_friendly(space) + count_enemy(space) if (n > 0) @@ -726,7 +742,7 @@ function start_free_deployment() { function validate_free_deployment() { game.setup_error = [] - for (let space in SPACES) { + for (let space of SPACELIST) { if (is_friendly_city(space)) { let n = count_friendly(space) let d = n - game.setup_limit[space] @@ -753,7 +769,7 @@ states.free_deployment = { } else { format_deployment_error(view) } - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_map_space(game.location[b])) gen_action(view, 'block', b) }, @@ -788,7 +804,7 @@ states.free_deployment_to = { } gen_action_undo(view) gen_action(view, 'block', game.who) - for (let space in SPACES) { + for (let space of SPACELIST) { if (space in game.setup_limit && space !== game.location[game.who]) { if (!is_enemy_city(space)) { if (block_type(game.who) === 'navis') { @@ -1153,7 +1169,7 @@ states.jupiter = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + "..." view.prompt = "Jupiter: Choose one enemy army adjacent to a friendly city." - for (let s in SPACES) { + for (let s of SPACELIST) { if (is_friendly_city(s)) { for (let to of SPACES[s].exits) if (is_enemy_city(to) || is_contested_city(to)) @@ -1165,7 +1181,7 @@ states.jupiter = { space: function (where) { /* pick a random block */ let list = [] - for (let x in BLOCKS) + for (let x of BLOCKLIST) if (game.location[x] === where) list.push(x) let i = random(list.length) @@ -1178,7 +1194,7 @@ states.jupiter = { jupiter_block(CLEOPATRA) } else { let list = [] - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && BLOCKS[b].owner === owner) list.push(b) let i = random(list.length) @@ -1214,14 +1230,14 @@ states.vulcan = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + "..." view.prompt = "Vulcan: Choose an enemy city to suffer a volcanic eruption." - for (let s in SPACES) + for (let s of SPACELIST) if (is_enemy_city(s)) gen_action(view, 'space', s) }, space: function (city) { log("Vulcan struck " + city + "!") if (game.automatic_disruption) { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === city) reduce_block(b) // uh-oh! cleopatra switched sides! @@ -1231,7 +1247,7 @@ states.vulcan = { } else { game.where = city game.vulcan = [] - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === city) game.vulcan.push(b) game.active = enemy(game.active) @@ -1265,7 +1281,7 @@ states.apply_vulcan = { function goto_mars_and_neptune() { game.surprise_list = [] - for (let where in SPACES) + for (let where of SPACELIST) if (is_map_space(where) && is_contested_space(where)) game.surprise_list.push(where) if (game.surprise_list.length === 0) { @@ -1343,7 +1359,7 @@ states.move_who = { else view.prompt = "Choose an army to group move. "+game.moves+"MP left." if (game.moves === 0) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { let from = game.location[b] if (game.activated.includes(from)) if (can_block_move(b)) @@ -1351,7 +1367,7 @@ states.move_who = { } } else { let have_amphibious = false - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { let can_move = false if (game.amphibious_available && can_amphibious_move(b)) { can_move = true @@ -1610,7 +1626,7 @@ states.levy = { view.prompt = "Choose an army to levy. "+game.levies+"LP left." let is_levy_possible = false if (game.levies > 0) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (can_levy(b)) { gen_action(view, 'block', b) is_levy_possible = true @@ -1652,7 +1668,7 @@ states.levy_where = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + " to levy..." view.prompt = "Choose a friendly city to levy " + block_name(game.who) + " in." - for (let to in SPACES) + for (let to of SPACELIST) if (can_levy_to(game.who, to)) gen_action(view, 'space', to) gen_action(view, 'block', game.who); // for canceling levy @@ -1697,7 +1713,7 @@ states.pick_battle = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + " to pick a battle..." view.prompt = "Choose the next battle to fight!" - for (let s in SPACES) + for (let s of SPACELIST) if (is_contested_city(s) || is_contested_sea(s)) gen_action(view, 'space', s) }, @@ -1721,7 +1737,7 @@ function is_defender(b) { function count_attackers() { let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_attacker(b)) ++count } @@ -1730,7 +1746,7 @@ function count_attackers() { function count_defenders() { let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_defender(b)) ++count } @@ -1755,7 +1771,7 @@ function resume_battle() { } function bring_on_reserves() { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where) { remove_from_array(game.reserves, b) } @@ -1765,14 +1781,14 @@ function bring_on_reserves() { function goto_disrupt_reserves() { game.flash = "Reserves were disrupted." if (game.automatic_disruption) { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where && block_owner(b) === game.attacker[game.where]) if (game.reserves.includes(b)) reduce_block(b) end_disrupt_reserves() } else { game.disrupted = [] - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where && block_owner(b) === game.attacker[game.where]) if (game.reserves.includes(b)) game.disrupted.push(b) @@ -1851,7 +1867,7 @@ function start_battle_round() { function pump_battle_round() { function filter_battle_blocks(ci, is_candidate) { let output = null - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_candidate(b) && !game.moved[b]) { if (block_initiative(b) === ci) { if (!output) @@ -2059,11 +2075,11 @@ function goto_battle_hits() { function list_victims(p) { let is_candidate = (p === game.attacker[game.where]) ? is_attacker : is_defender let max = 0 - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_candidate(b) && block_strength(b) > max) max = block_strength(b) let list = [] - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_candidate(b) && block_strength(b) === max) list.push(b) return list @@ -2188,7 +2204,7 @@ states.regroup = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + " to regroup..." view.prompt = "Regroup: Choose an army to move." - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where) { if (can_regroup(b)) gen_action(view, 'block', b) @@ -2287,7 +2303,7 @@ function check_victory() { function count_navis_to_port() { let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && BLOCKS[b].type === 'navis') if (SPACES[game.location[b]].type === 'sea') if (can_navis_move_to_port(b)) @@ -2329,7 +2345,7 @@ states.navis_to_port = { return view.prompt = "Waiting for " + game.active + " to move navis to port..." view.prompt = "Move all Navis to a friendly port." let count = 0 - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && BLOCKS[b].type === 'navis') { if (SPACES[game.location[b]].type === 'sea') { if (can_navis_move_to_port(b)) { @@ -2393,7 +2409,7 @@ states.disband = { if (is_inactive_player(current)) return view.prompt = "Waiting for " + game.active + " to disband..." let okay_to_end = true - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && is_map_space(game.location[b]) && b !== CLEOPATRA) { if (is_over_supply_limit(game.location[b])) { okay_to_end = false @@ -2406,7 +2422,7 @@ states.disband = { view.prompt = "Disband armies in excess of supply." } else { view.prompt = "You may disband armies to your levy pool." - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_map_space(game.location[b])) if (block_owner(b) === game.active && b !== CLEOPATRA) gen_action(view, 'block', b) @@ -2437,7 +2453,7 @@ states.disband = { function end_year() { game.year ++ - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === DEAD && BLOCKS[b].type !== 'leader') { disband_block(b) } @@ -2567,7 +2583,7 @@ exports.setup = function (seed, scenario, options) { } function deploy_block(owner, location, name) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (BLOCKS[b].owner === owner && BLOCKS[b].name === name) { game.steps[b] = BLOCKS[b].steps game.location[b] = location @@ -2577,7 +2593,7 @@ function deploy_block(owner, location, name) { } function setup_historical_deployment() { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { game.location[b] = LEVY game.steps[b] = BLOCKS[b].steps } @@ -2660,7 +2676,7 @@ function make_battle_view() { } function fill_cell(name, p, fn) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where & block_owner(b) === p && fn(b)) { bv[name].push(b) } -- cgit v1.2.3