summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-08-29 00:29:59 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-17 13:11:26 +0100
commit11b2796d2ce2e3067b6507997df6ba61119a78a3 (patch)
tree54f04a1abf99b271b65b48b22b74de6b13738133 /rules.js
parent4fd0773f7612459ede2f9a3f2935b4334d591ab9 (diff)
downloadrommel-in-the-desert-11b2796d2ce2e3067b6507997df6ba61119a78a3.tar.gz
Pass withdrawal permutations.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js164
1 files changed, 146 insertions, 18 deletions
diff --git a/rules.js b/rules.js
index 090918d..007264d 100644
--- a/rules.js
+++ b/rules.js
@@ -828,7 +828,7 @@ function fortress_src(fortress) {
}
function is_fortress_allied_controlled(fortress) {
- return (game.fortress & fortress_bit(fortress)) === 1
+ return (game.fortress & fortress_bit(fortress)) !== 0
}
function is_fortress_axis_controlled(fortress) {
@@ -1605,6 +1605,15 @@ function query_friendly_supply_network_from_to(src, x, y) {
return supply_temp_network
}
+function query_friendly_supply_network(src) {
+ if (is_axis_player())
+ init_trace_supply(supply_temp_network, supply_temp_line, AXIS)
+ else
+ init_trace_supply(supply_temp_network, supply_temp_line, ALLIED)
+ trace_supply_network(src)
+ return supply_temp_network
+}
+
// === PATHING ===
const path_from = [ new Array(hexcount), new Array(hexcount), new Array(hexcount), null, new Array(hexcount) ]
@@ -2074,25 +2083,138 @@ function is_valid_withdrawal_regroup_move_from(x) {
return 0
}
+function is_valid_withdrawal_regroup_permutation(src) {
+ let net = src_supply_network(src)
+ let new_net = query_friendly_supply_network(src)
+ return is_network_reduced(net, new_net)
+}
+
function list_valid_withdrawal_regroup_command_points() {
let always = []
- let maybe = []
+ let test = []
+ let maybe = null
for (let x of all_hexes) {
let status = is_valid_withdrawal_regroup_move_from(x)
if (status === 2)
always.push(x)
else if (status === 1)
- maybe.push(x)
+ test.push(x)
}
- console.log("WITHDRAW REGROUP CANDIDATES", always, maybe)
- // TODO: list valid permutations of 'maybe' hexes
+ console.log("WITHDRAW REGROUP CANDIDATES", always, test)
+ if (is_axis_player())
+ maybe = list_withdrawal_permutations(EL_AGHEILA, test)
+ else
+ maybe = list_withdrawal_permutations(ALEXANDRIA, test)
+ // TODO: fortress supply
return { always, maybe, to: null, evacuate: null }
}
+function count_bits(v) {
+ let c = 0
+ for (; v; ++c)
+ v &= v - 1
+ return c
+}
+
+function list_withdrawal_permutations(src, maybe) {
+ let rommel1 = (game.rommel === 1) ? 1 : 0
+ let result = {}
+ let hexes
+
+ // impossible...
+ if (maybe.length < 2)
+ return
+
+ console.log("LIST WITHDRAWAL REGROUPS", maybe)
+
+ // List all possible command points with more than one 'maybe' hex
+ let cmd_maybe = {}
+ let cmd_points = {}
+ for (let here of all_hexes) {
+ if (!is_enemy_hex(here)) {
+ hexes = null
+ for_each_hex_and_adjacent_hex(here, x => {
+ if (set_has(maybe, x) && hex_supply_source(x) === src) {
+ if (!hexes)
+ hexes = []
+ set_add(hexes, x)
+ }
+ })
+ if (hexes && hexes.length > 1) {
+ let key = hexes.join(",")
+ cmd_maybe[key] = hexes
+ if (!(key in cmd_points))
+ cmd_points[key] = []
+ cmd_points[key].push(here)
+ }
+ }
+ }
+
+ // For each unique set of "maybe" command points,
+ // find all permutations of removing more than one "maybe" hex.
+ if (presence_invalid)
+ update_presence()
+ let presence_friendly = is_axis_player() ? presence_axis : presence_allied
+
+ for (let key in cmd_maybe) {
+ hexes = cmd_maybe[key]
+ let n = hexes.length
+ let n2 = 1 << n
+ path_valid.fill(1)
+ for (let bits = 3; bits < n2; ++bits) {
+ if (count_bits(bits) >= 2) {
+ // Evacuate presence for testing
+ for (let i = 0; i < n; ++i)
+ if (bits & (1 << i))
+ presence_friendly[hexes[i]] &= 1 // clear 'undisrupted'
+
+ // Find the hexes that all units in the evacuated hexes can reach
+ for (let i = 0; i < n; ++i) {
+ if (bits & (1 << i)) {
+ let from = hexes[i]
+ let who = slowest_undisrupted_friendly_unit(from)
+ let speed = unit_speed[who]
+ search_withdraw(who, 1 + rommel1)
+ for (let to = 0; to < hexcount; ++to)
+ if (!can_move_to(to, speed + 1 + rommel1))
+ path_valid[to] = 0
+ }
+ }
+
+ // Test supply net for all possible destinations
+ for (let x of all_hexes) {
+ if (path_valid[x]) {
+ let save_x = presence_friendly[x]
+ presence_friendly[x] = 2
+ if (is_valid_withdrawal_regroup_permutation(src)) {
+ for (let here of cmd_points[key]) {
+ if (!(here in result))
+ result[here] = []
+ set_add(result[here], x)
+ }
+ }
+ presence_friendly[x] = save_x
+ }
+ }
+
+ // Restore presence
+ for (let i = 0; i < n; ++i)
+ if (bits & (1 << i))
+ presence_friendly[hexes[i]] |= 2 // set 'undisrupted'
+ }
+ }
+ }
+
+ console.log("MAYBE", result)
+ return result
+}
+
function gen_withdrawal_regroup_command_point() {
var m, n
for (let here of all_hexes) {
- if (!is_enemy_hex(here)) {
+ if (here in game.withdraw.maybe)
+ gen_action_hex(here)
+ else if (!is_enemy_hex(here)) {
m = n = 0
for_each_hex_and_adjacent_hex(here, x => {
// Must include at least one valid withdrawal hex to evacuate fully
@@ -2112,9 +2234,6 @@ function gen_withdrawal_regroup_command_point() {
function list_valid_withdrawal_regroup_destinations() {
let rommel1 = (game.rommel === 1) ? 1 : 0
- // TODO: list hexes that can be reached by ALL units of one valid permutation of maybe-hexes
- // remember
-
// Find hexes that can be reached by ALL units of ONE always-hex
// ... that also reduces the network (either by full retreat, or checking move)
let result = []
@@ -2134,7 +2253,7 @@ function list_valid_withdrawal_regroup_destinations() {
let who = slowest_undisrupted_friendly_unit(from)
let speed = unit_speed[who]
let src = unit_supply_source(who)
- let net = unit_supply_network(who) // TODO: remembered network
+ let net = unit_supply_network(who)
search_withdraw(who, 1 + rommel1)
for (let to of all_hexes) {
if (to != from && can_move_to(to, speed + 1 + rommel1)) {
@@ -2146,13 +2265,16 @@ function list_valid_withdrawal_regroup_destinations() {
}
})
+ // List hexes that can be reached by ALL units of one valid permutation of maybe-hexes.
+ if (game.from1 in game.withdraw.maybe) {
+ for (let to of game.withdraw.maybe[game.from1])
+ set_add(result, to)
+ }
+
game.withdraw.to = result
}
function gen_withdrawal_regroup_destination() {
- // XXX
- list_valid_withdrawal_regroup_destinations()
- // XXX
for (let x of game.withdraw.to)
gen_action_hex(x)
}
@@ -2505,6 +2627,7 @@ const xxx_fortress_supply = {
unit(who) {
let ix = game.assign
let ss = FORTRESS_SRC_LIST[ix]
+ let fortress = FORTRESS_HEX_LIST[ix]
push_undo()
game.capacity[ix]--
log(`Assigned #${fortress} supply.`)
@@ -2556,7 +2679,7 @@ function assign_oasis_supply() {
if (n === 1) {
for_each_friendly_unit_in_hex(oasis, u => {
game.oasis[ix] = 0
- log(`Assigned #${fortress} supply.`)
+ log(`Assigned #${oasis} supply.`)
set_unit_supply(u, SS_OASIS)
})
}
@@ -2577,9 +2700,10 @@ const xxx_oasis_supply = {
},
unit(who) {
let ix = game.assign
+ let oasis = OASIS_HEX_LIST[ix]
push_undo()
game.oasis[ix] = 0
- log(`Assigned #${fortress} supply.`)
+ log(`Assigned #${oasis} supply.`)
set_unit_supply(who, SS_OASIS)
game.assign++
resume_oasis_supply()
@@ -2768,7 +2892,9 @@ function push_move_summary(from, to, via, forced) {
}
function flush_move_summary() {
- if (!game.from2 && !game.to1) {
+ if (!game.from1 && !game.from2) {
+ log(`Passed.`)
+ } else if (!game.from2 && !game.to1) {
log(`Moved from #${game.from1}`)
} else if (!game.from2 && game.to1) {
log(`Moved to #${game.to1}`)
@@ -4427,7 +4553,7 @@ 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.minefields[MF_VISIBLE])) {
+ if (set_has(game.minefields[MF_VISIBLE], game.battle)) {
// DD advantage is lost if the defender initiated combat
if (is_axis_player())
return set_has(game.allied_hexes, game.battle)
@@ -5283,7 +5409,7 @@ function goto_buildup_point_determination() {
log(`Allied rolled ${allied_a} + ${allied_b}.`)
}
- log(`Receive ${axis + allied} BPs.`)
+ log(`Received ${axis + allied} BPs.`)
game.axis_bps += axis + allied
game.allied_bps += axis + allied
@@ -5614,6 +5740,8 @@ states.spending_bps = {
pay_bps(n - 20)
}
+ log(`Saved ${available_bps()} BPs.`)
+
end_buildup_spending()
}
}