diff options
-rw-r--r-- | rules.js | 241 |
1 files changed, 4 insertions, 237 deletions
@@ -16,6 +16,8 @@ // TODO: for_each_exit -> flat list of all exits // TODO: retreats with no survivors +// TODO: johnson and mohawks if subcommander! +// TODO: select leader for defense instead of automatically picking // TODO: flat force definition - use sum of leader command rating // (only allow dropping subordinate if stacking limit allows) @@ -1883,7 +1885,7 @@ function update_vp(name, s) { game[name] = v; } -// PATH FINDING +// SUPPLY LINES function search_supply_spaces_imp(queue) { console.log("======"); @@ -1964,242 +1966,7 @@ function is_in_supply(space) { return x; } -function list_intercept_spaces(is_lone_ld, is_lone_ax) { - let intercept = {}; - - // 6.723 Leaders moving alone can NOT be intercepted - if (is_lone_ld) - return intercept; - - console.log("INTERCEPT SEARCH is_lone_ax", is_lone_ax, "is_lone_ld", is_lone_ld); - - for (let from = first_space; from <= last_space; ++from) { - if (has_unbesieged_enemy_units(from)) { - console.log("INTERCEPT FROM", space_name(from)); - - // 6.721 exception -- can always intercept units infiltrating same space - // TODO: infiltration - // intercept[from] = 3; - - for_each_exit(from, to => { - // 6.722 - if (has_unbesieged_friendly_units(to)) - return; - if (has_unbesieged_friendly_fortifications(to)) - return; - - // 6.721 - if (is_lone_ax && is_wilderness_or_mountain(to)) { - if (has_unbesieged_enemy_auxiliary(from)) { - console.log("INTERCEPT TO", space_name(to), "(lone ax)"); - intercept[to] = 2; - } - } else { - console.log("INTERCEPT TO", space_name(to)); - intercept[to] = 1; - } - }); - } - } - - return intercept; -} - -// Use Breadth First Search to find all paths. - -function pq_push(queue, item, prio) { - // TODO: reprioritize if item is already in the queue - for (let i = 0, n = queue.length; i < n; ++i) - if (queue[i].prio > prio) - return queue.splice(i, 0, [prio, item]); - queue.push([prio, item]) -} - -function pq_pop(queue) { - return queue.shift()[1]; -} - -function search_boat_move(who, start_space, start_cost, max_cost) { - let move_cost = game.move.cost = {}; - let move_path = game.move.path = {}; - - if (start_cost >= max_cost) - return; - - let queue = []; - pq_push(queue, start_space, 0); - move_cost[start_space] = start_cost; - move_path[start_space] = null; - - const is_lone_ld = is_lone_leader(who); - const is_lone_ax = is_lone_auxiliary(who); - const has_dt = force_has_drilled_troops(who); - - while (queue.length > 0) { - let current = pq_pop(queue); - let c_cost = move_cost[current]; - let c_ff = has_friendly_fortifications(current) || is_originally_friendly(current); - for_each_exit(current, (next, connection) => { - let n_ff = has_friendly_fortifications(next) || is_originally_friendly(next); - let n_cost = c_cost + 2; - let must_stop = false; - - // TODO: check actual MP required to reach safe space - let may_infiltrate = is_lone_ax && n_cost < max_cost; - - if (connection === 'land') { - if (c_ff && n_ff && (c_cost & 1) === 0) { - n_cost += 1; - } else { - return; // Not a usable land connection - } - } - - // Must stop on entering interception space - if (next in game.move.intercept) - must_stop = true; - - // Must stop on entering enemy occupied spaces - if (has_unbesieged_enemy_units(next)) { - if (is_lone_ld) - return; // Lone leaders can never enter an enemy occupied space - if (may_infiltrate) - game.move.infiltrate[next] = 1; - must_stop = true; // May continue if over-run - } - - if (has_enemy_stockade(next)) { - if (may_infiltrate) - game.move.infiltrate[next] = 1; - else - n_cost = 18; // may not continue - } - - if (has_unbesieged_enemy_fort_or_fortress(next)) { - if (may_infiltrate) { - game.move.infiltrate[next] = 1; - } else { - if (!has_dt) - return; // Must have Drilled Troops to enter an enemy fort or fortress space. - n_cost = 18; // may not continue - } - } - - // Stop when entering a space with a lone enemy leader(s) to force a retreat - if (!is_lone_ld && has_unbesieged_enemy_leader(next)) - must_stop = true; // May continue after retreat - - // No movement points left. - if (n_cost >= max_cost) - must_stop = true; - - console.log("SEARCH BOAT MOVE", space_name(current), ">", space_name(next), c_cost, n_cost, c_ff, n_ff); - - if (!(next in move_cost) || (n_cost < move_cost[next])) { - move_cost[next] = n_cost; - move_path[next] = current; - if (!must_stop) - pq_push(queue, next, n_cost); - } - - }); - } -} - -function search_land_move(who, start_space, start_cost, max_cost) { - let move_cost = game.move.cost = {}; - let move_path = game.move.path = {}; - - if (start_cost >= max_cost) - return; - - let queue = []; - pq_push(queue, start_space, 0); - move_cost[start_space] = start_cost; - move_path[start_space] = null; - - const is_lone_ld = is_lone_leader(who); - const is_lone_ax = is_lone_auxiliary(who); - const has_dt = force_has_drilled_troops(who); - const has_ax = force_has_auxiliary_unit(who); - - while (queue.length > 0) { - let current = pq_pop(queue); - let c_cost = move_cost[current]; - let c_ff = has_friendly_fortifications(current); - for_each_exit(current, (next, connection) => { - let n_ff = has_friendly_fortifications(next); - let n_cost = c_cost + 1; - let must_stop = false; - - // TODO: check actual MP required to reach safe space - let may_infiltrate = is_lone_ax && n_cost < max_cost; - - // Must stop on mountains. - if (is_mountain(next) && !n_ff) - n_cost = 9; // may not continue - - // Must stop in the next space after passing through... - if (current !== game.move.start_space && !c_ff) { - // Drilled Troops that pass through wilderness must stop in the next space. - if (has_dt && !has_ax && is_wilderness(current)) - if (!game.events.george_croghan) - n_cost = 9; // may not continue - - // Auxiliaries that pass through enemy cultivated must stop in the next space. - if (has_ax && !has_dt && is_originally_enemy(current)) - n_cost = 9; // may not continue - } - - // Must stop on entering interception space - if (next in game.move.intercept) - must_stop = true; - - // Must stop on entering enemy occupied spaces - if (has_unbesieged_enemy_units(next)) { - if (is_lone_ld) - return; // Lone leaders can never enter an enemy occupied space - if (may_infiltrate) - game.move.infiltrate[next] = 1; - must_stop = true; // May continue if over-run - } - - if (has_enemy_stockade(next)) { - if (may_infiltrate) - game.move.infiltrate[next] = 1; - else - n_cost = 9; // may not continue - } - - if (has_unbesieged_enemy_fort_or_fortress(next)) { - if (may_infiltrate) { - game.move.infiltrate[next] = 1; - } else { - if (!has_dt) - return; // Must have Drilled Troops to enter an enemy fort or fortress space. - n_cost = 9; // may not continue - } - } - - // Stop when entering a space with a lone enemy leader(s) to force a retreat - if (!is_lone_ld && has_unbesieged_enemy_leader(next)) - must_stop = true; // May continue after retreat - - // No movement points left. - if (n_cost >= max_cost) - must_stop = true; - - console.log("SEARCH LAND MOVE", space_name(current), ">", space_name(next), c_cost, n_cost, must_stop, game.move.infiltrate[next]); - - if (!(next in move_cost) || (n_cost < move_cost[next])) { - move_cost[next] = n_cost; - move_path[next] = current; - if (!must_stop) - pq_push(queue, next, n_cost); - } - }); - } -} +// CLOSEST PATH SEARCH function find_closest_friendly_unbesieged_fortification(start) { let queue = []; |