diff options
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 194 |
1 files changed, 127 insertions, 67 deletions
@@ -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 |