From d08d720730fd0b2517a864c4ea308b145a69da72 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 30 May 2024 22:04:31 +0200 Subject: stoof --- rules.js | 393 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 391 insertions(+), 2 deletions(-) diff --git a/rules.js b/rules.js index bad1211..51218c6 100644 --- a/rules.js +++ b/rules.js @@ -9,6 +9,55 @@ var game, view // space list: // objective/fortress have control (0 or power) +const data = require("./data") +let objectives = {} +let anti_objectives = { Austria: [], "Pragmatic Army": [], France: [], Prussia: [] } +let prot_objectives = { Austria: [], "Pragmatic Army": [], France: [], Prussia: [] } + +let whose_objective = { + Austria: [ "France", "Prussia" ], + Bavaria: [ "Austria" ], + France: [ "Austria", "Pragmatic Army" ], + Netherlands: [ "France" ], + Prussia: [ "Austria" ], + Saxony: [ "Austria" ], + Silesia: [ "Austria", "Prussia" ], + HRE: [ "Austria", "Pragmatic Army", "France" ], +} + +let protect_objective = { + Austria: [ "Austria" ], + Bavaria: [ "France" ], + France: [ "France" ], + Netherlands: [ "Pragmatic Army" ], + Prussia: [ "Prussia" ], + Saxony: [ "Prussia" ], + Silesia: [ "Austria", "Prussia" ], + HRE: [ "Austria", "Pragmatic Army", "France" ], +} + +for (let type of [ "major_fortress", "minor_fortress" ]) { + let group = object_group_by(data.type[type], s => data.cities.country[s]) + for (let region in group) { + if (objectives[region] === undefined) + objectives[region] = [] + for (let s of group[region]) { + set_add(objectives[region], s) + console.log(region) + for (let list of whose_objective[region]) + set_add(anti_objectives[list], s) + for (let list of protect_objective[region]) + set_add(prot_objectives[list], s) + } + + } +} +for (let x in anti_objectives) + console.log(x, anti_objectives[x].length) +console.log(objectives) +console.log("TAKE", anti_objectives) +console.log("PROT", prot_objectives) + exports.roles = [ "Maria Theresa", "Frederick", "Louis XV" ] exports.scenarios = [ "Standard", "Introductory" ] @@ -50,6 +99,7 @@ exports.setup = function (seed, scenario, options) { state: "setup", turn: 1, + step: 0, ctl: [], loc: [], str: [], @@ -106,8 +156,8 @@ exports.setup = function (seed, scenario, options) { exports.view = function (state) { game = state view = { - log: game.log - power: game.power + log: game.log, + power: game.power, turn: game.turn, ctl: game.ctl, loc: game.loc, @@ -115,3 +165,342 @@ exports.view = function (state) { } return view } + + + +// === COMMON LIBRARY === + +function clear_undo() { + if (game.undo) { + game.undo.length = 0 + } +} + +function push_undo() { + if (game.undo) { + let copy = {} + for (let k in game) { + let v = game[k] + if (k === "undo") + continue + else if (k === "log") + v = v.length + else if (typeof v === "object" && v !== null) + v = object_copy(v) + copy[k] = v + } + game.undo.push(copy) + } +} + +function pop_undo() { + if (game.undo) { + let save_log = game.log + let save_undo = game.undo + game = save_undo.pop() + save_log.length = game.log + game.log = save_log + game.undo = save_undo + } +} + +function random(range) { + // An MLCG using integer arithmetic with doubles. + // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf + // m = 2**35 − 31 + return (game.seed = game.seed * 200105 % 34359738337) % range +} + +function random_bigint(range) { + // Largest MLCG that will fit its state in a double. + // Uses BigInt for arithmetic, so is an order of magnitude slower. + // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf + // m = 2**53 - 111 + return (game.seed = Number(BigInt(game.seed) * 5667072534355537n % 9007199254740881n)) % range +} + +function shuffle(list) { + // Fisher-Yates shuffle + for (let i = list.length - 1; i > 0; --i) { + let j = random(i + 1) + let tmp = list[j] + list[j] = list[i] + list[i] = tmp + } +} + +function shuffle_bigint(list) { + // Fisher-Yates shuffle + for (let i = list.length - 1; i > 0; --i) { + let j = random_bigint(i + 1) + let tmp = list[j] + list[j] = list[i] + list[i] = tmp + } +} + +// Fast deep copy for objects without cycles +function object_copy(original) { + if (Array.isArray(original)) { + let n = original.length + let copy = new Array(n) + for (let i = 0; i < n; ++i) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } else { + let copy = {} + for (let i in original) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } +} + +// Array remove and insert (faster than splice) + +function array_remove(array, index) { + let n = array.length + for (let i = index + 1; i < n; ++i) + array[i - 1] = array[i] + array.length = n - 1 +} + +function array_remove_item(array, item) { + let n = array.length + for (let i = 0; i < n; ++i) + if (array[i] === item) + return array_remove(array, i) +} + +function array_insert(array, index, item) { + for (let i = array.length; i > index; --i) + array[i] = array[i - 1] + array[index] = item +} + +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 +} + +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 +} + +// Set as plain sorted array + +function set_clear(set) { + set.length = 0 +} + +function set_has(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return true + } + return false +} + +function set_add(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return + } + array_insert(set, a, item) +} + +function set_delete(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove(set, m) + return + } + } +} + +function set_toggle(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove(set, m) + return + } + } + array_insert(set, a, item) +} + +function set_union(a, b) { + let out = a.slice() + for (let item of b) + set_add(out, item) + return out +} + +// Map as plain sorted array of key/value pairs + +function map_clear(map) { + map.length = 0 +} + +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, 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 { + array_remove_pair(map, m<<1) + return + } + } +} + +function object_diff(a, b) { + if (a === b) + return false + if (a !== null && b !== null && typeof a === "object" && typeof b === "object") { + if (Array.isArray(a)) { + if (!Array.isArray(b)) + return true + let a_length = a.length + if (b.length !== a_length) + return true + for (let i = 0; i < a_length; ++i) + if (object_diff(a[i], b[i])) + return true + return false + } + for (let key in a) + if (object_diff(a[key], b[key])) + return true + for (let key in b) + if (!(key in a)) + return true + return false + } + return true +} + +// same as Object.groupBy +function object_group_by(items, callback) { + let groups = {} + if (typeof callback === "function") { + for (let item of items) { + let key = callback(item) + if (key in groups) + groups[key].push(item) + else + groups[key] = [ item ] + } + } else { + for (let item of items) { + let key = item[callback] + if (key in groups) + groups[key].push(item) + else + groups[key] = [ item ] + } + } + return groups +} -- cgit v1.2.3