summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rules.js120
1 files changed, 62 insertions, 58 deletions
diff --git a/rules.js b/rules.js
index 7da97d7..494c418 100644
--- a/rules.js
+++ b/rules.js
@@ -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;