diff options
-rw-r--r-- | rules.js | 120 |
1 files changed, 62 insertions, 58 deletions
@@ -77,6 +77,10 @@ delete TOWNS[F_POOL]; delete TOWNS[S_POOL]; delete TOWNS[SEA]; +// Quick lists for fast iteration +const BLOCKLIST = Object.keys(BLOCKS) +const TOWNLIST = Object.keys(TOWNS) + let states = {}; let game = null; @@ -259,7 +263,7 @@ function deal_cards(deck, n) { function select_random_block(where) { let list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where) list.push(b); if (list.length === 0) @@ -269,7 +273,7 @@ function select_random_block(where) { function select_random_enemy_block(where) { let list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === enemy(game.active)) list.push(b); if (list.length === 0) @@ -416,7 +420,7 @@ function reset_road_limits() { function count_player(p, where) { let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) ++count; return count; @@ -425,7 +429,7 @@ function count_player(p, where) { function count_friendly(where) { let p = game.active; let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) ++count; return count; @@ -434,7 +438,7 @@ function count_friendly(where) { function count_enemy(where) { let p = enemy(game.active); let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) ++count; return count; @@ -443,7 +447,7 @@ function count_enemy(where) { function count_friendly_in_field(where) { let p = game.active; let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b)) ++count; @@ -453,7 +457,7 @@ function count_friendly_in_field(where) { function count_enemy_in_field(where) { let p = enemy(game.active); let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b)) ++count; @@ -463,7 +467,7 @@ function count_enemy_in_field(where) { function count_friendly_in_field_excluding_reserves(where) { let p = game.active; let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b) && !is_reserve(b)) ++count; @@ -473,7 +477,7 @@ function count_friendly_in_field_excluding_reserves(where) { function count_enemy_in_field_excluding_reserves(where) { let p = enemy(game.active); let count = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b) && !is_reserve(b)) ++count; @@ -482,7 +486,7 @@ function count_enemy_in_field_excluding_reserves(where) { function count_blocks_in_castle(where) { let n = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === where && game.castle.includes(b)) ++n; return n; @@ -490,7 +494,7 @@ function count_blocks_in_castle(where) { function count_enemy_in_field_and_reserve(where) { let n = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) !== game.active) if (game.location[b] === where && !game.castle.includes(b)) ++n; @@ -499,7 +503,7 @@ function count_enemy_in_field_and_reserve(where) { function count_reserves(where) { let n = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active) if (game.location[b] === where && is_reserve(b)) ++n; @@ -632,7 +636,7 @@ function is_block_in_castle_in(b, town) { } function besieged_player(where) { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_block_in_castle_in(b, where)) return block_owner(b); return null; @@ -669,7 +673,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 (!is_reserve(b)) ++count; @@ -955,14 +959,14 @@ function can_block_muster(who, muster) { } function can_muster_to(muster) { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (can_block_muster(b, muster)) return true; return false; } function can_muster_anywhere() { - for (let where in TOWNS) + for (let where of TOWNLIST) if (is_friendly_field(where)) if (can_muster_to(where)) return true; @@ -972,19 +976,19 @@ function can_muster_anywhere() { function lift_siege(where) { if (is_under_siege(where) && !is_contested_town(where)) { log("Siege lifted in " + where + "."); - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_block_in_castle_in(b, where)) remove_from_array(game.castle, b); } } function lift_all_sieges() { - for (let t in TOWNS) + for (let t of TOWNLIST) lift_siege(t); } function reset_blocks() { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { game.location[b] = null; game.steps[b] = block_max_steps(b); } @@ -1028,7 +1032,7 @@ function reduce_block(who) { function is_valid_frank_deployment() { let errors = []; - for (let town in TOWNS) + for (let town of TOWNLIST) if (!is_within_castle_limit(town)) errors.push(town); return errors; @@ -1047,7 +1051,7 @@ states.frank_deployment = { let errors = is_valid_frank_deployment(); if (errors.length === 0) gen_action(view, 'next'); - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && is_block_on_land(b)) if (list_seats(b).length > 1) gen_action(view, 'block', b); @@ -1385,7 +1389,7 @@ states.assassins = { if (is_inactive_player(current)) return view.prompt = "Assassins: Waiting for " + game.active + "."; view.prompt = "Assassins: Choose one enemy block."; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_block_on_land(b) && block_owner(b) === enemy(game.active)) gen_action(view, 'block', b); } @@ -1473,7 +1477,7 @@ function goto_jihad() { function goto_select_jihad() { game.jihad_list = []; - for (let where in TOWNS) + for (let where of TOWNLIST) if (is_contested_field(where) || besieging_player(where) === game.active) game.jihad_list.push(where); if (game.jihad_list.length === 0) { @@ -1520,7 +1524,7 @@ states.manna = { gen_action_undo(view); gen_action(view, 'next'); if (game.moves > 0) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (is_block_on_land(b) && block_owner(b) === game.active && !game.moved[b]) if (game.steps[b] < block_max_steps(b)) gen_action(view, 'block', b); @@ -1660,7 +1664,7 @@ states.move_phase = { gen_action_undo(view); gen_action(view, 'end_move_phase'); if (game.moves > 0) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (can_block_land_move(b)) gen_action(view, 'block', b); if (can_block_sea_move(b)) @@ -1708,7 +1712,7 @@ states.move_phase_event = { view.prompt = group_move_name(0) + "Choose a block to group move."; gen_action_undo(view); gen_action(view, 'end_move_phase'); - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (can_block_land_move(b)) gen_action(view, 'block', b); }, @@ -1792,7 +1796,7 @@ function group_move_name() { } function can_group_move_more() { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where) if (can_block_land_move(b)) return true; @@ -1809,7 +1813,7 @@ states.group_move_who = { gen_action(view, 'end_move_phase'); else gen_action(view, 'end_group_move'); - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where) if (can_block_land_move(b)) gen_action(view, 'block', b); @@ -1982,7 +1986,7 @@ states.muster = { return view.prompt = "Move Phase: Waiting for " + game.active + "."; view.prompt = "Muster: Choose a friendly muster town."; gen_action_undo(view); - for (let where in TOWNS) { + for (let where of TOWNLIST) { // cannot start or reinforce battles in winter if (is_winter()) { if (is_friendly_town(where)) @@ -2012,7 +2016,7 @@ states.muster_who = { view.muster = game.where; gen_action_undo(view); gen_action(view, 'end_muster'); - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (can_block_muster(b, game.where)) gen_action(view, 'block', b); }, @@ -2149,7 +2153,7 @@ states.winter_campaign = { return view.prompt = "Move Phase: Waiting for " + game.active + "."; view.prompt = "Winter Campaign: Select a siege to maintain over the winter."; gen_action_undo(view); - for (let town in TOWNS) + for (let town of TOWNLIST) if (is_friendly_field(town) && is_under_siege(town)) gen_action(view, 'town', town); }, @@ -2170,7 +2174,7 @@ function goto_combat_phase() { } game.combat_list = []; - for (let where in TOWNS) + for (let where of TOWNLIST) if (is_contested_town(where)) game.combat_list.push(where); resume_combat_phase(); @@ -2267,7 +2271,7 @@ states.combat_deployment = { let n = count_blocks_in_castle(game.where); let have_options = false; if (n < max) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b)) { if (game.location[b] === game.where && !game.castle.includes(b)) { gen_action(view, 'withdraw', b); @@ -2330,7 +2334,7 @@ states.regroup = { view.prompt = "Regroup: Choose a block to move."; gen_action_undo(view); gen_action(view, 'end_regroup'); - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where) { if (can_block_regroup(b)) gen_action(view, 'block', b); @@ -2398,7 +2402,7 @@ function next_combat_round() { function bring_on_reserves(reserves) { let f = 0; let s = 0; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where) { if (reserves.includes(b)) { if (block_owner(b) === FRANKS) @@ -2416,7 +2420,7 @@ function bring_on_reserves(reserves) { } function clear_reserves(where) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === where) { remove_from_array(game.reserves1, b); remove_from_array(game.reserves2, b); @@ -2501,7 +2505,7 @@ states.declare_storm = { view.prompt = "Siege Declaration: Declare which blocks should storm the castle."; let have_options = false; if (game.storming.length < castle_limit(game.where)) { - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b)) { if (game.location[b] === game.where && !game.storming.includes(b)) { gen_action(view, 'storm', b); @@ -2559,7 +2563,7 @@ states.declare_sally = { return view.prompt = "Siege Declaration: Waiting for " + game.active + " to declare sally."; view.prompt = "Siege Declaration: Declare which blocks should sally onto the field."; let have_options = false; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b) && is_block_in_castle(b)) { if (game.location[b] === game.where && !game.sallying.includes(b)) { gen_action(view, 'sally', b); @@ -2643,7 +2647,7 @@ states.retreat = { view.prompt = "Retreat: Choose a block to move."; gen_action_undo(view); let can_retreat = false; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (game.location[b] === game.where && !is_block_in_castle(b) && can_block_retreat(b)) { gen_action(view, 'block', b); can_retreat = true; @@ -2654,7 +2658,7 @@ states.retreat = { }, end_retreat: function () { clear_undo(); - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where && !is_block_in_castle(b) && block_owner(b) === game.active) eliminate_block(b); print_summary(game.active + " retreated:"); @@ -2709,7 +2713,7 @@ function goto_siege_attrition() { game.active = besieged_player(game.where); game.state = 'siege_attrition'; game.attrition_list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_block_in_castle_in(b, game.where)) game.attrition_list.push(b); } @@ -2754,7 +2758,7 @@ states.siege_attrition = { 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) @@ -2966,11 +2970,11 @@ function goto_field_battle_hits() { function list_field_victims() { let max = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_field_combatant(b) && game.steps[b] > max) max = game.steps[b]; let list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_field_combatant(b) && game.steps[b] === max) list.push(b); return list; @@ -3029,11 +3033,11 @@ function list_siege_victims() { if (game.halfhit && block_owner(game.halfhit) === game.active) return [ game.halfhit ]; let max = 0; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_siege_combatant(b) && game.steps[b] > max) max = game.steps[b]; let list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_siege_combatant(b) && game.steps[b] === max) list.push(b); return list; @@ -3287,7 +3291,7 @@ states.draw_phase = { break; case 'pilgrims': view.prompt = "Draw Phase: Place " + block_name(game.who) + " in a friendly port."; - for (let town in TOWNS) { + for (let town of TOWNLIST) { if (is_friendly_port(town) || can_enter_besieged_port(town)) { gen_action(view, 'town', town); can_place = true; @@ -3300,7 +3304,7 @@ states.draw_phase = { case 'nomads': view.prompt = "Draw Phase: Place " + BLOCKS[game.who].name + " at full strength in " + list_seats(game.who).join(", ") + " or at strength 1 in any friendly town."; - for (let town in TOWNS) { + for (let town of TOWNLIST) { if (town === ENGLAND || town === FRANCE || town === GERMANIA) continue; // FAQ claims besieger controls town for draw purposes @@ -3378,7 +3382,7 @@ function goto_winter_siege_attrition() { game.active = besieged_player(game.where); game.state = 'winter_siege_attrition'; game.attrition_list = []; - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (is_block_in_castle_in(b, game.where)) game.attrition_list.push(b); } @@ -3433,7 +3437,7 @@ function goto_winter_2() { function eliminate_besieging_blocks(owner) { game.summary = []; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === owner) { let where = game.location[b]; if (where === game.winter_campaign) @@ -3450,7 +3454,7 @@ function eliminate_besieging_blocks(owner) { } function need_winter_supply_check() { - for (let town in TOWNS) { + for (let town of TOWNLIST) { if (town === game.winter_campaign) continue; if (is_friendly_town(town) && !is_within_castle_limit(town)) @@ -3482,7 +3486,7 @@ states.winter_supply = { return view.prompt = "Winter Supply: Waiting for " + game.active + "."; gen_action_undo(view); let okay_to_end = true; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active) { if (is_block_on_land(b)) { let where = game.location[b]; @@ -3526,7 +3530,7 @@ states.winter_supply = { function goto_winter_replacements() { game.rp = {}; - for (let town in TOWNS) + for (let town of TOWNLIST) if (is_under_siege(town)) game.rp[town] = 0; else @@ -3550,7 +3554,7 @@ states.winter_replacements = { view.prompt = "Winter Replacements: Distribute replacement points."; gen_action_undo(view); let okay_to_end = true; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === game.active && is_block_on_land(b)) { let where = game.location[b]; let cost = replacement_cost(where); @@ -3615,7 +3619,7 @@ function goto_year_end() { } // Return eliminated blocks to pool. - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === DEAD) game.location[b] = block_pool(b); @@ -3637,7 +3641,7 @@ function setup_game() { reset_blocks(); game.year = 1187; game.turn = 0; - for (let b in BLOCKS) { + for (let b of BLOCKLIST) { if (block_owner(b) === FRANKS) { switch (block_type(b)) { case 'pilgrims': @@ -3698,7 +3702,7 @@ function make_battle_view() { battle.title += " \u2014 Jihad!"; function fill_cell(cell, owner, fn) { - for (let b in BLOCKS) + for (let b of BLOCKLIST) if (game.location[b] === game.where & block_owner(b) === owner && fn(b)) cell.push(b) } @@ -3775,7 +3779,7 @@ exports.resign = function (state, current) { function make_siege_view() { let list = {}; - for (let t in TOWNS) + for (let t of TOWNLIST) if (is_under_siege(t)) list[t] = besieging_player(t); return list; |