summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-11-12 14:34:56 +0100
committerTor Andersson <tor@ccxvii.net>2023-11-12 17:39:46 +0100
commit0cee28075504d3354e5c327200d472c760452b94 (patch)
treed4c87746e5365e553ded624bd4c7500f0607372a /rules.js
parent9323f62100b1f74ac5361b86cc53655adaee9572 (diff)
downloadrichard-iii-0cee28075504d3354e5c327200d472c760452b94.tar.gz
Show border limits.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js142
1 files changed, 122 insertions, 20 deletions
diff --git a/rules.js b/rules.js
index 5efce8c..9bca996 100644
--- a/rules.js
+++ b/rules.js
@@ -27,6 +27,9 @@ const ENEMY = { Lancaster: "York", York: "Lancaster" }
const OBSERVER = "Observer"
const BOTH = "Both"
+const PLAYER_ID = { "": 0, Lancaster: 1, York: 2 }
+const ID_PLAYER = [ "", "Lancaster", "York" ]
+
// areas
const NOWHERE = 0
const POOL = 1
@@ -608,11 +611,11 @@ function border_id(a, b) {
}
function border_was_last_used_by_enemy(from, to) {
- return game.last_used[border_id(from, to)] === ENEMY[game.active]
+ return map_get(game.last_used, border_id(from, to), 0) === PLAYER_ID[ENEMY[game.active]]
}
function border_was_last_used_by_active(from, to) {
- return game.last_used[border_id(from, to)] === game.active
+ return map_get(game.last_used, border_id(from, to), 0) === PLAYER_ID[game.active]
}
function border_type(a, b) {
@@ -620,11 +623,15 @@ function border_type(a, b) {
}
function border_limit(a, b) {
- return game.border_limit[border_id(a,b)] || 0
+ return map_get(game.border_limit, border_id(a,b), 0)
+}
+
+function set_border_limit(a, b, n) {
+ map_set(game.border_limit, border_id(a,b), n)
}
function reset_border_limits() {
- game.border_limit = {}
+ game.border_limit.length = 0
}
function count_friendly(where) {
@@ -1399,7 +1406,7 @@ function start_game_turn() {
// Reset movement and attack tracking state
reset_border_limits()
- game.last_used = {}
+ game.last_used = []
game.attacker = {}
set_clear(game.reserves)
set_clear(game.moved)
@@ -1733,7 +1740,7 @@ states.muster_move_2 = {
// ACTION PHASE
function use_border(from, to) {
- game.border_limit[border_id(from, to)] = border_limit(from, to) + 1
+ set_border_limit(from, to, border_limit(from, to) + 1)
}
function move_block(who, from, to) {
@@ -1741,12 +1748,12 @@ function move_block(who, from, to) {
use_border(from, to)
game.distance ++
if (is_contested_area(to)) {
- game.last_used[border_id(from, to)] = game.active
+ map_set(game.last_used, border_id(from, to), PLAYER_ID[game.active])
if (!game.attacker[to]) {
game.attacker[to] = game.active
- game.main_border[to] = from
+ map_set(game.main_border, to, from)
} else {
- if (game.attacker[to] !== game.active || game.main_border[to] !== from) {
+ if (game.attacker[to] !== game.active || map_get(game.main_border, to, 0) !== from) {
set_add(game.reserves, who)
return RESERVE_MARK
}
@@ -1760,8 +1767,8 @@ function goto_action_phase(moves) {
game.state = 'action_phase'
game.moves = moves
game.activated = []
- game.move_port = {}
- game.main_border = {}
+ game.move_port = []
+ game.main_border = []
game.turn_log = []
game.recruit_log = []
clear_undo()
@@ -1812,7 +1819,7 @@ states.action_phase = {
}
if (can_block_sea_move(b)) {
if (game.moves === 0) {
- if (game.move_port[game.location[b]] !== undefined)
+ if (map_has(game.move_port, game.location[b]))
gen_action(view, 'block', b)
} else {
gen_action(view, 'block', b)
@@ -1892,7 +1899,7 @@ states.move_to = {
let has_destination_port = false
if (game.moves === 0) {
for (let port of AREAS[to].exits)
- if (game.move_port[game.origin] === port)
+ if (map_get(game.move_port, game.origin) === port)
has_destination_port = true
} else {
if (game.active === game.piracy)
@@ -1923,6 +1930,7 @@ states.move_to = {
log_move_start(from)
game.last_from = from
if (is_sea_area(to)) {
+ // XXX use_border(from, to) // if displaying sea moves
log_move_continue(to)
game.location[game.who] = to
game.state = 'sea_move_to'
@@ -1953,7 +1961,7 @@ states.sea_move_to = {
continue
if (is_friendly_or_vacant_area(to)) {
if (game.moves === 0) {
- if (game.move_port[game.origin] === to)
+ if (map_get(game.move_port, game.origin) === to)
gen_action(view, 'area', to)
} else {
gen_action(view, 'area', to)
@@ -1965,6 +1973,8 @@ states.sea_move_to = {
}
},
area: function (to) {
+ // XXX use_border(game.location[game.who], to) // if displaying sea moves
+
game.location[game.who] = to
set_add(game.moved, game.who)
@@ -1979,13 +1989,13 @@ states.sea_move_to = {
} else {
// Can sea move two blocks between same major ports for 1 AP.
log_move_continue(to)
- if (game.move_port[game.origin] === to) {
- delete game.move_port[game.origin]
+ if (map_get(game.move_port, game.origin) === to) {
+ map_delete(game.move_port, game.origin)
} else {
logp("sea moved.")
--game.moves
if (is_major_port(game.origin) && is_major_port(to))
- game.move_port[game.origin] = to
+ map_set(game.move_port, game.origin, to)
}
}
@@ -2020,6 +2030,7 @@ function end_action() {
// BATTLE PHASE
function goto_battle_phase() {
+ reset_border_limits()
if (have_contested_areas()) {
game.active = game.p1
game.state = 'battle_phase'
@@ -3463,9 +3474,9 @@ exports.setup = function (seed, scenario, options) {
reserves: [],
attacker: {},
- border_limit: {},
- last_used: {},
- main_border: {},
+ border_limit: [],
+ last_used: [],
+ main_border: [],
}
// Old RNG for ancient replays
@@ -3537,10 +3548,18 @@ exports.view = function(state, current) {
steps: game.steps,
moved: game.moved,
dead: game.dead,
+ last_used: game.last_used,
+ border_limit: game.border_limit,
battle: null,
prompt: null,
}
+ if (game.main_border && game.main_border.length > 0) {
+ view.main_border = []
+ for (let i = 0; i < game.main_border.length; i += 2)
+ set_add(view.main_border, border_id(game.main_border[i+0], game.main_border[i+1]))
+ }
+
states[game.state].prompt(view, current)
if (states[game.state].show_battle)
@@ -3560,6 +3579,13 @@ function array_remove(array, index) {
return array
}
+function array_remove_pair(array, index) {
+ let n = array.length
+ for (let i = index + 2; i < n; ++i)
+ array[i - 2] = array[i]
+ array.length = n - 2
+}
+
// insert item at index (faster than splice)
function array_insert(array, index, item) {
for (let i = array.length; i > index; --i)
@@ -3568,6 +3594,15 @@ function array_insert(array, index, item) {
return array
}
+function array_insert_pair(array, index, key, value) {
+ for (let i = array.length; i > index; i -= 2) {
+ array[i] = array[i-2]
+ array[i+1] = array[i-1]
+ }
+ array[index] = key
+ array[index+1] = value
+}
+
function set_clear(set) {
set.length = 0
}
@@ -3620,6 +3655,73 @@ function set_delete(set, item) {
return set
}
+function map_has(map, key) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return true
+ }
+ return false
+}
+
+function map_get(map, key, missing) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return map[(m<<1)+1]
+ }
+ return missing
+}
+
+function map_set(map, key, value) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else {
+ map[(m<<1)+1] = value
+ return
+ }
+ }
+ array_insert_pair(map, a<<1, key, value)
+}
+
+function map_delete(map, item) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else {
+ array_remove_pair(map, m<<1)
+ return
+ }
+ }
+}
+
// Fast deep copy for objects without cycles
function object_copy(original) {
if (Array.isArray(original)) {