summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rules.js198
1 files changed, 109 insertions, 89 deletions
diff --git a/rules.js b/rules.js
index c3e7fb5..48d5a62 100644
--- a/rules.js
+++ b/rules.js
@@ -1111,6 +1111,8 @@ function print_path(who, from, to, road) {
// retreat move: must leave battle hex via friendly side. may ignore disrupted enemy. may move freely.
// retreat withdrawal: must leave battle hex via friendly side. may ignore disrupted enemy. must follow supply lines.
+// TODO: cache search results from previous invocation
+
function search_move(start, speed) {
// Normal moves.
search_init()
@@ -1893,32 +1895,26 @@ function gen_move(search_fn) {
search_fn(from, max(speed + rommel1, speed + rommel2))
- if (!game.to1 && game.from1) {
- if (from === game.from1) {
- for (let to of all_hexes)
- if (to != from && can_move_to(to, speed + rommel1))
- gen_action_hex(to)
- }
+ if (!game.to1 && game.from1 === from) {
+ for (let to of all_hexes)
+ if (to != from && can_move_to(to, speed + rommel1))
+ gen_action_hex(to)
}
- if (!game.to2 && game.from2) {
- if (from === game.from2) {
- for (let to of all_hexes)
- if (to != from && can_move_to(to, speed + rommel2))
- gen_action_hex(to)
- }
+ if (!game.to2 && game.from2 === from) {
+ for (let to of all_hexes)
+ if (to != from && can_move_to(to, speed + rommel2))
+ gen_action_hex(to)
}
- if (game.to1) {
- if (is_hex_or_adjacent_to(from, game.from1))
- if (can_move_to(game.to1, speed + rommel1))
- gen_action_hex(game.to1)
+ if (game.to1 && is_hex_or_adjacent_to(from, game.from1)) {
+ if (can_move_to(game.to1, speed + rommel1))
+ gen_action_hex(game.to1)
}
- if (game.to2) {
- if (is_hex_or_adjacent_to(from, game.from2))
- if (can_move_to(game.to2, speed + rommel2))
- gen_action_hex(game.to2)
+ if (game.to2 && is_hex_or_adjacent_to(from, game.from2)) {
+ if (can_move_to(game.to2, speed + rommel2))
+ gen_action_hex(game.to2)
}
}
@@ -1994,93 +1990,110 @@ function friendly_unit_supply_distance(who) {
return is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA]
}
-function can_unit_disengage_and_withdraw(who) {
- let sline = friendly_unit_supply_line(who)
- let sdist = friendly_unit_supply_distance(who)
- let from = unit_hex(who)
+function is_valid_retreat_hex(from) {
+ if (game.turn_option === 'pass')
+ return can_all_retreat(from)
+ else
+ return can_any_retreat(from)
+}
+
+function can_any_retreat(from) {
let result = false
- for_each_adjacent_hex(from, to => {
- let side = to_side_id(from, to)
- if (is_friendly_hexside(side) && !has_enemy_unit(to))
- if (sline[side] && sdist[to] <= sdist[from])
+ for_each_undisrupted_friendly_unit_in_hex(from, u => {
+ if (result === false) {
+ if (can_unit_retreat(u))
result = true
+ }
})
return result
}
-function can_all_disengage_and_withdraw(from) {
+function can_all_retreat(from) {
let result = true
for_each_undisrupted_friendly_unit_in_hex(from, u => {
- if (result && !can_unit_disengage_and_withdraw(u))
+ if (result === true && !can_unit_retreat(u))
result = false
})
return result
}
-function can_disengage_and_move(from) {
- let result = false
- for_each_adjacent_hex(from, to => {
- let side = to_side_id(from, to)
- if (is_friendly_hexside(side) && !has_enemy_unit(to))
- result = true
- })
- return result
+function can_unit_retreat(who) {
+ let from = unit_hex(who)
+ if (!game.to1 && game.from1 === from)
+ return can_unit_retreat_group_move(from)
+ if (!game.to2 && game.from2 === from)
+ return can_unit_retreat_group_move(from)
+ if (game.to1 && is_hex_or_adjacent_to(from, game.from1))
+ if (can_unit_retreat_regroup_move(u, game.to1, rommel1))
+ return true
+ if (game.to2 && is_hex_or_adjacent_to(from, game.from2))
+ if (can_unit_retreat_regroup_move(u, game.to2, rommel2))
+ return true
+ return false
}
-function can_retreat_with_group_move(from) {
- if (!is_battle_hex(from) || set_has(game.partial_retreats, from))
- return false
+function can_unit_retreat_group_move(who) {
+ if (game.turn_option === 'pass')
+ return can_unit_disengage_and_withdraw(who)
+ else
+ return can_unit_disengage_and_move(who)
+}
+function can_unit_retreat_regroup_move(who, to, rommel) {
if (game.turn_option === 'pass')
- return can_all_disengage_and_withdraw(from)
+ return can_unit_disengage_and_withdraw_to(who, to, rommel)
else
- return can_disengage_and_move(from)
+ return can_unit_disengage_and_move_to(who, to, rommel)
}
-function can_all_disengage_and_move_to(from) {
- let result = true
- for_each_undisrupted_friendly_unit_in_hex(from, u => {
- if (result && !can_unit_disengage_and_withdraw(u))
- result = false
+function can_unit_disengage_and_withdraw(who) {
+ let sline = friendly_unit_supply_line(who)
+ let sdist = friendly_unit_supply_distance(who)
+ let from = unit_hex(who)
+ let result = false
+ for_each_adjacent_hex(from, to => {
+ let side = to_side_id(from, to)
+ if (is_friendly_hexside(side) && !has_enemy_unit(to))
+ if (sline[side] && sdist[to] <= sdist[from])
+ result = true
})
return result
}
-function can_retreat_with_regroup_move(from, to, rommel) {
- if (!is_battle_hex(from) || set_has(game.partial_retreats, from))
- return false
+function can_unit_disengage_and_move(who) {
+ let from = unit_hex(who)
+ let result = false
+ for_each_adjacent_hex(from, to => {
+ let side = to_side_id(from, to)
+ if (is_friendly_hexside(side) && !has_enemy_unit(to))
+ result = true
+ })
+ return result
+}
- let speed = max_speed_of_undisrupted_and_unmoved_friendly_unit_in_hex(from)
- if (game.turn_option === 'pass')
- search_withdraw_retreat(from, speed + rommel)
- else
- search_move_retreat(from, speed + rommel)
+function can_unit_disengage_and_withdraw_to(who, to, rommel) {
+ search_withdraw_retreat(unit_hex(who), unit_speed(who) + rommel)
+ return can_move_to(to, unit_speed(who) + rommel)
+}
- if (game.turn_option === 'pass')
- return can_all_disengage_and_move_to(from, to, rommel)
- else
- return can_any_disengage_and_move_to(from, to, rommel)
+function can_unit_disengage_and_move_to(who, to, rommel) {
+ search_move_retreat(unit_hex(who), unit_speed(who) + rommel)
+ return can_move_to(to, unit_speed(who) + rommel)
}
function can_select_retreat_hex() {
- update_supply_networks()
- let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line
- let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA]
- let rommel1 = (game.rommel === 1) ? 1 : 0
- let rommel2 = (game.rommel === 2) ? 1 : 0
-
if (!game.to1 && game.from1)
- if (can_retreat_with_group_move(game.from1)
+ if (is_valid_retreat_hex(game.from1))
return true
if (!game.to2 && game.from2)
- if (can_retreat_with_group_move(game.from2)
+ if (is_valid_retreat_hex(game.from2))
return true
if (game.to1) {
let result = false
for_each_hex_and_adjacent_hex(game.from1, x => {
- if (can_retreat_with_regroup_move(x, game.to1, rommel1))
+ if (result === false && is_valid_retreat_hex(x))
result = true
})
if (result)
@@ -2090,7 +2103,7 @@ function can_select_retreat_hex() {
if (game.to2) {
let result = false
for_each_hex_and_adjacent_hex(game.from2, x => {
- if (can_retreat_with_regroup_move(x, game.to2, rommel2))
+ if (result === false && is_valid_retreat_hex(x))
result = true
})
if (result)
@@ -2104,32 +2117,26 @@ states.retreat_from = {
prompt() {
view.prompt = `Retreat: Select hex to retreat from.`
- update_supply_networks()
- let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line
- let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA]
- let rommel1 = (game.rommel === 1) ? 1 : 0
- let rommel2 = (game.rommel === 2) ? 1 : 0
-
if (!game.to1 && game.from1) {
- if (can_retreat_with_group_move(game.from1, sline, sdist))
+ if (is_valid_retreat_hex(game.from1))
gen_action_hex(game.from1)
}
if (!game.to2 && game.from2) {
- if (can_retreat_with_group_move(game.from2, sline, sdist))
+ if (is_valid_retreat_hex(game.from2))
gen_action_hex(game.from2)
}
if (game.to1) {
for_each_hex_and_adjacent_hex(game.from1, x => {
- if (can_retreat_with_regroup_move(x, game.to1, rommel1))
+ if (is_valid_retreat_hex(x))
gen_action_hex(x)
})
}
if (game.to2) {
for_each_hex_and_adjacent_hex(game.from2, x => {
- if (can_retreat_with_regroup_move(x, game.to2, rommel2))
+ if (is_valid_retreat_hex(x))
gen_action_hex(x)
})
}
@@ -2156,10 +2163,10 @@ states.retreat_who = {
for_each_undisrupted_friendly_unit_in_hex(game.retreat, u => {
if (!set_has(game.retreat_units, u))
full_retreat = false
- // TODO: has available retreat path XXX
- // TODO: can reach regroup destination?
- gen_action_unit(u)
+ if (can_unit_retreat(u))
+ gen_action_unit(u)
})
+
if (full_retreat) {
view.actions.retreat = 1
} else {
@@ -2176,9 +2183,9 @@ states.retreat_who = {
},
select_all() {
for_each_undisrupted_friendly_unit_in_hex(game.retreat, u => {
- // TODO: has available retreat path XXX
- // TODO: can reach regroup destination?
- set_add(game.retreat_units, u)
+ if (!set_has(game.retreat_units, u))
+ if (can_unit_retreat(u))
+ set_add(game.retreat_units, u)
})
},
retreat() {
@@ -2323,12 +2330,25 @@ function goto_refuse_battle() {
}
}
+function can_all_refuse_battle(from) {
+ let result = true
+ for_each_undisrupted_friendly_unit_in_hex(from, u => {
+ if (result === true && !can_unit_refuse_battle(u))
+ result = false
+ })
+ return result
+}
+
+function can_unit_refuse_battle(who) {
+ return can_unit_disengage_and_withdraw(who)
+}
+
states.refuse_battle = {
inactive: "refuse battle",
prompt() {
view.prompt = `You may Refuse Battle.`
for (let x of game.active_battles)
- if (can_all_disengage_and_withdraw(x))
+ if (can_all_refuse_battle(x))
gen_action_hex(x)
gen_action('next')
},
@@ -2653,9 +2673,9 @@ function is_fortress_defensive_fire() {
function is_minefield_offensive_fire() {
if ((game.state === 'battle_fire' && is_active_player()) || (game.state === 'probe_fire' && is_passive_player())) {
- if (set_has(game.revealed_minefields) {
+ if (set_has(game.revealed_minefields)) {
// DD advantage is lost if the defender initiated combat
- if (is_axis_player()
+ if (is_axis_player())
return set_has(game.allied_hexes, game.battle)
else
return set_has(game.axis_hexes, game.battle)