summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-10-08 11:38:08 +0200
committerTor Andersson <tor@ccxvii.net>2023-12-10 18:16:55 +0100
commit2ab5c4c485c4f5a4a1d116889a55029eabe62c55 (patch)
tree7a07efafcc753a3dab3ff3838e26fd94a8686443
parent2c038ad158ef7e0bd9082682d386aa3e110e1829 (diff)
downloadplantagenet-2ab5c4c485c4f5a4a1d116889a55029eabe62c55.tar.gz
Optimize and fix Supply.
-rw-r--r--play.js2
-rw-r--r--rules.js315
2 files changed, 171 insertions, 146 deletions
diff --git a/play.js b/play.js
index 79a631d..7182845 100644
--- a/play.js
+++ b/play.js
@@ -280,7 +280,7 @@ function get_locale_tip(id) {
let loc = data.locales[id]
let tip = loc.name
if (set_has(data.seaports, id))
- tip += " - Seaport"
+ tip += " - Port"
let list = []
for (let lord = 0; lord < data.lords.length; ++lord) {
if (data.lords[lord].seat === id)
diff --git a/rules.js b/rules.js
index 9f7528b..05a611d 100644
--- a/rules.js
+++ b/rules.js
@@ -3472,6 +3472,8 @@ function can_parley_at(loc) {
var search_seen = new Array(last_locale + 1)
var search_dist = new Array(last_locale + 1)
+var search_carts = new Array(last_locale + 1)
+var search_ships = new Array(last_locale + 1)
function search_parley(result, start) {
let ships = get_shared_assets(start, SHIP)
@@ -3573,32 +3575,6 @@ function list_parley_levy() {
return search_parley([], here)
}
-function* map_search(lord, acceptfn, adjacentfn, prune = true) {
- let start = get_lord_locale(lord)
- let queue = [ { locale: start, distance: 0 } ]
- let seen = [ start ]
-
- while (queue.length > 0) {
- let item = queue.shift()
-
- if (acceptfn(item)) {
- yield item
- if (prune)
- continue
- }
-
- if (is_friendly_locale(item.locale)) {
- let distance = item.distance + 1
- for (let next of adjacentfn(item.locale, lord)) {
- if (!set_has(seen, next)) {
- set_add(seen, next)
- queue.push({ locale: next, distance })
- }
- }
- }
- }
-}
-
function goto_parley() {
push_state("parley")
@@ -4153,62 +4129,118 @@ function take_spoils(type) {
// === ACTION: SUPPLY (SEARCHING) ===
-function supply_adjacent(here, lord) {
- let lord_loc = get_lord_locale(lord)
- if (is_exile(here) && get_shared_assets(here, SHIP) > 0) {
- return find_ports_from_locale(here)
- } else if (is_exile(lord_loc) && lord_loc !== here) {
- return []
+// If Lord is in Exile: use ships and a port on the same sea.
+// If Lord is not in Exile or is in Scotland: use carts by way.
+// If Lord is in Exile in Scotland: may use carts by way to stronghold.
+// If source is stronghold: must use way.
+// Record number of carts needed in result map.
+
+// TODO: supply from scotland with carts? no ways defined in data
+
+function can_supply_at(loc, ships) {
+ // if theoretically possible to supply (does not check carts or ships)
+ if (is_stronghold(loc) && is_friendly_locale(loc)) {
+ if (ships > 0 && is_seaport(loc))
+ return true
+ if (!has_exhausted_marker(loc))
+ return true
}
- return data.locales[here].adjacent
+ return false
}
-// === ACTION: SUPPLY ===
+function search_supply_by_way(result, start, carts, ships) {
+ search_dist.fill(0)
+ search_seen.fill(0)
+ search_seen[start] = 1
-function supply_accept(loc, carts, ships) {
- return (
- !is_exile(loc.locale) &&
- is_friendly_locale(loc.locale) &&
- !has_enemy_lord(loc.locale) &&
- (!has_exhausted_marker(loc.locale) || (ships > 0 && is_seaport(loc.locale))) &&
- carts >= loc.distance
- )
-}
+ let queue = [ start ]
+ while (queue.length > 0) {
+ let here = queue.shift()
+ let dist = search_dist[here]
-function find_supply_sources(lord, carts, ships) {
- let search = map_search(lord, loc => supply_accept(loc, carts, ships), supply_adjacent, false)
+ if (can_supply_at(here, ships)) {
+ if (result)
+ map_set(result, here, dist)
+ else
+ return true
+ }
- let results = []
- for (let loc of search)
- results.push(loc)
- return results
+ if (is_friendly_locale(here)) {
+ let next_dist = dist + 1
+ if (next_dist <= carts) {
+ for (let next of data.locales[here].adjacent) {
+ if (!search_seen[next]) {
+ search_seen[next] = 1
+ search_dist[next] = next_dist
+ queue.push(next)
+ }
+ }
+ }
+ }
+ }
+
+ if (result)
+ return result
+ return false
}
-function init_supply() {
+function search_supply_by_sea(result, here) {
+ // Search via sea from Exile box.
+ if (is_friendly_locale(here)) {
+ for (let next of find_ports(here)) {
+ if (can_supply_at(next, 1)) {
+ if (result)
+ map_set(result, next, 0)
+ else
+ return true
+ }
+ }
+ }
+ if (result)
+ return result
+ return false
+}
+
+function search_supply(result) {
let here = get_lord_locale(game.command)
let carts = get_shared_assets(here, CART)
let ships = get_shared_assets(here, SHIP)
+ if (ships > 0 && is_exile(here))
+ result = search_supply_by_sea(result, here)
+ result = search_supply_by_way(result, here, carts, ships)
+ return result
+}
+
+// === ACTION: SUPPLY ===
+
+function command_has_harbingers() {
+ return (
+ lord_has_capability(game.command, AOW_LANCASTER_HARBINGERS) ||
+ lord_has_capability(game.command, AOW_YORK_HARBINGERS)
+ )
+}
- game.supply = {
- sources: find_supply_sources(game.command, carts, ships),
- carts: carts,
- ships: ships,
+function command_has_stafford_branch(loc) {
+ if (lord_has_capability(game.command, AOW_YORK_STAFFORD_BRANCH)) {
+ return (
+ loc === LOC_EXETER ||
+ loc === LOC_LAUNCESTON ||
+ loc === LOC_PLYMOUTH ||
+ loc === LOC_WELLS ||
+ loc === LOC_DORCHESTER
+ )
}
+ return false
+}
+
+function init_supply() {
+ game.supply = search_supply([])
}
function can_action_supply() {
if (game.actions < 1)
return false
- return can_supply()
-}
-
-function can_supply() {
- let here = get_lord_locale(game.command)
- let carts = get_shared_assets(here, CART)
- let ships = get_shared_assets(here, SHIP)
- let search = map_search(game.command, loc => supply_accept(loc, carts, ships), supply_adjacent, false)
-
- return search.next().done !== true
+ return search_supply(false)
}
function goto_supply() {
@@ -4218,32 +4250,41 @@ function goto_supply() {
init_supply()
}
-function get_supply_from_source(source) {
- let prov = 0
+function modify_supply(loc, supply) {
+ let here = get_lord_locale(game.command)
+ let carts = get_shared_assets(here, CART)
- if (has_exhausted_marker(source))
- return prov
+ // Must carry supply over land with one cart per provender per way
+ let distance = map_get(game.supply, loc)
+ if (distance > 0)
+ supply = Math.min(supply, Math.floor(carts / distance))
- if (
- game.command === LORD_DEVON &&
- lord_has_capability(LORD_DEVON, AOW_YORK_STAFFORD_BRANCH) &&
- (game.where === LOC_EXETER ||
- game.where === LOC_LAUNCESTON ||
- game.where === LOC_PLYMOUTH ||
- game.where === LOC_WELLS ||
- game.where === LOC_DORCHESTER)
- )
- prov += 1
+ // Harbingers event doubles supply received
+ if (command_has_harbingers())
+ supply = supply * 2
- if (source === LOC_LONDON || source === LOC_CALAIS) {
- prov += 2
- return prov
- } else if (is_city(source)) {
- prov += 1
- return prov
+ return supply
+}
+
+function get_port_supply_amount(loc) {
+ if (is_seaport(loc)) {
+ let here = get_lord_locale(game.command)
+ let ships = get_shared_assets(here, SHIP)
+ return modify_supply(loc, ships)
}
- prov += 1
- return prov
+ return 0
+}
+
+function get_stronghold_supply_amount(loc) {
+ if (!has_exhausted_marker(loc)) {
+ let supply = 1
+ if (loc === LOC_LONDON || loc === LOC_CALAIS)
+ supply = 2
+ if (command_has_stafford_branch(loc))
+ supply += 1
+ return modify_supply(loc, supply)
+ }
+ return 0
}
states.supply_source = {
@@ -4251,89 +4292,73 @@ states.supply_source = {
prompt() {
view.prompt = "Supply: Select Supply Source."
- let list = []
- if (game.supply.carts > 0)
- list.push(`${game.supply.carts} Cart`)
- if (game.supply.ships > 0)
- list.push(`${game.supply.ships} Ship`)
+ let here = get_lord_locale(game.command)
+ let carts = get_shared_assets(here, CART)
+ let ships = get_shared_assets(here, SHIP)
- if (list.length > 0)
- view.prompt += " " + list.join(", ") + "."
+ if (carts > 0)
+ view.prompt += ` ${carts} Cart.`
+ if (ships > 0)
+ view.prompt += ` ${carts} Ship.`
- for (let x of game.supply.sources)
- gen_action_locale(x.locale)
+ for (let i = 0; i < game.supply.length; i += 2)
+ gen_action_locale(game.supply[i])
},
- locale(source) {
- let source_item = game.supply.sources.find(s => s.locale === source)
- if (source_item !== undefined) {
- let supply = 0
- let sea_supply = 0
-
- if (is_seaport(source))
- sea_supply = game.supply.ships
+ locale(loc) {
+ push_undo()
- if (!is_exile(get_lord_locale(game.command)))
- supply = Math.min(get_supply_from_source(source), Math.floor(game.supply.carts / source_item.distance))
+ let port_supply = get_port_supply_amount(loc)
+ let stronghold_supply = get_stronghold_supply_amount(loc)
- if (
- lord_has_capability(game.command, AOW_LANCASTER_HARBINGERS) ||
- lord_has_capability(game.command, AOW_YORK_HARBINGERS)
- ) {
- supply = supply * 2
- sea_supply = sea_supply * 2
- }
+ if (stronghold_supply > 0 && port_supply === 0) {
+ use_stronghold_supply(loc, stronghold_supply)
+ return
+ }
- if (supply > 0 && sea_supply === 0) {
- logi(`Stronghold at %${source}`)
- add_lord_assets(game.command, PROV, supply)
- deplete_locale(source)
- } else if (sea_supply > 0 && supply === 0) {
- logi(`Seaport at %${source}`)
- add_lord_assets(game.command, PROV, sea_supply)
- } else {
- game.where = source
- goto_select_supply_type(supply, sea_supply)
- return
- }
+ if (port_supply > 0 && stronghold_supply === 0) {
+ use_port_supply(loc, port_supply)
+ return
}
- end_supply()
+
+ game.where = loc
+ game.state = "select_supply_type"
},
}
-function end_supply() {
- spend_action(1)
- resume_command()
- game.supply = 0
+function use_stronghold_supply(source, amount) {
+ logi(`${amount} from Stronghold at %${source}`)
+ add_lord_assets(game.command, PROV, amount)
+ deplete_locale(source)
+ end_supply()
}
-function goto_select_supply_type(supply, sea_supply) {
- push_state("select_supply_type")
- game.count = supply
- game.what = sea_supply
+function use_port_supply(source, amount) {
+ logi(`${amount} from Port at %${source}`)
+ add_lord_assets(game.command, PROV, amount)
+ end_supply()
}
-function end_select_supply_type() {
- pop_state()
- end_supply()
+function end_supply() {
+ spend_action(1)
+ resume_command()
+ game.supply = 0
}
states.select_supply_type = {
inactive: "Supply",
prompt() {
- view.prompt = `Supply: ${game.count} from Stronghold or ${game.what} from Port?`
+ let port = get_port_supply_amount(game.where)
+ let stronghold = get_stronghold_supply_amount(game.where)
+
+ view.prompt = `Supply: ${stronghold} from Stronghold or ${port} from Port?`
view.actions.stronghold = 1
view.actions.port = 1
},
stronghold() {
- logi(`Stronghold at %${game.where}`)
- add_lord_assets(game.command, PROV, game.count)
- deplete_locale(game.where)
- end_select_supply_type()
+ use_stronghold_supply(source, get_stronghold_supply_amount(source))
},
port() {
- logi(`Seaport at %${game.where}`)
- add_lord_assets(game.command, PROV, game.what)
- end_select_supply_type()
+ use_port_supply(source, get_port_supply_amount(source))
},
}
@@ -4604,7 +4629,7 @@ states.sail = {
let overflow_cart = (cart / 2 - ships) * 2
if (overflow_prov <= 0 && overflow_cart <= 0) {
- view.prompt = `Sail: Select a destination Seaport.`
+ view.prompt = `Sail: Select a destination Port.`
for (let to of find_sail_locales(here)) {
if (to !== here)
if (!has_enemy_lord(to) || lord_has_capability(game.command, AOW_LANCASTER_HIGH_ADMIRAL))