"use strict" var game, view // piece list: // generals, trains, and hussars - have location (loc) // generals - have strength (str) // 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 = [ "Louis XV", "Frederick", "Maria Theresa", ] exports.scenarios = [ "Standard", "Introductory" ] const P_AUSTRIA = 0 const P_PRUSSIA = 1 const P_SAXONY = 2 const P_PRAGMATIC = 3 const P_FRANCE = 4 const P_BAVARIA = 5 const PLAYERS = { "Maria Theresa": [ P_AUSTRIA ], "Frederick": [ P_PRUSSIA, P_SAXONY, P_PRAGMATIC ], "Louis XV": [ P_FRANCE, P_BAVARIA ], } const MAJOR_POWERS = [ P_AUSTRIA, P_PRUSSIA, P_FRANCE, P_PRAGMATIC ] const MINOR_POWERS = [ P_BAVARIA, P_SAXONY ] const ALLIED = [ [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY ], [ P_AUSTRIA, P_PRAGMATIC ], ] const COOPERATE = [ [ P_FRANCE, P_BAVARIA ], [ P_PRUSSIA, P_SAXONY ], [ P_AUSTRIA, P_PRAGMATIC ], ] exports.setup = function (seed, scenario, options) { game = { seed: seed, log: [], undo: [], active: 0, // player power: 0, // power state: "setup", turn: 1, step: 0, ctl: [], loc: [], str: [], } /* SETUP Austria 6 Malmedy Austria T Geel Austria 1 Austerlitz Austria 2 Steinamanger Austria 3 Stuhlweißenburg Austria 4 Stuhlweißenburg Austria 5 Trübau Austria T Hlinsko Austria T Bruck Austria H1 Off-map Austria H2 Off-map Prussia 1 Steinau Prussia 2 Steinau Prussia 3 Sprottau Prussia 4 Ostpreussen Box Prussia T Grünberg Prussia T Silesia Box Saxony 1 Radeberg Saxony T Meißen Bavaria 1 Ergoldsbach Bavaria T Falkenstein France 1 Beaune France T Bar-le-Duc France 5 Sarreguemines France 4 Créspy-en-V. France 2 Schwandorf France 3 Ergoldsbach France T Regensburg Pragmatic T Tilburg Pragmatic 3 Dordecht Pragmatic 1 Delfzijl Pragmatic 2 Delfzijl */ return game } exports.view = function (state) { game = state view = { log: game.log, power: game.power, turn: game.turn, ctl: game.ctl, loc: game.loc, str: game.str, // TODO: redact! } 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 }