From f3e39d636cb1281e1fbc55abae28b1f2317b743a Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 25 Jul 2022 11:38:55 +0200 Subject: regroup move forward search --- rules.js | 227 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 120 insertions(+), 107 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index 0726a42..312faaa 100644 --- a/rules.js +++ b/rules.js @@ -605,6 +605,14 @@ function for_each_undisrupted_friendly_unit_in_hex(x, fn) { fn(u) } +function for_each_undisrupted_and_unmoved_friendly_unit_in_hex(x, fn) { + // TODO: first/last_enemy_unit + for (let u = 0; u < units.length; ++u) + if (is_friendly_unit(u) && !is_unit_disrupted(u) && unit_hex(u) === x && !is_unit_moved(u)) + fn(u) +} + + function for_each_undisrupted_friendly_unit_in_hex_or_adjacent(x, fn) { // TODO: first/last_enemy_unit for (let u = 0; u < units.length; ++u) @@ -1172,9 +1180,9 @@ function adjacent_hex_has_undisrupted_friendly_unit(here) { return false } -function max_speed_of_undisrupted_friendly_unit_in_hex(from) { +function max_speed_of_undisrupted_and_unmoved_friendly_unit_in_hex(from) { let max_speed = 0 - for_each_undisrupted_friendly_unit_in_hex(from, u => { + for_each_undisrupted_and_unmoved_friendly_unit_in_hex(from, u => { let s = unit_speed(u) if (s > max_speed) max_speed = s @@ -1184,7 +1192,7 @@ function max_speed_of_undisrupted_friendly_unit_in_hex(from) { function find_valid_regroup_destinations(from, rommel) { // TODO: forced march - let speed = max_speed_of_undisrupted_friendly_unit_in_hex(from) + let speed = max_speed_of_undisrupted_and_unmoved_friendly_unit_in_hex(from) if (speed > 0) { search_move(from, speed + rommel) for (let x of all_hexes) @@ -1490,9 +1498,117 @@ function goto_move() { log(`Group move from #${game.from2}.`) } log_br() - game.state = 'move_who' + game.state = 'move' } +states.move = { + inactive: "move", + prompt() { + view.prompt = `Move: Select unit to move.` + + let rommel1 = (game.rommel === 1) ? 1 : 0 + let rommel2 = (game.rommel === 2) ? 1 : 0 + + if (game.selected < 0) { + + // Select Group Move 1 + if (!game.to1 && game.from1) { + if (!is_battle_hex(game.from1)) { + for_each_undisrupted_and_unmoved_friendly_unit_in_hex(game.from1, u => { + gen_action_unit(u) + }) + } + } + + // Select Group Move 2 + if (!game.to2 && game.from2) { + if (!is_battle_hex(game.from2)) { + for_each_undisrupted_and_unmoved_friendly_unit_in_hex(game.from2, u => { + gen_action_unit(u) + }) + } + } + + // Select Regroup Move 1 + if (game.to1) { + for_each_hex_and_adjacent_hex(game.from1, from => { + let speed = max_speed_of_undisrupted_and_unmoved_friendly_unit_in_hex(from) + if (speed > 0 && !has_enemy_unit(from)) { + search_move(from, speed + rommel1) + for_each_undisrupted_and_unmoved_friendly_unit_in_hex(from, u => { + if (can_move_to(game.to1, unit_speed(u) + rommel1)) + gen_action_unit(u) + }) + } + }) + } + + // Select Regroup Move 2 + if (game.to1) { + for_each_hex_and_adjacent_hex(game.from2, from => { + let speed = max_speed_of_undisrupted_and_unmoved_friendly_unit_in_hex(from) + if (speed > 0 && !has_enemy_unit(from)) { + search_move(from, speed + rommel2) + for_each_undisrupted_and_unmoved_friendly_unit_in_hex(from, u => { + if (can_move_to(game.to2, unit_speed(u) + rommel2)) + gen_action_unit(u) + }) + } + }) + } + + // Retreat + let has_retreat_hex = false + if (!game.to1 && game.from1 && is_battle_hex(game.from1) && !set_has(game.partial_retreats, game.from1)) + has_retreat_hex = true + if (!game.to2 && game.from2 && is_battle_hex(game.from2) && !set_has(game.partial_retreats, game.from2)) + has_retreat_hex = true + if (game.to1 && !has_enemy_unit(game.to1)) { + for_each_hex_and_adjacent_hex(game.from1, x => { + if (has_undisrupted_friendly_unit(x) && is_battle_hex(x) && !set_has(game.partial_retreats, x)) + has_retreat_hex = true + }) + } + if (game.to2 && !has_enemy_unit(game.to2)) { + for_each_hex_and_adjacent_hex(game.from2, x => { + if (has_undisrupted_friendly_unit(x) && is_battle_hex(x) && !set_has(game.partial_retreats, x)) + has_retreat_hex = true + }) + } + if (has_retreat_hex) + gen_action('retreat') + + gen_action('end_move') + } else { + + // Deselect + gen_action_unit(game.selected) + + // Move + if (game.turn_option === 'pass') + gen_move(search_withdraw) + else + gen_move(search_move) + + } + }, + unit(who) { + apply_select(who) + }, + hex(to) { + apply_move(to) + }, + retreat() { + push_undo() + log_br() + game.state = 'retreat_from' + }, + end_move() { + clear_undo() + log_br() + end_move_phase() + } +} function gen_move(search_fn) { let rommel1 = (game.rommel === 1) ? 1 : 0 @@ -1602,109 +1718,6 @@ function move_unit(who, to, speed) { } } -states.move_who = { - inactive: "move", - prompt() { - view.prompt = `Move: Select unit to move.` - - let rommel1 = (game.rommel === 1) ? 1 : 0 - let rommel2 = (game.rommel === 2) ? 1 : 0 - - if (game.selected < 0) { - - // Select Group Move 1 - if (!game.to1 && game.from1) { - if (!is_battle_hex(game.from1)) { - for_each_undisrupted_friendly_unit_in_hex(game.from1, u => { - if (!is_unit_moved(u)) - gen_action_unit(u) - }) - } - } - - // Select Group Move 2 - if (!game.to2 && game.from2) { - if (!is_battle_hex(game.from2)) { - for_each_undisrupted_friendly_unit_in_hex(game.from2, u => { - if (!is_unit_moved(u)) - gen_action_unit(u) - }) - } - } - - // Select Regroup Move 1 - if (game.to1) { - search_move(game.to1, 4 + rommel1) - for_each_undisrupted_friendly_unit_in_hex_or_adjacent(game.from1, u => { - if (!is_unit_moved(u) && can_move_to(game.to1, unit_speed(u) + rommel1)) - if (!is_battle_hex(unit_hex(u))) - gen_action_unit(u) - }) - } - - // Select Regroup Move 2 - if (game.to1) { - search_move(game.to2, 4 + rommel1) - for_each_undisrupted_friendly_unit_in_hex_or_adjacent(game.from2, u => { - if (!is_unit_moved(u) && can_move_to(game.to2, unit_speed(u) + rommel2)) - if (!is_battle_hex(unit_hex(u))) - gen_action_unit(u) - }) - } - - // Retreat - let has_retreat_hex = false - if (!game.to1 && game.from1 && is_battle_hex(game.from1) && !set_has(game.partial_retreats, game.from1)) - has_retreat_hex = true - if (!game.to2 && game.from2 && is_battle_hex(game.from2) && !set_has(game.partial_retreats, game.from2)) - has_retreat_hex = true - if (game.to1 && !has_enemy_unit(game.to1)) { - for_each_hex_and_adjacent_hex(game.from1, x => { - if (has_undisrupted_friendly_unit(x) && is_battle_hex(x) && !set_has(game.partial_retreats, x)) - has_retreat_hex = true - }) - } - if (game.to2 && !has_enemy_unit(game.to2)) { - for_each_hex_and_adjacent_hex(game.from2, x => { - if (has_undisrupted_friendly_unit(x) && is_battle_hex(x) && !set_has(game.partial_retreats, x)) - has_retreat_hex = true - }) - } - if (has_retreat_hex) - gen_action('retreat') - - gen_action('end_move') - } else { - - // Deselect - gen_action_unit(game.selected) - - // Move - if (game.turn_option === 'pass') - gen_move(search_withdraw) - else - gen_move(search_move) - - } - }, - unit(who) { - apply_select(who) - }, - hex(to) { - apply_move(to) - }, - retreat() { - push_undo() - log_br() - game.state = 'retreat_from' - }, - end_move() { - clear_undo() - log_br() - end_move_phase() - } -} - // === RETREAT === function can_select_retreat_hex() { -- cgit v1.2.3