summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-07-30 12:30:35 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-17 13:11:26 +0100
commit0d05fec47710c332ab45c1e546cc35743e474348 (patch)
treef1169169094f2bdb9003e67afba682e8f9d2a5e2 /rules.js
parent27e1c173919d3d1506ced0350df576781dec491f (diff)
downloadrommel-in-the-desert-0d05fec47710c332ab45c1e546cc35743e474348.tar.gz
Deploy in supplied hexes only.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js194
1 files changed, 127 insertions, 67 deletions
diff --git a/rules.js b/rules.js
index ee617f3..4a22e36 100644
--- a/rules.js
+++ b/rules.js
@@ -5,12 +5,13 @@
// TODO: RAIDERS
// TODO: MINEFIELDS
+// TODO: legal pass withdrawal moves (reduce supply net, withdraw from fortress attack)
// TODO: group move from queue holding box to base
// TODO: 1942 malta group (reinforce, reduce supply card draw)
-// TODO: legal pass withdrawal moves (reduce supply net, withdraw from fortress attack)
// TODO: log summaries (deploy, rebuild, move, etc)
+// TODO: put initial deployment stack somewhere more accessible (spread out along the top?)
// RULES: for sea redeployment, can bases be "besieged"? (yes)
// RULES: may units redeploying out of battle hex leave disrupted units behind to be routed? (no)
@@ -199,7 +200,7 @@ function to_side_id(a, b) {
return a * 3 + 1
else if (a + hexnext[2] === b)
return a * 3 + 2
- throw new Error("not a hexside " + a + " to " + b);
+ throw new Error("not a hexside " + a + " to " + b)
}
function is_map_hex(x) {
@@ -237,6 +238,9 @@ var supply_allied_invalid = true
var supply_allied_network = new Array(hexcount).fill(0)
var supply_allied_line = new Array(sidecount).fill(0)
+var supply_temp_network = new Array(hexcount).fill(0)
+var supply_temp_line = new Array(sidecount).fill(0)
+
var first_friendly_unit, last_friendly_unit
var first_enemy_unit, last_enemy_unit
@@ -524,6 +528,14 @@ function update_presence() {
presence_allied[unit_hex(u)] |= 2
}
+function count_friendly_units_in_hex(x) {
+ let n = 0
+ for (let u = first_friendly_unit; u <= last_friendly_unit; ++u)
+ if (unit_hex(u) === x)
+ n++
+ return n
+}
+
function has_friendly_unit_in_month(month) {
for (let u = first_friendly_unit; u <= last_friendly_unit; ++u)
if (unit_hex(u) === hexdeploy + month)
@@ -1049,13 +1061,11 @@ function shuffle_cards() {
// === SUPPLY NETWORK ===
-function ind(d, msg, here, ...extra) {
- console.log(new Array(d).fill("-").join("") + msg, here, "("+hex_name[here]+")", extra.join(" "))
-}
-
var supply_defender, supply_defender_sides, supply_friendly, supply_enemy, supply_net, supply_line
var supply_visited = new Array(hexcount).fill(0)
var supply_src = new Array(hexcount).fill(0)
+
+var trace_total
var trace_highway
var trace_chain
@@ -1085,12 +1095,10 @@ function is_supply_line_blocked(here, next, side) {
}
function trace_supply_highway(here, d) {
- trace_highway++
- ind(d, "> highway", here)
+ trace_total++
// TODO: hoist to call sites to avoid function call overhead
if (supply_src[here]) {
- ind(d, "! source highway", here)
return true
}
@@ -1100,6 +1108,10 @@ function trace_supply_highway(here, d) {
for (let s = 0; s < 6; ++s) {
let next = here + hexnext[s]
+
+ if (next < first_hex || next > last_hex || !hex_exists[next])
+ continue
+
if (supply_visited[next])
continue
@@ -1110,15 +1122,12 @@ function trace_supply_highway(here, d) {
let road = side_road[side]
if (road === HIGHWAY) {
if (supply_friendly[next] > 1) {
- ind(d, "? highway head", next)
if (trace_supply_chain(next, d+1, 0, 3)) {
- ind(d, "< highway chain", here, next)
supply_line[side] = 1
has_supply = true
}
} else {
if (trace_supply_highway(next, d+1)) {
- ind(d, "< highway", here, next)
supply_line[side] = 1
has_supply = true
}
@@ -1138,11 +1147,9 @@ function trace_supply_highway(here, d) {
}
function trace_supply_chain(here, d, n, range) {
- ind(d, "> chain", here, n, range)
- trace_chain++
+ trace_total++
if (supply_src[here]) {
- ind(d, "! source chain", here)
return true
}
@@ -1152,6 +1159,10 @@ function trace_supply_chain(here, d, n, range) {
for (let s = 0; s < 6; ++s) {
let next = here + hexnext[s]
+
+ if (next < first_hex || next > last_hex || !hex_exists[next])
+ continue
+
if (supply_visited[next])
continue
@@ -1161,17 +1172,13 @@ function trace_supply_chain(here, d, n, range) {
let road = side_road[side]
if (road === HIGHWAY) {
- ind(d, "? chain highway", next)
if (supply_friendly[next] > 1) {
- ind(d, "? chain highway head", next)
if (trace_supply_chain(next, d+1, 0, 3)) {
- ind(d, "< highway chain", here, next)
supply_line[side] = 1
has_supply = true
}
} else {
if (trace_supply_highway(next, d+1)) {
- ind(d, "< chain highway", here, next)
supply_line[side] = 1
has_supply = true
}
@@ -1180,15 +1187,12 @@ function trace_supply_chain(here, d, n, range) {
let next_range = min(range, SUPPLY_RANGE[road])
if (n + 1 <= next_range) {
if (supply_friendly[next] > 1) {
- ind(d, "? chain head", next)
if (trace_supply_chain(next, d+1, 0, 3)) {
- ind(d, "< highway chain", here, next)
supply_line[side] = 1
has_supply = true
}
} else {
if (trace_supply_chain(next, d+1, n+1, next_range)) {
- ind(d, "< chain trail", here, next_range)
supply_line[side] = 1
has_supply = true
}
@@ -1218,25 +1222,42 @@ function trace_supply_network(start) {
supply_src[start] = 1
supply_net[start] = 1
- console.log("=== SUPPLY NETWORK ===")
- // debug_hexes("FH", supply_friendly)
- // debug_hexes("EH", supply_enemy)
- // debug_hexes("SS1", supply_src)
-
- var trace_total = 0
- for (let x of all_hexes) {
- if (supply_friendly[x] > 0) {
- trace_highway = trace_chain = 0
- ind(0, "START", x)
+ trace_total = 0
+ for (let x of all_hexes)
+ if (supply_friendly[x] > 0)
trace_supply_chain(x, 0, 0, 3)
- console.log("END", trace_highway, trace_chain)
- trace_total += trace_highway + trace_chain
- }
+
+ console.log("SUPPLY VISITS", trace_total)
+ //debug_hexes("SS", supply_src)
+ //debug_hexes("SN", supply_net)
+}
+
+// For repeated supplied hex checks during deployment
+function init_trace_supply_to_base() {
+ if (presence_invalid)
+ update_presence()
+ supply_net = supply_temp_network
+ supply_line = supply_temp_line
+ supply_defender = null
+ supply_defender_sides = null
+ if (is_axis_player()) {
+ supply_friendly = presence_axis
+ supply_enemy = presence_allied
+ } else {
+ supply_friendly = presence_allied
+ supply_enemy = presence_axis
}
- console.log("VISITS", trace_total)
+ supply_net.fill(0)
+}
- debug_hexes("SS", supply_src)
- debug_hexes("SN", supply_net)
+function can_trace_supply_to_base(base, from) {
+ // we've already seen this hex during a previous supplied hex check this go
+ if (supply_net[from] > 0)
+ return true
+ supply_visited.fill(0)
+ supply_src.fill(0)
+ supply_src[base] = 1
+ return trace_supply_chain(from, 0, 0, 3)
}
function update_axis_supply() {
@@ -4537,6 +4558,16 @@ function goto_free_deployment() {
end_free_deployment()
}
+function is_valid_deployment_hex(base, x) {
+ if (can_trace_supply_to_base(base, x))
+ return true
+ if (x === TOBRUK)
+ return count_friendly_units_in_hex(x) < 5
+ if (x === JALO_OASIS || x === JARABUB_OASIS || x === SIWA_OASIS)
+ return count_friendly_units_in_hex(x) < 1
+ return false
+}
+
states.free_deployment = {
inactive: "free deployment",
prompt() {
@@ -4545,7 +4576,8 @@ states.free_deployment = {
let axis = (game.active === AXIS)
let done = true
- view.prompt = axis ? "Axis Free Deployment" : "Allied Free Deployment"
+ view.prompt = `Setup: ${game.active} Deployment.`
+ view.prompt = `Setup: Deploy units in a supplied location in the setup area.`
if (game.selected < 0) {
for_each_friendly_unit_in_hex(deploy, u => {
@@ -4553,15 +4585,26 @@ states.free_deployment = {
done = false
})
} else {
+ trace_total = 0
+
+ let base = friendly_base()
+ init_trace_supply_to_base()
+
for (let x of (axis ? scenario.axis_deployment : scenario.allied_deployment)) {
if (!is_enemy_hex(x)) {
- let limit = scenario.deployment_limit[x] | 0
- if (!limit || count_friendly_units_in_hex(x) < limit)
- gen_action_hex(x)
+ let limit = 0
+ if (scenario.deployment_limit)
+ limit = scenario.deployment_limit[x] | 0
+ if (!limit || count_friendly_units_in_hex(x) < limit) {
+ if (is_valid_deployment_hex(base, x))
+ gen_action_hex(x)
+ }
}
}
gen_action_unit(game.selected)
done = false
+
+ console.log("DEPLOYMENT SUPPLY VISITS", trace_total)
}
if (done)
@@ -4706,57 +4749,74 @@ function current_scenario() {
return SCENARIOS[game.scenario]
}
+function bring_to_front(list, hex) {
+ if (list.includes(hex)) {
+ remove_from_array(list, hex)
+ list.unshift(hex)
+ }
+}
+
+function sort_deployment_for_axis(list) {
+ list = list.slice()
+ list.reverse()
+ bring_to_front(list, BARDIA)
+ bring_to_front(list, TOBRUK)
+ bring_to_front(list, 88)
+ bring_to_front(list, 58) // Mechili
+ bring_to_front(list, 130) // Haraga
+ bring_to_front(list, 113) // Ft Maddalena
+ return list
+}
+
+function sort_deployment_for_allied(list) {
+ list = list.slice()
+ list.reverse()
+ return list
+}
+
const SCENARIOS = {
"1940": {
year: 1940,
start: 1,
end: 6,
- axis_deployment: region_libya_and_sidi_omar,
- allied_deployment: region_egypt,
+ axis_deployment: sort_deployment_for_axis(region_libya_and_sidi_omar),
+ allied_deployment: sort_deployment_for_allied(region_egypt),
axis_initial_supply: 6,
allied_initial_supply: 3,
- deployment_limit: {},
},
"1941": {
year: 1941,
start: 1,
end: 10,
axis_deployment: [],
- allied_deployment: region_egypt_and_libya,
+ allied_deployment: sort_deployment_for_allied(region_egypt_and_libya),
axis_initial_supply: 6,
allied_initial_supply: 6,
- deployment_limit: {},
},
"Crusader": {
year: 1941,
start: 8,
end: 10,
- axis_deployment: region_libya_and_sidi_omar_and_sollum,
- allied_deployment: region_egypt_and_tobruk,
+ axis_deployment: sort_deployment_for_axis(region_libya_and_sidi_omar_and_sollum),
+ allied_deployment: sort_deployment_for_allied(region_egypt_and_tobruk),
axis_initial_supply: 10,
allied_initial_supply: 12,
- deployment_limit: {
- [TOBRUK]: 5,
- },
},
"Battleaxe": {
year: 1941,
start: 4,
end: 10,
- axis_deployment: region_libya_except_tobruk,
- allied_deployment: region_egypt_and_tobruk,
+ axis_deployment: sort_deployment_for_axis(region_libya_except_tobruk),
+ allied_deployment: sort_deployment_for_allied(region_egypt_and_tobruk),
axis_initial_supply: 4,
allied_initial_supply: 8,
- deployment_limit: {
- [TOBRUK]: 5,
- },
},
"1942": {
year: 1942,
start: 11,
end: 20,
axis_deployment: [ EL_AGHEILA, MERSA_BREGA ],
- allied_deployment: region_egypt_and_libya,
+ allied_deployment: sort_deployment_for_allied(region_egypt_and_libya),
axis_initial_supply: 5,
allied_initial_supply: 5,
deployment_limit: {
@@ -4768,11 +4828,10 @@ const SCENARIOS = {
year: 1942,
start: 14,
end: 15,
- axis_deployment: regions["West Line"],
- allied_deployment: regions["East Line"],
+ axis_deployment: sort_deployment_for_axis(regions["West Line"]),
+ allied_deployment: sort_deployment_for_allied(regions["East Line"]),
axis_initial_supply: 10,
allied_initial_supply: 12,
- deployment_limit: {},
special: {
gazala_pre_build: true,
}
@@ -4781,21 +4840,19 @@ const SCENARIOS = {
year: 1942,
start: 15,
end: 20,
- axis_deployment: regions["Libya"],
- allied_deployment: regions["Egypt"],
+ axis_deployment: sort_deployment_for_axis(regions["Libya"]),
+ allied_deployment: sort_deployment_for_allied(regions["Egypt"]),
axis_initial_supply: 8,
allied_initial_supply: 8,
- deployment_limit: {},
},
"1941-42": {
year: 1941,
start: 1,
end: 20,
axis_deployment: [],
- allied_deployment: region_egypt_and_libya,
+ allied_deployment: sort_deployment_for_allied(region_egypt_and_libya),
axis_initial_supply: 6,
allied_initial_supply: 6,
- deployment_limit: {},
},
}
@@ -5132,6 +5189,7 @@ exports.setup = function (seed, scenario, options) {
revealed: [],
moved: [],
fired: [],
+ raiders: [],
recover: [],
axis_minefields: [],
@@ -5204,7 +5262,6 @@ exports.view = function(state, current) {
allied_hexes: game.allied_hexes,
axis_sides: game.axis_sides,
allied_sides: game.allied_sides,
- selected: game.selected,
}
if (current === AXIS)
@@ -5212,6 +5269,9 @@ exports.view = function(state, current) {
if (current === ALLIED)
view.cards = game.allied_hand
+ if (current === game.active)
+ view.selected = game.selected
+
if (game.from1) view.from1 = game.from1
if (game.from2) view.from2 = game.from2
if (game.to1) view.to1 = game.to1