diff options
-rw-r--r-- | play.css | 20 | ||||
-rw-r--r-- | play.html | 1 | ||||
-rw-r--r-- | play.js | 170 | ||||
-rw-r--r-- | rules.js | 142 | ||||
-rw-r--r-- | tools/borders.svg | 626 | ||||
-rw-r--r-- | tools/coord.js | 7 | ||||
-rw-r--r-- | tools/genborders.js | 53 | ||||
-rw-r--r-- | tools/makeborders.js | 29 | ||||
-rw-r--r-- | tools/slice.sh | 16 |
9 files changed, 1044 insertions, 20 deletions
@@ -147,6 +147,26 @@ header.your_turn { background-color: orange; } visibility: hidden; } +.border { + position: absolute; + width: 24px; + height: 24px; + border-radius: 50%; + text-align: center; + line-height: 24px; + font-size: 16px; + font-weight: bold; + color: #000c; + background-color: #535a26; +} + +.border.sea { background-color: #ecb30c; } +.border.major { background-color: #cbc183; } +.border.minor { background-color: #946127; } +.border.river { background-color: #91a1a9; } +.border.Lancaster { background-color: brown; color: #fed; } +.border.York { background-color: #fdfefc; color: #ae2e24; } + /* BLOCKS */ body.shift .block.known:hover { @@ -529,6 +529,7 @@ l0 -3 539 0 540 0 2 2 3 3 -1 78 c0 60 0 79 1 83 3 11 14 23 25 27 5 1 24 1 </g> </svg> +<div id="borders"></div> <div id="blocks"></div> <div id="offmap" style="visibility:hidden"></div> </div> @@ -1,5 +1,37 @@ "use strict" +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 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 +} + const LANCASTER = "Lancaster" const YORK = "York" const ENEMY = { York: "Lancaster", Lancaster: "York" } @@ -76,6 +108,100 @@ const LONG_NAME = { "Gloucester": "Duke of Gloucester", } +// :!r node tools/genborders.js +const BORDERS_XY = { + "English Channel / Calais": [1317,1792], + "English Channel / France": [378,125], + "English Channel / Cornwall": [382,1762], + "English Channel / Dorset": [860,1660], + "English Channel / Kent": [1437,1565], + "English Channel / Sussex": [1090,1631], + "Irish Sea / France": [185,245], + "Irish Sea / Ireland": [176,396], + "Irish Sea / Scotland": [575,284], + "Irish Sea / Caernarvon": [524,816], + "Irish Sea / Chester": [627,782], + "Irish Sea / Cornwall": [286,1646], + "Irish Sea / Cumbria": [570,482], + "Irish Sea / Glamorgan": [459,1366], + "Irish Sea / Isle of Man": [389,467], + "Irish Sea / Lancaster": [645,654], + "Irish Sea / Pembroke": [303,1187], + "Irish Sea / Somerset": [688,1418], + "North Sea / Calais": [1565,1760], + "North Sea / Scotland": [844,16], + "North Sea / East Anglia": [1582,972], + "North Sea / East Yorks": [1224,643], + "North Sea / Essex": [1504,1295], + "North Sea / Kent": [1562,1445], + "North Sea / Lincoln": [1305,801], + "North Sea / Middlesex": [1382,1392], + "North Sea / Northumbria": [952,248], + "North Sea / Rutland": [1298,965], + "Scotland / Cumbria": [679,248], + "Scotland / Northumbria": [774,171], + "Caernarvon / Chester": [677,920], + "Caernarvon / Pembroke": [479,1071], + "Caernarvon / Powys": [522,995], + "Chester / Derby": [842,879], + "Chester / Hereford": [717,1012], + "Chester / Lancaster": [762,794], + "Chester / Powys": [610,986], + "Chester / Warwick": [793,982], + "Cornwall / Dorset": [613,1627], + "Cornwall / Somerset": [528,1574], + "Cumbria / Lancaster": [740,517], + "Cumbria / North Yorks": [819,478], + "Cumbria / Northumbria": [782,342], + "Derby / Lancaster": [881,784], + "Derby / Leicester": [1029,943], + "Derby / Lincoln": [1098,840], + "Derby / South Yorks": [986,814], + "Derby / Warwick": [878,981], + "Dorset / Somerset": [716,1566], + "Dorset / Sussex": [965,1582], + "Dorset / Wilts": [879,1558], + "East Anglia / Essex": [1452,1168], + "East Anglia / Rutland": [1354,1042], + "East Yorks / North Yorks": [971,521], + "East Yorks / Northumbria": [997,431], + "East Yorks / South Yorks": [1039,654], + "Essex / Leicester": [1218,1165], + "Essex / Middlesex": [1300,1261], + "Essex / Rutland": [1287,1132], + "Glamorgan / Hereford": [712,1226], + "Glamorgan / Pembroke": [447,1274], + "Glamorgan / Powys": [563,1195], + "Gloucester / Hereford": [799,1282], + "Gloucester / Oxford": [956,1254], + "Gloucester / Somerset": [786,1397], + "Gloucester / Warwick": [881,1208], + "Gloucester / Wilts": [913,1351], + "Hereford / Powys": [640,1112], + "Hereford / Warwick": [793,1127], + "Kent / Middlesex": [1329,1401], + "Kent / Sussex": [1276,1509], + "Lancaster / North Yorks": [791,623], + "Lancaster / South Yorks": [880,701], + "Leicester / Lincoln": [1145,937], + "Leicester / Middlesex": [1157,1180], + "Leicester / Oxford": [1051,1173], + "Leicester / Rutland": [1172,1057], + "Leicester / Warwick": [974,1048], + "Lincoln / Rutland": [1211,967], + "Lincoln / South Yorks": [1111,741], + "Middlesex / Oxford": [1138,1298], + "Middlesex / Sussex": [1152,1413], + "North Yorks / Northumbria": [905,434], + "North Yorks / South Yorks": [939,611], + "Oxford / Sussex": [1085,1404], + "Oxford / Warwick": [975,1128], + "Oxford / Wilts": [1032,1363], + "Pembroke / Powys": [517,1141], + "Somerset / Wilts": [838,1452], + "Sussex / Wilts": [1018,1495], +} + function toggle_blocks() { document.getElementById("map").classList.toggle("hide_blocks") } @@ -85,6 +211,7 @@ let ui = { card_backs: {}, areas: {}, blocks: {}, + borders: [], battle_menu: {}, battle_block: {}, present: new Set(), @@ -458,6 +585,23 @@ function build_map() { build_battle_block(b, block) build_map_block(b, block) } + + for (let name in BORDERS_XY) { + let [x, y] = BORDERS_XY[name] + let [a, b] = name.split(" / ") + let id = area_index[a] * 100 + area_index[b] + let type = BORDERS[id] || "sea" + if (type !== "sea") { + let e = document.createElement("div") + e.my_id = id + e.my_show = "border " + type + e.className = "hide" + e.style.left = (x - 12) + "px" + e.style.top = (y - 12) + "px" + ui.borders.push(e) + document.getElementById("borders").appendChild(e) + } + } } function update_steps(b, steps, element) { @@ -672,6 +816,32 @@ function update_map() { if (view.who !== NOBODY) ui.blocks[view.who].classList.add('selected') } + + for (let e of ui.borders) { + let u = map_get(view.last_used, e.my_id, 0) + let n = map_get(view.border_limit, e.my_id, "") + if (view.main_border && set_has(view.main_border, e.my_id)) + n += "*" + switch (u) { + case 1: + e.className = "border Lancaster" + e.textContent = n + break + case 2: + e.className = "border York" + e.textContent = n + break + case 0: + if (n) { + e.className = e.my_show + e.textContent = n + } else { + e.className = "hide" + e.textContent = "" + } + break + } + } } function update_cards() { @@ -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)) { diff --git a/tools/borders.svg b/tools/borders.svg new file mode 100644 index 0000000..af5d4a5 --- /dev/null +++ b/tools/borders.svg @@ -0,0 +1,626 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="1688" + height="1950" + version="1.1" + id="svg184" + sodipodi:docname="borders.svg" + inkscape:version="1.0.2 (e86c870879, 2021-01-15)"> + <metadata + id="metadata190"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs188" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview186" + showgrid="false" + inkscape:zoom="1.1527496" + inkscape:cx="1088.4392" + inkscape:cy="1254.8844" + inkscape:current-layer="svg184" + inkscape:document-rotation="0" /> + <image + sodipodi:absref="/home/tor/src/rally/public/richard-iii/map75.png" + xlink:href="../map75.png" + x="0" + y="0" + width="1688" + height="1950" + image-rendering="pixelated" + sodipodi:insensitive="true" + id="image2" /> + <circle + inkscape:label="English Channel / Calais" + cx="1317.2211" + cy="1791.8992" + r="12" + id="circle4" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="English Channel / France" + cx="378.1528" + cy="124.8569" + r="12" + id="circle6" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="English Channel / Cornwall" + cx="381.73529" + cy="1761.797" + r="12" + id="circle8" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="English Channel / Dorset" + cx="860.13171" + cy="1660.2496" + r="12" + id="circle10" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="English Channel / Kent" + cx="1437.1509" + cy="1564.6982" + r="12" + id="circle12" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="English Channel / Sussex" + cx="1089.8998" + cy="1631.4418" + r="12" + id="circle14" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / France" + cx="185.40173" + cy="245.46254" + r="12" + id="circle16" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Ireland" + cx="176.3347" + cy="396.28262" + r="12" + id="circle18" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Scotland" + cx="574.70367" + cy="283.78055" + r="12" + id="circle20" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Caernarvon" + cx="523.86005" + cy="815.64746" + r="12" + id="circle22" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Chester" + cx="627.04523" + cy="782.03564" + r="12" + id="circle24" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Cornwall" + cx="286.44171" + cy="1645.9286" + r="12" + id="circle26" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Cumbria" + cx="570.30176" + cy="482.10016" + r="12" + id="circle28" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Glamorgan" + cx="459.25238" + cy="1366.3389" + r="12" + id="circle30" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Isle of Man" + cx="388.50479" + cy="466.7449" + r="12" + id="circle32" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Lancaster" + cx="645.15912" + cy="653.99316" + r="12" + id="circle34" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Pembroke" + cx="303.14954" + cy="1187.4073" + r="12" + id="circle36" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Irish Sea / Somerset" + cx="688.13031" + cy="1418.3497" + r="12" + id="circle38" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Calais" + cx="1565.3402" + cy="1760.4211" + r="12" + id="circle40" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Scotland" + cx="843.83649" + cy="16.06251" + r="12" + id="circle42" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / East Anglia" + cx="1581.7091" + cy="972.2962" + r="12" + id="circle44" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / East Yorks" + cx="1224.0212" + cy="642.82007" + r="12" + id="circle46" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Essex" + cx="1503.5902" + cy="1294.7825" + r="12" + id="circle48" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Kent" + cx="1562.2502" + cy="1444.588" + r="12" + id="circle50" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Lincoln" + cx="1304.6338" + cy="801.10284" + r="12" + id="circle52" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Middlesex" + cx="1382.402" + cy="1391.8545" + r="12" + id="circle54" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Northumbria" + cx="951.58667" + cy="247.53162" + r="12" + id="circle56" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="North Sea / Rutland" + cx="1298.3813" + cy="965.31958" + r="12" + id="circle58" + style="fill:#3b4dcf;fill-opacity:1" /> + <circle + inkscape:label="Scotland / Cumbria" + cx="679.41974" + cy="247.78326" + r="12" + id="circle60" /> + <circle + inkscape:label="Scotland / Northumbria" + cx="774.32373" + cy="171.45955" + r="12" + id="circle62" /> + <circle + inkscape:label="Caernarvon / Chester" + cx="677.22357" + cy="919.91083" + r="12" + id="circle64" /> + <circle + inkscape:label="Caernarvon / Pembroke" + cx="479.18152" + cy="1071.2867" + r="12" + id="circle66" /> + <circle + inkscape:label="Caernarvon / Powys" + cx="522" + cy="995" + r="12" + id="circle68" /> + <circle + inkscape:label="Chester / Derby" + cx="841.73511" + cy="878.95709" + r="12" + id="circle70" /> + <circle + inkscape:label="Chester / Hereford" + cx="717" + cy="1012" + r="12" + id="circle72" /> + <circle + inkscape:label="Chester / Lancaster" + cx="762.40192" + cy="794.37726" + r="12" + id="circle74" /> + <circle + inkscape:label="Chester / Powys" + cx="610.23871" + cy="986.29907" + r="12" + id="circle76" /> + <circle + inkscape:label="Chester / Warwick" + cx="793.16736" + cy="981.92181" + r="12" + id="circle78" /> + <circle + inkscape:label="Cornwall / Dorset" + cx="613.08881" + cy="1626.8434" + r="12" + id="circle80" /> + <circle + inkscape:label="Cornwall / Somerset" + cx="528.29218" + cy="1573.7902" + r="12" + id="circle82" /> + <circle + inkscape:label="Cumbria / Lancaster" + cx="739.91083" + cy="517.10699" + r="12" + id="circle84" /> + <circle + inkscape:label="Cumbria / North Yorks" + cx="819.25238" + cy="478.09601" + r="12" + id="circle86" /> + <circle + inkscape:label="Cumbria / Northumbria" + cx="782" + cy="342" + r="12" + id="circle88" /> + <circle + inkscape:label="Derby / Lancaster" + cx="880.53363" + cy="784.37726" + r="12" + id="circle90" /> + <circle + inkscape:label="Derby / Leicester" + cx="1029.3416" + cy="943.33472" + r="12" + id="circle92" /> + <circle + inkscape:label="Derby / Lincoln" + cx="1098.0782" + cy="840.03564" + r="12" + id="circle94" /> + <circle + inkscape:label="Derby / South Yorks" + cx="986.32373" + cy="814.30591" + r="12" + id="circle96" /> + <circle + inkscape:label="Derby / Warwick" + cx="877.66943" + cy="980.64062" + r="12" + id="circle98" /> + <circle + inkscape:label="Dorset / Somerset" + cx="716.47736" + cy="1566.2812" + r="12" + id="circle100" /> + <circle + inkscape:label="Dorset / Sussex" + cx="964.68726" + cy="1581.8723" + r="12" + id="circle102" /> + <circle + inkscape:label="Dorset / Wilts" + cx="878.70093" + cy="1558.0961" + r="12" + id="circle104" /> + <circle + inkscape:label="East Anglia / Essex" + cx="1452.0713" + cy="1167.5514" + r="12" + id="circle106" /> + <circle + inkscape:label="East Anglia / Rutland" + cx="1354.4843" + cy="1041.9039" + r="12" + id="circle108" /> + <circle + inkscape:label="East Yorks / North Yorks" + cx="971.37036" + cy="520.69409" + r="12" + id="circle110" /> + <circle + inkscape:label="East Yorks / Northumbria" + cx="997.01782" + cy="430.68314" + r="12" + id="circle112" /> + <circle + inkscape:label="East Yorks / South Yorks" + cx="1038.9218" + cy="654.40192" + r="12" + id="circle114" /> + <circle + inkscape:label="Essex / Leicester" + cx="1217.6516" + cy="1164.9644" + r="12" + id="circle116" /> + <circle + inkscape:label="Essex / Middlesex" + cx="1299.6338" + cy="1261.3169" + r="12" + id="circle118" /> + <circle + inkscape:label="Essex / Rutland" + cx="1286.609" + cy="1132.0891" + r="12" + id="circle120" /> + <circle + inkscape:label="Glamorgan / Hereford" + cx="711.75031" + cy="1225.7545" + r="12" + id="circle122" /> + <circle + inkscape:label="Glamorgan / Pembroke" + cx="447.43951" + cy="1273.673" + r="12" + id="circle124" /> + <circle + inkscape:label="Glamorgan / Powys" + cx="562.64062" + cy="1195.0713" + r="12" + id="circle126" /> + <circle + inkscape:label="Gloucester / Hereford" + cx="799.41571" + cy="1282.0376" + r="12" + id="circle128" /> + <circle + inkscape:label="Gloucester / Oxford" + cx="955.68311" + cy="1253.8971" + r="12" + id="circle130" /> + <circle + inkscape:label="Gloucester / Somerset" + cx="786.47028" + cy="1396.5815" + r="12" + id="circle132" /> + <circle + inkscape:label="Gloucester / Warwick" + cx="881.19202" + cy="1208.0782" + r="12" + id="circle134" /> + <circle + inkscape:label="Gloucester / Wilts" + cx="913.00684" + cy="1351.3525" + r="12" + id="circle136" /> + <circle + inkscape:label="Hereford / Powys" + cx="640" + cy="1112" + r="12" + id="circle138" /> + <circle + inkscape:label="Hereford / Warwick" + cx="792.65845" + cy="1126.9287" + r="12" + id="circle140" /> + <circle + inkscape:label="Kent / Middlesex" + cx="1329.3594" + cy="1401.3594" + r="12" + id="circle142" /> + <circle + inkscape:label="Kent / Sussex" + cx="1275.7544" + cy="1509.413" + r="12" + id="circle144" /> + <circle + inkscape:label="Lancaster / North Yorks" + cx="790.7298" + cy="622.5871" + r="12" + id="circle146" /> + <circle + inkscape:label="Lancaster / South Yorks" + cx="880.07819" + cy="700.62274" + r="12" + id="circle148" /> + <circle + inkscape:label="Leicester / Lincoln" + cx="1145" + cy="937" + r="12" + id="circle150" /> + <circle + inkscape:label="Leicester / Middlesex" + cx="1157" + cy="1180" + r="12" + id="circle152" /> + <circle + inkscape:label="Leicester / Oxford" + cx="1050.7723" + cy="1172.6228" + r="12" + id="circle154" /> + <circle + inkscape:label="Leicester / Rutland" + cx="1172" + cy="1057" + r="12" + id="circle156" /> + <circle + inkscape:label="Leicester / Warwick" + cx="974.4129" + cy="1048.3347" + r="12" + id="circle158" /> + <circle + inkscape:label="Lincoln / Rutland" + cx="1211.4664" + cy="967.40192" + r="12" + id="circle160" /> + <circle + inkscape:label="Lincoln / South Yorks" + cx="1111.3237" + cy="741.33472" + r="12" + id="circle162" /> + <circle + inkscape:label="Middlesex / Oxford" + cx="1138.4268" + cy="1298.3546" + r="12" + id="circle164" /> + <circle + inkscape:label="Middlesex / Sussex" + cx="1152.1249" + cy="1412.6763" + r="12" + id="circle166" /> + <circle + inkscape:label="North Yorks / Northumbria" + cx="905.06036" + cy="434.40192" + r="12" + id="circle168" /> + <circle + inkscape:label="North Yorks / South Yorks" + cx="938.86829" + cy="611.4129" + r="12" + id="circle170" /> + <circle + inkscape:label="Oxford / Sussex" + cx="1084.5089" + cy="1404.4308" + r="12" + id="circle172" /> + <circle + inkscape:label="Oxford / Warwick" + cx="975.07819" + cy="1127.7229" + r="12" + id="circle174" /> + <circle + inkscape:label="Oxford / Wilts" + cx="1032.4266" + cy="1363.1674" + r="12" + id="circle176" /> + <circle + inkscape:label="Pembroke / Powys" + cx="517.39093" + cy="1141.3169" + r="12" + id="circle178" /> + <circle + inkscape:label="Somerset / Wilts" + cx="838.11383" + cy="1451.9932" + r="12" + id="circle180" /> + <circle + inkscape:label="Sussex / Wilts" + cx="1017.5446" + cy="1495.0356" + r="12" + id="circle182" /> +</svg> diff --git a/tools/coord.js b/tools/coord.js new file mode 100644 index 0000000..5776990 --- /dev/null +++ b/tools/coord.js @@ -0,0 +1,7 @@ +for (let row=1; row<=9; ++row) { + let y = -(row-1) * 62 + for (let col=1; col<=7; ++col) { + let x = -(col-1) * 62 + console.log(`.known.block_${row}${col}{background-position:${x}px ${y}px}`) + } +} diff --git a/tools/genborders.js b/tools/genborders.js new file mode 100644 index 0000000..f639e8a --- /dev/null +++ b/tools/genborders.js @@ -0,0 +1,53 @@ +const fs = require("fs") + +const { round, floor, ceil } = Math + +let output = {} +let mode, name, x, y, w, h, cx, cy, rx, ry + +function flush() { + if (mode === 'circle') { + output[name] = [ cx, cy ] + } + x = y = w = h = cx = cy = rx = ry = 0 + name = null +} + +for (let line of fs.readFileSync("tools/borders.svg", "utf-8").split("\n")) { + line = line.trim() + if (line.startsWith("<rect")) { + flush() + mode = "rect" + x = y = w = h = 0 + } else if (line.startsWith("<ellipse") || line.startsWith("<circle")) { + flush() + mode = "circle" + cx = cy = rx = ry = 0 + } else if (line.startsWith('x="')) + x = round(Number(line.split('"')[1])) + else if (line.startsWith('y="')) + y = round(Number(line.split('"')[1])) + else if (line.startsWith('width="')) + w = round(Number(line.split('"')[1])) + else if (line.startsWith('height="')) + h = round(Number(line.split('"')[1])) + else if (line.startsWith('cx="')) + cx = round(Number(line.split('"')[1])) + else if (line.startsWith('cy="')) + cy = round(Number(line.split('"')[1])) + else if (line.startsWith('r="')) + rx = ry = round(Number(line.split('"')[1])) + else if (line.startsWith('rx="')) + rx = round(Number(line.split('"')[1])) + else if (line.startsWith('ry="')) + ry = round(Number(line.split('"')[1])) + else if (line.startsWith('inkscape:label="')) + name = line.split('"')[1] +} + +flush() + +console.log("const BORDERS_XY = {") +for (let key in output) + console.log("\t\"" + key + "\": " + JSON.stringify(output[key]) + ",") +console.log("}") diff --git a/tools/makeborders.js b/tools/makeborders.js new file mode 100644 index 0000000..2dfdbd5 --- /dev/null +++ b/tools/makeborders.js @@ -0,0 +1,29 @@ +const print = console.log + +const data = require("../data.js") + +var w = 1688 +var h = 1950 +var m = "../map75.png" + +print(`<?xml version="1.0" encoding="UTF-8"?> +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="${w}" + height="${h}" +> +<image xlink:href="${m}" x="0" y="0" width="${w}" height="${h}" image-rendering="pixelated" sodipodi:insensitive="true" />`) + +for (let id in data.BORDERS) { + let a = (id / 100) | 0 + let b = id % 100 + let x = (data.AREAS[a].layout.x + data.AREAS[b].layout.x) >> 1 + let y = (data.AREAS[a].layout.y + data.AREAS[b].layout.y) >> 1 + let label = data.AREAS[a].name + " / " + data.AREAS[b].name + print(`<circle inkscape:label="${label}" cx="${x}" cy="${y}" r="12"/>`) +} + +print(`</svg>`) diff --git a/tools/slice.sh b/tools/slice.sh new file mode 100644 index 0000000..8053af7 --- /dev/null +++ b/tools/slice.sh @@ -0,0 +1,16 @@ +# white ffffff +# red eb2127 + +pnmcut -left 247 -top 394 -width 1736 -height 2232 tools/labels.ppm | pnmtopng > blocks300.png + +exit + +i=1 +for y in 394 642 890 1138 1386 1634 1882 2130 2378 +do + for x in 247 495 743 991 1239 1487 1735 + do + pnmcut -left $x -top $y -width 248 -height 248 tools/labels.ppm > tools/b$i.ppm + i=$(expr $i + 1) + done +done |