diff options
author | Joël Simoneau <simoneaujoel@gmail.com> | 2024-10-27 21:56:57 -0400 |
---|---|---|
committer | Joël Simoneau <simoneaujoel@gmail.com> | 2024-10-27 21:56:57 -0400 |
commit | 5231a78b3ea434fbf6adb65665b90d901706824d (patch) | |
tree | 1c21791481cd536709b89cff081f111030f0be59 | |
parent | 48b128fa766363fc35a74bfdeefed133c1f6b78c (diff) | |
download | vijayanagara-5231a78b3ea434fbf6adb65665b90d901706824d.tar.gz |
March.
-rw-r--r-- | play.js | 2 | ||||
-rw-r--r-- | rules.js | 238 |
2 files changed, 174 insertions, 66 deletions
@@ -965,6 +965,8 @@ function on_update() { // DS buttons action_button("conscript", "Conscript") action_button("end_conscript", "End Conscript") + action_button("march", "March") + action_button("end_march", "End March") // Command buttons action_button("rally", "Rally") @@ -6,10 +6,11 @@ let view = null /* DATA */ const data = require("./data.js") -const space_name = data.space_name +const SPACES = data.spaces +const SPACE_NAME = data.space_name function get_space_id(name) { - return space_name.indexOf(name); + return SPACE_NAME.indexOf(name); } const S_ANDHRA = get_space_id("Andhra") @@ -194,11 +195,12 @@ exports.setup = function (seed, scenario, _options) { pieces: Array(104).fill(AVAILABLE), // piece locations cavalry: [0, 0, 0], deck: [], - op: { + cmd: { type: null, limited: null, free: null, spaces: [], + pieces: [], where: null, }, decree: 0 @@ -309,7 +311,7 @@ function goto_eligible() { end_card() } else { game.state = "eligible" - game.op = { + game.cmd = { limited: 0, free: 0, spaces: [], @@ -349,7 +351,7 @@ function adjust_eligibility(faction) { function goto_pass() { push_undo() - game.op = 0 + game.cmd = 0 game.sa = 0 game.cylinder[game.current] = SOP_PASS @@ -380,20 +382,38 @@ function goto_conscript() { if (conscript_count() === 1) { let p = find_piece(AVAILABLE, game.current, TROOPS) log_summary_place(p) - place_piece(p, game.op.where) + place_piece(p, game.cmd.where) end_conscript_space() } else { - game.op.count = 0 + game.cmd.count = 0 game.state = "conscript_space" } } function end_conscript_space() { - log_space(game.op.where, "Conscript") + log_space(game.cmd.where, "Conscript") pop_summary() game.state = "conscript" } + function goto_march() { + init_command("March") + game.cmd.pieces = [] + game.state = "march" + } + + function goto_march_space() { + push_summary() + game.cmd_count = 0 + game.state = "march_space" + } + + function end_march_space() { + log_space(game.cmd.where, "March") + pop_summary() + game.state = "march" + } + function goto_rally() { init_command("Rally") game.state = "rally" @@ -405,16 +425,16 @@ function goto_conscript() { if (rally_count() === 1) { let p = find_piece(AVAILABLE, game.current, ELITE) log_summary_place(p) - place_piece(p, game.op.where) + place_piece(p, game.cmd.where) end_rally_space() } else { - game.op.count = 0 + game.cmd.count = 0 game.state = "rally_space" } } function end_rally_space() { - log_space(game.op.where, "Rally") + log_space(game.cmd.where, "Rally") pop_summary() game.state = "rally" } @@ -460,7 +480,7 @@ states.eligible = { lim_command() { push_undo() game.cylinder[game.current] = SOP_LIMITED_COMMAND - game.op.limited = 1 + game.cmd.limited = 1 game.state = "lim_command" }, } @@ -475,6 +495,7 @@ states.command_decree = { }, build: goto_build, conscript: goto_conscript, + march: goto_march, rally: goto_rally, rebel: goto_rebel, } @@ -486,6 +507,7 @@ states.event_command = { gen_any_command() }, conscript: goto_conscript, + march: goto_march, rally: goto_rally, rebel: goto_rebel, } @@ -497,6 +519,7 @@ states.lim_command = { gen_any_command() }, conscript: goto_conscript, + march: goto_march, rally: goto_rally, rebel: goto_rebel, } @@ -553,15 +576,15 @@ states.conscript = { states.conscript_space = { prompt() { view.prompt = `Conscript: Place up to ${conscript_count()} Troops.` - view.where = game.op.where + view.where = game.cmd.where view.actions.next = 1 gen_place_piece(DS, TROOPS) }, piece(p) { log_summary_place(p) - place_piece(p, game.op.where) - if (++game.op.count >= conscript_count()) + place_piece(p, game.cmd.where) + if (++game.cmd.count >= conscript_count()) end_conscript_space() }, next() { @@ -569,6 +592,52 @@ states.conscript_space = { } } +states.march = { + prompt() { + view.prompt = "March: Select a space to move into." + + if (can_select_cmd_space(1)) { + for (let s = first_space; s <= last_space; ++s) { + if (!is_selected_cmd_space(s) && can_march_in_space(s)) + gen_action_space(s) + } + } + + view.actions.end_march = prompt_end_cmd(1) + }, + space(s) { + push_undo + select_cmd_space(s, 1) + goto_march_space() + }, + end_march: end_command +} + +states.march_space = { + prompt() { + view.prompt = "March: Move pieces from adjacent spaces." + view.where = game.cmd.where + view.actions.next = 1 + + for (let p of iter_faction_movable(DS)) { + if ( + set_has(SPACES[game.cmd.where].adjacent, piece_space(p)) && + !set_has(game.cmd.pieces, p) + ) + gen_action_piece(p) + } + + }, + piece(p) { + log_summary_move_from(p) + set_add(game.cmd.pieces, p) + place_piece(p, game.cmd.where) + }, + next() { + end_march_space() + } +} + states.rally = { prompt() { if (game.current === BK) @@ -596,15 +665,15 @@ states.rally = { states.rally_space = { prompt() { view.prompt = `Rally: Place up to ${rally_count()} ${PIECE_FACTION_TYPE_NAME[game.current][ELITE]}` - view.where = game.op.where + view.where = game.cmd.where view.actions.next = 1 gen_place_piece(game.current, ELITE) }, piece(p) { log_summary_place(p) - place_piece(p, game.op.where) - if (++game.op.count >= rally_count()) + place_piece(p, game.cmd.where) + if (++game.cmd.count >= rally_count()) end_rally_space() }, next() { @@ -640,16 +709,17 @@ states.rebel = { function init_command(type) { push_undo() - if (game.op.limited) + if (game.cmd.limited) log_h2(faction_name[game.current] + " - Limited " + type) else log_h2(faction_name[game.current] + " - " + type) - game.op.type = type + game.cmd.type = type } function gen_any_command() { if (game.current === DS) { view.actions.conscript = can_conscript() ? 1 : 0 + view.actions.march = can_march() ? 1 : 0 } else if (game.current === BK || game.current === VE) { view.actions.rally = can_rally() ? 1 : 0 view.actions.rebel = can_rebel() ? 1 : 0 @@ -657,18 +727,18 @@ function gen_any_command() { } function can_select_cmd_space(cost) { - if (!game.op.free && game.resources[game.current] < cost) + if (!game.cmd.free && game.resources[game.current] < cost) return false - if (game.op.limited) - return game.op.spaces.length === 0 + if (game.cmd.limited) + return game.cmd.spaces.length === 0 return true } function select_cmd_space(s, cost) { - set_add(game.op.spaces, s) - if (!game.op.free) + set_add(game.cmd.spaces, s) + if (!game.cmd.free) game.resources[game.current] -= cost - game.op.where = s + game.cmd.where = s } function can_conscript() { @@ -681,14 +751,28 @@ function can_conscript_in_space(s) { } function conscript_count() { - if (game.op.where === S_DELHI) + if (game.cmd.where === S_DELHI) return 5 - if (has_piece(game.op.where, DS, DISC)) { + if (has_piece(game.cmd.where, DS, DISC)) { return 2 } return 1 } +function can_march() { + for (let s = first_space; s <= last_space; ++s) + if (can_march_in_space(s)) + return true + return false +} + +function can_march_in_space(s) { + for (let adj of SPACES[s].adjacent) + if (has_unmoved_piece(adj, DS)) + return true + return false +} + function can_rally() { return has_piece(AVAILABLE, game.current, ELITE) } @@ -705,10 +789,10 @@ function rally_count() { // TODO : Add rally with control + 1 let count = 1 if (game.current === BK) { - count += (game.op.where === S_MAHARASHTRA ? 1 : 0) + count += (game.cmd.where === S_MAHARASHTRA ? 1 : 0) } else if (game.current === VE) { - count += (game.op.where === S_KARNATAKA ? 1 : 0) - count += (has_piece(game.op.where, VE, DISC) ? 1 : 0) + count += (game.cmd.where === S_KARNATAKA ? 1 : 0) + count += (has_piece(game.cmd.where, VE, DISC) ? 1 : 0) } return count } @@ -730,19 +814,19 @@ function can_rebel_in_space(s) { function prompt_end_cmd(cost) { if (!view.actions.space) { - if (game.op.limited && game.op.spaces && game.op.spaces.length > 0) - view.prompt = game.op.type + ": Done." - else if (!game.op.free && game.resources[game.current] < cost) - view.prompt = game.op.type + ": No resources." + if (game.cmd.limited && game.cmd.spaces && game.cmd.spaces.length > 0) + view.prompt = game.cmd.type + ": Done." + else if (!game.cmd.free && game.resources[game.current] < cost) + view.prompt = game.cmd.type + ": No resources." else - view.prompt = game.op.type + ": Done." + view.prompt = game.cmd.type + ": Done." } - return (game.op.spaces.length > 0) ? 1 : 0 + return (game.cmd.spaces.length > 0) ? 1 : 0 } function end_command() { log_br() - game.op = null + game.cmd = null resume_event_card() } @@ -775,6 +859,10 @@ function is_tributary(s) { return game.tributary & (1 << s) } +function is_faction_control(s, faction) { + return game.control[faction] & (1 << s) +} + function remove_tributary(s) { game.tributary &= ~(1 << s) update_control() @@ -789,28 +877,26 @@ function to_obedient(p) { function to_rebel(p) { let faction = piece_faction(p) let piece_index = p - first_piece[faction][ELITE] - console.log("with p ", p) - console.log("with piece_index ", piece_index) - console.log(game.rebel) game.rebel[faction] |= (1 << piece_index) - console.log(game.rebel) } function to_rebel_space(s, faction) { - let first = first_piece[faction][ELITE] - let last = last_piece[faction][ELITE] - for (let p = first; p <= last; ++p) + for (let p of iter_faction_pieces(faction, ELITE)) if (piece_space(p) === s) to_rebel(p) } +function update_rebel(p, s) { + let faction = piece_faction(p) + if (is_faction_control(s, faction)) + to_rebel(p) +} + /* MISC SPACE + PIECE QUERIES */ function count_pieces(s, faction, type) { - let first = first_piece[faction][type] - let last = last_piece[faction][type] let n = 0 - for (let p = first; p <= last; ++p) + for (let p of iter_faction_pieces(faction, type)) if (piece_space(p) === s) ++n return n @@ -847,29 +933,30 @@ function has_majority(s) { return -1 } -function has_piece(s, faction, type) { - let first = first_piece[faction][type] - let last = last_piece[faction][type] - for (let p = first; p <= last; ++p) - if (piece_space(p) === s) - return true - return false -} - function find_piece(s, faction, type) { - let first = first_piece[faction][type] - let last = last_piece[faction][type] - for (let p = first; p <= last; ++p) + for (let p of iter_faction_pieces(faction, type)) if (piece_space(p) === s) return p return -1 } +function has_piece(s, faction, type) { + return find_piece(s, faction, type) != -1 +} + +function has_unmoved_piece(s, faction) { + for (let p of iter_faction_movable(faction)) + if (piece_space(p) === s) + if (!game.cmd.pieces || game.cmd.pieces.length === 0) + return true + else if (!set_has(game.cmd.pieces, p)) + return true + return false +} + function gen_place_piece(faction, type) { - let p0 = first_piece[faction][type] - let p1 = last_piece[faction][type] let can_place = false - for (let p = p0; p <= p1; ++p) { + for (let p of iter_faction_pieces(faction, type)) { if (piece_space(p) === AVAILABLE) { gen_action_piece(p) can_place = true @@ -881,7 +968,7 @@ function gen_place_piece(faction, type) { } function is_selected_cmd_space(s) { - return game.op.spaces && set_has(game.op.spaces, s) + return game.cmd.spaces && set_has(game.cmd.spaces, s) } function place_piece(p, s) { @@ -890,6 +977,7 @@ function place_piece(p, s) { set_piece_space(p, s) update_control() + update_rebel(p, s) } function piece_faction(p) { @@ -1053,8 +1141,8 @@ function log_summary_place(p) { log_summary("% " + piece_name(p)) } -function log_summary_move_to_from(p, to) { - log_summary("% " + piece_name(p) + " to S" + to + " from S" + piece_space(p)) +function log_summary_move_from(p) { + log_summary("% " + piece_name(p) + " from S" + piece_space(p)) } function log_summary_remove(p) { @@ -1409,6 +1497,24 @@ function object_group_by(items, callback) { return groups } +/* GENERATORS */ + +function* iter_faction_pieces(faction, type) { + let first = first_piece[faction][type] + let last = last_piece[faction][type] + for (let p = first; p <= last; ++p) + yield p; +} + +function* iter_faction_movable(faction) { + if (faction === DS) { + yield* iter_faction_pieces(DS, ELITE) + yield* iter_faction_pieces(DS, TROOPS) + } else { + yield* iter_faction_pieces(faction, ELITE) + } +} + // === CONST === |