summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-06-10 01:25:36 +0200
committerTor Andersson <tor@ccxvii.net>2024-08-21 00:28:20 +0200
commit5a458a5a578445d70356b23c998fe3b8cbe909ec (patch)
tree5d9293badfcbae3f1dbc7a4a15eab40b5702f038 /tools
parent5eb2975315a50c585eb048479c4fdc765a24a20c (diff)
downloadwashingtons-war-5a458a5a578445d70356b23c998fe3b8cbe909ec.tar.gz
stuff
Diffstat (limited to 'tools')
-rw-r--r--tools/gendata.js488
-rw-r--r--tools/layout.json3728
-rw-r--r--tools/layout.svg343
-rw-r--r--tools/parse-layout-old.js466
-rw-r--r--tools/parse-layout.js325
-rw-r--r--tools/process-layout.js164
-rw-r--r--tools/rotate_year.sh8
7 files changed, 5078 insertions, 444 deletions
diff --git a/tools/gendata.js b/tools/gendata.js
new file mode 100644
index 0000000..72379ec
--- /dev/null
+++ b/tools/gendata.js
@@ -0,0 +1,488 @@
+"use strict"
+
+const fs = require("fs")
+
+let data = JSON.parse(fs.readFileSync("tools/data.json", "utf-8"))
+
+function make_index_from_list(list) {
+ let map = {}
+ for (let i = 0; i < list.length; ++i)
+ map[list[i]] = i
+ return map
+}
+
+/* GENERALS */
+
+data.generals = [
+ { name: "Arnold", owner: "American", strategy: 1, battle: 3, agility: 2, bonus: false },
+ { name: "Gates", owner: "American", strategy: 2, battle: 2, agility: 1, bonus: false },
+ { name: "Greene", owner: "American", strategy: 1, battle: 4, agility: 2, bonus: true },
+ { name: "Lafayette", owner: "American", strategy: 1, battle: 2, agility: 1, bonus: false },
+ { name: "Lee", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
+ { name: "Lincoln", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
+ { name: "Washington", owner: "American", strategy: 1, battle: 5, agility: 2, bonus: true },
+
+ { name: "Rochambeau", owner: "French", strategy: 2, battle: 4, agility: 2, bonus: false },
+
+ { name: "Burgoyne", owner: "British", strategy: 2, battle: 2, agility: 1, bonus: false },
+ { name: "Carleton", owner: "British", strategy: 3, battle: 3, agility: 2, bonus: false },
+ { name: "Clinton", owner: "British", strategy: 3, battle: 4, agility: 2, bonus: false },
+ { name: "Cornwallis", owner: "British", strategy: 2, battle: 4, agility: 2, bonus: false },
+ { name: "Howe", owner: "British", strategy: 3, battle: 6, agility: 3, bonus: false },
+]
+
+data.general_index = make_index_from_list(data.generals.map(x=>x.name))
+
+/* COLONIES */
+
+data.colony_name = [ "Canada", "NH", "NY", "MA", "CT", "RI", "PA", "NJ", "MD", "DE", "VA", "NC", "SC", "GA" ]
+
+const Canada = 0
+const NH = 1
+const NY = 2
+const MA = 3
+const CT = 4
+const RI = 5
+const PA = 6
+const NJ = 7
+const MD = 8
+const DE = 9
+const VA = 10
+const NC = 11
+const SC = 12
+const GA = 13
+
+/* CARDS */
+
+const CARD_3_OPS = { title: "3 OPS", type: "ops", count: 3 }
+const CARD_2_OPS = { title: "2 OPS", type: "ops", count: 2 }
+const CARD_1_OPS = { title: "1 OPS", type: "ops", count: 1 }
+
+data.cards = [
+ null,
+
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+
+ /* 67 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 68 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 69 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 70 */
+ {
+ title: "Major Campaign",
+ type: "campaign",
+ count: 3,
+ },
+
+ /* 71 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1779",
+ title: "The War Ends in 1779",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1779,
+ },
+
+ /* 72 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1780",
+ title: "The War Ends in 1780",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1780,
+ },
+
+ /* 73 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1781",
+ title: "The War Ends in 1781",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1781,
+ },
+
+ /* 74 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1782",
+ title: "The War Ends in 1782",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1782,
+ },
+
+ /* 75 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1783",
+ title: "The War Ends in 1783",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1783,
+ },
+
+ /* 76 */
+ {
+ title: "Henry Know Continental Artillery Commander",
+ type: "american-battle",
+ },
+
+ /* 77 */
+ {
+ title: "Jane McCrea Indian Atrocity Sparks Outrage",
+ type: "american-event",
+ event: "place_american_pc",
+ count: 2,
+ once: true,
+ },
+
+ /* 78 */
+ {
+ title: "Iroquois Uprising!",
+ type: "british-event",
+ event: "remove_american_pc_from_non_port",
+ where: [ NH, NY, PA ],
+ count: 2,
+ },
+
+ /* 79 */
+ {
+ title: "Joseph Brant Leads an Iroquois Raid",
+ type: "british-event",
+ event: "remove_american_pc_from_non_port",
+ where: [ NH, NY, PA ],
+ count: 2,
+ },
+
+ /* 80 */
+ {
+ title: "Lt. Colonel Simcoe's Queen's Rangers",
+ type: "british-event",
+ event: "remove_american_pc_within_two_spaces_of_a_british_general",
+ count: 2,
+ },
+
+ /* 81 */
+ {
+ title: "D'Estaing Sails for the Caribbean",
+ type: "british-event",
+ when: "after_french_alliance",
+ event: "remove_french_navy",
+ },
+
+ /* 82 */
+ {
+ title: "Banastre Tarleton's Waxhaws Massacre",
+ type: "british-event-or-battle",
+ event: "remove_american_cu",
+ },
+
+ /* 83 */
+ {
+ title: "Lord George Germaine Offers Royal Amnesty",
+ type: "british-event",
+ event: "remove_american_pc",
+ count: 2,
+ },
+
+ /* 84 */
+ {
+ title: "George Rogers Clark Leads a Western Offensive",
+ type: "american-event",
+ event: "remove_random_british_card",
+ },
+
+ /* 85 */
+ {
+ title: "Don Bernardo Galvez Captures Pensacola",
+ type: "american-event",
+ when: "european_war_in_effect",
+ event: "remove_british_cu",
+ count: 2,
+ },
+
+ /* 86 */
+ {
+ title: "Baron von Steuben Trains the Continental Army",
+ type: "american-event",
+ event: "baron_von_steuben_trains_the_continental_army",
+ },
+
+ /* 87 */
+ {
+ title: "Lord North Offers a Royal Amnesty",
+ type: "british-event",
+ event: "remove_american_pc",
+ count: 4,
+ once: true,
+ },
+
+ /* 88 */
+ {
+ title: "The Swamp Fox, Francis Marion",
+ type: "american-event",
+ event: "remove_british_pc_from",
+ where: [ NC, SC, GA ],
+ count: 2,
+ },
+
+ /* 89 */
+ {
+ title: "The Gamecock: Thomas Sumter",
+ type: "american-event",
+ event: "remove_british_pc_from",
+ where: [ NC, SC, GA ],
+ count: 2,
+ },
+
+ /* 90 */
+ {
+ title: "Josiah Martin Rallies North Carolina Loyalists",
+ type: "british-event",
+ event: "remove_american_pc_from",
+ where: [ NC ],
+ count: 2,
+ },
+
+ /* 91 */
+ {
+ title: 'Thomas Paine Publishes Pamphlets "Common Sense" and "The American Crisis"',
+ type: "american-event",
+ event: "place_american_pc_in",
+ where: [ NH, NY, MA, CT, RI, PA, NJ, MD, DE, VA, NC, SC, GA ],
+ count: 3,
+ once: true,
+ },
+
+ /* 92 */
+ {
+ title: "Nathan Hale, American Martyr",
+ type: "american-event",
+ event: "place_american_pc",
+ count: 2,
+ once: true,
+ },
+
+ /* 93 */
+ {
+ title: "John Glover's Marblehead Regiment",
+ type: "american-event",
+ event: "john_glovers_marblehead_regiment",
+ },
+
+ /* 94 */
+ {
+ title: "Pennsylvania and New Jersey Line Mutinies",
+ type: "british-event",
+ event: "pennsylvania_and_new_jersey_line_mutinies",
+ },
+
+ /* 95 */
+ {
+ title: "William Pitt Urges Peace Talks",
+ type: "british-event",
+ when: "before_french_alliance",
+ event: "remove_american_pc",
+ count: 2,
+ reshuffle: "if_played",
+ },
+
+ /* 96 */
+ {
+ title: "Hortelez et Cie: Clandestine French and Spanish Aid",
+ type: "american-event",
+ when: "before_french_alliance",
+ event: "advance_french_alliance",
+ reshuffle: "if_discarded",
+ count: 2,
+ },
+
+ /* 97 */
+ {
+ title: "Admiral Suffren Wins a Naval Victory",
+ type: "american-event",
+ when: "after_french_alliance",
+ event: "remove_random_british_card",
+ },
+
+ /* 98 */
+ {
+ title: '"Mad" Anthony Wayne',
+ type: "american-battle",
+ },
+
+ /* 99 */
+ {
+ title: "Declaration of Independence",
+ type: "mandatory-event",
+ event: "declaration_of_independence",
+ once: true,
+ reshuffle: "if_played",
+ tournament: true,
+ },
+
+ /* 100 */
+ {
+ title: "Benedict Arnold's Treason Undermines the Patriot Cause",
+ type: "british-battle",
+ event: "remove_benedict_arnold",
+ once: true,
+ },
+
+ /* 101 */
+ {
+ title: "Benjamin Franklin: Minister to France",
+ type: "mandatory-event",
+ event: "advance_french_alliance",
+ count: 4,
+ once: true,
+ tournament: true,
+ },
+
+ /* 102 */
+ {
+ title: "Admiral Rodney Captures St. Eustatius",
+ type: "british-event",
+ event: "remove_random_american_card",
+ when: "european_war_in_effect",
+ once: true,
+ },
+
+ /* 103 */
+ {
+ title: "Thaddeus Kosciuszco Constructs Engineering Works",
+ type: "american-battle",
+ },
+
+ /* 104 */
+ {
+ title: "Light Horse Harry Lee",
+ type: "american-battle",
+ },
+
+ /* 105 */
+ {
+ title: "Morgan's Riflemen",
+ type: "american-battle",
+ },
+
+ /* 106 */
+ {
+ title: "John Paul Jones' Shipping Raids",
+ type: "american-event",
+ event: "remove_random_british_card",
+ },
+
+ /* 107 */
+ {
+ title: "British Light Infantry",
+ type: "british-battle",
+ },
+
+ /* 108 */
+ {
+ title: "Lord Sandwich Coastal Raids",
+ type: "british-event",
+ event: "lord_sandwich_coastal_raids",
+ },
+
+ /* 109 */
+ {
+ title: "Edward Bancroft, British Double Agent",
+ type: "british-event",
+ event: "remove_random_american_card",
+ },
+
+ /* 110 */
+ {
+ title: "Hessian Infantry Bayonet Charge",
+ type: "british-battle",
+ },
+]
+
+/* OUTPUT */
+
+console.log("const data = " + JSON.stringify(data,0,'\t'))
+console.log("if (typeof module === 'object') module.exports = data")
diff --git a/tools/layout.json b/tools/layout.json
new file mode 100644
index 0000000..78b8e34
--- /dev/null
+++ b/tools/layout.json
@@ -0,0 +1,3728 @@
+{
+ "boxes": {
+ "fortified_port": [
+ {
+ "x": 450,
+ "y": 2052,
+ "w": 68,
+ "h": 68,
+ "name": "Charleston"
+ },
+ {
+ "x": 852,
+ "y": 964,
+ "w": 68,
+ "h": 67,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 1006,
+ "y": 161,
+ "w": 68,
+ "h": 68,
+ "name": "Montreal"
+ },
+ {
+ "x": 1129,
+ "y": 60,
+ "w": 67,
+ "h": 67,
+ "name": "Quebec"
+ }
+ ],
+ "winter_quarters": [
+ {
+ "x": 995,
+ "y": 353,
+ "w": 79,
+ "h": 79,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 1126,
+ "y": 339,
+ "w": 79,
+ "h": 79,
+ "name": "Norwich"
+ },
+ {
+ "x": 878,
+ "y": 481,
+ "w": 79,
+ "h": 79,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 967,
+ "y": 624,
+ "w": 79,
+ "h": 79,
+ "name": "Albany"
+ },
+ {
+ "x": 1097,
+ "y": 622,
+ "w": 79,
+ "h": 78,
+ "name": "Springfield"
+ },
+ {
+ "x": 1328,
+ "y": 590,
+ "w": 79,
+ "h": 78,
+ "name": "Boston"
+ },
+ {
+ "x": 1291,
+ "y": 733,
+ "w": 78,
+ "h": 79,
+ "name": "Newport"
+ },
+ {
+ "x": 1185,
+ "y": 747,
+ "w": 78,
+ "h": 78,
+ "name": "Hartford"
+ },
+ {
+ "x": 1025,
+ "y": 835,
+ "w": 79,
+ "h": 79,
+ "name": "New York"
+ },
+ {
+ "x": 687,
+ "y": 745,
+ "w": 78,
+ "h": 78,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 441,
+ "y": 955,
+ "w": 78,
+ "h": 79,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 887,
+ "y": 1077,
+ "w": 78,
+ "h": 79,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 771,
+ "y": 1103,
+ "w": 79,
+ "h": 79,
+ "name": "Baltimore"
+ },
+ {
+ "x": 654,
+ "y": 1215,
+ "w": 79,
+ "h": 78,
+ "name": "Alexandria"
+ },
+ {
+ "x": 610,
+ "y": 1321,
+ "w": 78,
+ "h": 78,
+ "name": "Richmond"
+ },
+ {
+ "x": 436,
+ "y": 1254,
+ "w": 78,
+ "h": 79,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 783,
+ "y": 1448,
+ "w": 78,
+ "h": 79,
+ "name": "Norfolk"
+ }
+ ],
+ "regular": [
+ {
+ "x": 226.5,
+ "y": 2266.5,
+ "w": 81,
+ "h": 81,
+ "name": "Savannah"
+ },
+ {
+ "x": 139.01387,
+ "y": 2055.9861,
+ "w": 81,
+ "h": 81,
+ "name": "Augusta"
+ },
+ {
+ "x": 222.01385,
+ "y": 1927.5,
+ "w": 81,
+ "h": 81,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 403.05807,
+ "y": 1901.0138,
+ "w": 81,
+ "h": 81,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 573.5592,
+ "y": 1910.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Georgetown"
+ },
+ {
+ "x": 675.0592,
+ "y": 1811.8098,
+ "w": 81,
+ "h": 81,
+ "name": "Wilmington"
+ },
+ {
+ "x": 495.05920000000003,
+ "y": 1790.0598,
+ "w": 81,
+ "h": 81,
+ "name": "Cheraw"
+ },
+ {
+ "x": 345.3092,
+ "y": 1768.3098,
+ "w": 81,
+ "h": 81,
+ "name": "Camden"
+ },
+ {
+ "x": 605.8092,
+ "y": 1666.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 763.3092,
+ "y": 1665.5598,
+ "w": 81,
+ "h": 81,
+ "name": "New Bern"
+ },
+ {
+ "x": 483.55920000000003,
+ "y": 1577.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 308.3092,
+ "y": 1556.0598,
+ "w": 81,
+ "h": 81,
+ "name": "Salem"
+ },
+ {
+ "x": 214.5592,
+ "y": 1648.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Charlotte"
+ },
+ {
+ "x": 122.3092,
+ "y": 1563.3098,
+ "w": 81,
+ "h": 81,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 73.5592,
+ "y": 1768.8098,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 60.260580000000004,
+ "y": 1446.7491,
+ "w": 81,
+ "h": 81,
+ "name": "Abingdon"
+ },
+ {
+ "x": 211.40466,
+ "y": 1403.6156,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 348.58337,
+ "y": 1397.2516,
+ "w": 81,
+ "h": 81,
+ "name": "Fincastle"
+ },
+ {
+ "x": 485.93884,
+ "y": 1439.1477,
+ "w": 81,
+ "h": 81,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 634.07404,
+ "y": 1441.644,
+ "w": 81,
+ "h": 81,
+ "name": "Petersburg"
+ },
+ {
+ "x": 766.12952,
+ "y": 1312.0383,
+ "w": 81,
+ "h": 81,
+ "name": "Yorktown"
+ },
+ {
+ "x": 131.70384,
+ "y": 1213.4077,
+ "w": 81,
+ "h": 81,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 146.95384,
+ "y": 979.7827,
+ "w": 81,
+ "h": 81,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 446.21503,
+ "y": 1093.475,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Cumberland"
+ },
+ {
+ "x": 645.7276,
+ "y": 1092.4473,
+ "w": 81,
+ "h": 81,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 588.75372,
+ "y": 987.3384000000001,
+ "w": 81,
+ "h": 81,
+ "name": "York"
+ },
+ {
+ "x": 683.25372,
+ "y": 895.58838,
+ "w": 81,
+ "h": 81,
+ "name": "Reading"
+ },
+ {
+ "x": 554.00372,
+ "y": 875.33838,
+ "w": 81,
+ "h": 81,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 863.60297,
+ "y": 826.91376,
+ "w": 81,
+ "h": 81,
+ "name": "Morristown"
+ },
+ {
+ "x": 960.8301,
+ "y": 937.04565,
+ "w": 81,
+ "h": 81,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 996.8300999999999,
+ "y": 1069.7957,
+ "w": 81,
+ "h": 81,
+ "name": "Monmouth"
+ },
+ {
+ "x": 1145.8301,
+ "y": 863.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Long Island"
+ },
+ {
+ "x": 1087.5801,
+ "y": 731.54565,
+ "w": 81,
+ "h": 81,
+ "name": "New Haven"
+ },
+ {
+ "x": 954.33008,
+ "y": 742.29565,
+ "w": 81,
+ "h": 81,
+ "name": "Westchester"
+ },
+ {
+ "x": 1217.8301,
+ "y": 623.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1393.8301,
+ "y": 700.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1333.5618,
+ "y": 405.97501,
+ "w": 81,
+ "h": 81,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1213.5618,
+ "y": 456.47501,
+ "w": 81,
+ "h": 81,
+ "name": "Concord"
+ },
+ {
+ "x": 1100.8118,
+ "y": 481.97504000000004,
+ "w": 81,
+ "h": 81,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 991.3118,
+ "y": 491.22504000000004,
+ "w": 81,
+ "h": 81,
+ "name": "Saratoga"
+ },
+ {
+ "x": 767.56177,
+ "y": 419.47504,
+ "w": 81,
+ "h": 81,
+ "name": "Oswego"
+ },
+ {
+ "x": 667.56177,
+ "y": 577.97504,
+ "w": 81,
+ "h": 81,
+ "name": "Genesee"
+ },
+ {
+ "x": 461.06177,
+ "y": 521.47504,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 54.828918,
+ "y": 667.84613,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 179.39716,
+ "y": 2389.0383,
+ "w": 81,
+ "h": 81,
+ "name": "St. Mary's"
+ }
+ ],
+ "sea": [
+ {
+ "x": 351,
+ "y": 2352,
+ "w": 97,
+ "h": 83,
+ "name": "Sea7"
+ },
+ {
+ "x": 629,
+ "y": 2022,
+ "w": 97,
+ "h": 83,
+ "name": "Sea6"
+ },
+ {
+ "x": 938,
+ "y": 1389,
+ "w": 97,
+ "h": 83,
+ "name": "Sea5"
+ },
+ {
+ "x": 1049,
+ "y": 1169,
+ "w": 97,
+ "h": 83,
+ "name": "Sea4"
+ },
+ {
+ "x": 1205,
+ "y": 975,
+ "w": 97,
+ "h": 83,
+ "name": "Sea3"
+ },
+ {
+ "x": 1461,
+ "y": 508,
+ "w": 97,
+ "h": 84,
+ "name": "Sea2"
+ },
+ {
+ "x": 1268,
+ "y": 60,
+ "w": 97,
+ "h": 83,
+ "name": "Sea1"
+ }
+ ],
+ "colony": [
+ {
+ "x": 1171,
+ "y": 1558,
+ "w": 66,
+ "h": 57,
+ "name": "GA"
+ },
+ {
+ "x": 1218,
+ "y": 1486,
+ "w": 67,
+ "h": 58,
+ "name": "SC"
+ },
+ {
+ "x": 1267,
+ "y": 1415,
+ "w": 66,
+ "h": 57,
+ "name": "NC"
+ },
+ {
+ "x": 1248,
+ "y": 1344,
+ "w": 67,
+ "h": 58,
+ "name": "VA"
+ },
+ {
+ "x": 1306,
+ "y": 1274,
+ "w": 66,
+ "h": 57,
+ "name": "MD"
+ },
+ {
+ "x": 1383,
+ "y": 1274,
+ "w": 66,
+ "h": 57,
+ "name": "DE"
+ },
+ {
+ "x": 1306,
+ "y": 1201,
+ "w": 66,
+ "h": 58,
+ "name": "PA"
+ },
+ {
+ "x": 1383,
+ "y": 1196,
+ "w": 66,
+ "h": 58,
+ "name": "NJ"
+ },
+ {
+ "x": 1462,
+ "y": 1163,
+ "w": 66,
+ "h": 58,
+ "name": "CT"
+ },
+ {
+ "x": 1540,
+ "y": 1163,
+ "w": 66,
+ "h": 58,
+ "name": "RI"
+ },
+ {
+ "x": 1498,
+ "y": 1088,
+ "w": 67,
+ "h": 58,
+ "name": "MA"
+ },
+ {
+ "x": 1382,
+ "y": 1089,
+ "w": 66,
+ "h": 58,
+ "name": "NY"
+ },
+ {
+ "x": 1465,
+ "y": 1014,
+ "w": 66,
+ "h": 58,
+ "name": "NH"
+ },
+ {
+ "x": 1383,
+ "y": 975,
+ "w": 66,
+ "h": 57,
+ "name": "Canada"
+ }
+ ],
+ "box": [
+ {
+ "x": 1358,
+ "y": 1673,
+ "w": 214,
+ "h": 206,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 294,
+ "y": 258,
+ "w": 214,
+ "h": 206,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 63,
+ "y": 258,
+ "w": 214,
+ "h": 207,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 542,
+ "y": 332,
+ "w": 88,
+ "h": 104,
+ "name": "Continental Congress Dispersed"
+ },
+ {
+ "x": 1400,
+ "y": 46,
+ "w": 205,
+ "h": 136,
+ "name": "Captured Generals"
+ }
+ ],
+ "Card Boxes": [
+ {
+ "x": 904,
+ "y": 1915,
+ "w": 199,
+ "h": 277,
+ "name": "BRC"
+ },
+ {
+ "x": 1137,
+ "y": 1915,
+ "w": 199,
+ "h": 277,
+ "name": "ARC1"
+ },
+ {
+ "x": 1370,
+ "y": 1915,
+ "w": 199.00003,
+ "h": 277,
+ "name": "ARC2"
+ },
+ {
+ "x": 1027,
+ "y": 1679,
+ "w": 278,
+ "h": 198.99998,
+ "name": "War Ends Card"
+ }
+ ],
+ "Game Turn": [
+ {
+ "x": 904,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1775"
+ },
+ {
+ "x": 970,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1776"
+ },
+ {
+ "x": 1036,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1777"
+ },
+ {
+ "x": 1102,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1778"
+ },
+ {
+ "x": 1168,
+ "y": 2368,
+ "w": 65,
+ "h": 72,
+ "name": "1779"
+ },
+ {
+ "x": 1235,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1780"
+ },
+ {
+ "x": 1301,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1781"
+ },
+ {
+ "x": 1367,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1782"
+ },
+ {
+ "x": 1433,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1783"
+ }
+ ],
+ "French Alliance Track": [
+ {
+ "x": 905,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "0"
+ },
+ {
+ "x": 971,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "1"
+ },
+ {
+ "x": 1037,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "2"
+ },
+ {
+ "x": 1103,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "3"
+ },
+ {
+ "x": 1169,
+ "y": 2241,
+ "w": 65,
+ "h": 71,
+ "name": "4"
+ },
+ {
+ "x": 1236,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "5"
+ },
+ {
+ "x": 1302,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "6"
+ },
+ {
+ "x": 1368,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "7"
+ },
+ {
+ "x": 1434,
+ "y": 2241,
+ "w": 65,
+ "h": 71,
+ "name": "8"
+ },
+ {
+ "x": 1501,
+ "y": 2241,
+ "w": 63,
+ "h": 71,
+ "name": "9"
+ }
+ ]
+ },
+ "points": {
+ "fortified_port": [
+ {
+ "x": 484,
+ "y": 2086,
+ "name": "Charleston"
+ },
+ {
+ "x": 886,
+ "y": 997.5,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 1040,
+ "y": 195,
+ "name": "Montreal"
+ },
+ {
+ "x": 1162.5,
+ "y": 93.5,
+ "name": "Quebec"
+ }
+ ],
+ "winter_quarters": [
+ {
+ "x": 1034.5,
+ "y": 392.5,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 1165.5,
+ "y": 378.5,
+ "name": "Norwich"
+ },
+ {
+ "x": 917.5,
+ "y": 520.5,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 1006.5,
+ "y": 663.5,
+ "name": "Albany"
+ },
+ {
+ "x": 1136.5,
+ "y": 661,
+ "name": "Springfield"
+ },
+ {
+ "x": 1367.5,
+ "y": 629,
+ "name": "Boston"
+ },
+ {
+ "x": 1330,
+ "y": 772.5,
+ "name": "Newport"
+ },
+ {
+ "x": 1224,
+ "y": 786,
+ "name": "Hartford"
+ },
+ {
+ "x": 1064.5,
+ "y": 874.5,
+ "name": "New York"
+ },
+ {
+ "x": 726,
+ "y": 784,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 480,
+ "y": 994.5,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 926,
+ "y": 1116.5,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 810.5,
+ "y": 1142.5,
+ "name": "Baltimore"
+ },
+ {
+ "x": 693.5,
+ "y": 1254,
+ "name": "Alexandria"
+ },
+ {
+ "x": 649,
+ "y": 1360,
+ "name": "Richmond"
+ },
+ {
+ "x": 475,
+ "y": 1293.5,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 822,
+ "y": 1487.5,
+ "name": "Norfolk"
+ }
+ ],
+ "regular": [
+ {
+ "x": 267,
+ "y": 2307,
+ "name": "Savannah"
+ },
+ {
+ "x": 179.51387,
+ "y": 2096.4861,
+ "name": "Augusta"
+ },
+ {
+ "x": 262.51385,
+ "y": 1968,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 443.55807,
+ "y": 1941.5138,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 614.0592,
+ "y": 1951.0598,
+ "name": "Georgetown"
+ },
+ {
+ "x": 715.5592,
+ "y": 1852.3098,
+ "name": "Wilmington"
+ },
+ {
+ "x": 535.5592,
+ "y": 1830.5598,
+ "name": "Cheraw"
+ },
+ {
+ "x": 385.8092,
+ "y": 1808.8098,
+ "name": "Camden"
+ },
+ {
+ "x": 646.3092,
+ "y": 1707.0598,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 803.8092,
+ "y": 1706.0598,
+ "name": "New Bern"
+ },
+ {
+ "x": 524.0592,
+ "y": 1618.0598,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 348.8092,
+ "y": 1596.5598,
+ "name": "Salem"
+ },
+ {
+ "x": 255.0592,
+ "y": 1689.0598,
+ "name": "Charlotte"
+ },
+ {
+ "x": 162.8092,
+ "y": 1603.8098,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 114.0592,
+ "y": 1809.3098,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 100.76058,
+ "y": 1487.2491,
+ "name": "Abingdon"
+ },
+ {
+ "x": 251.90466,
+ "y": 1444.1156,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 389.08337,
+ "y": 1437.7516,
+ "name": "Fincastle"
+ },
+ {
+ "x": 526.43884,
+ "y": 1479.6477,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 674.57404,
+ "y": 1482.144,
+ "name": "Petersburg"
+ },
+ {
+ "x": 806.62952,
+ "y": 1352.5383,
+ "name": "Yorktown"
+ },
+ {
+ "x": 172.20384,
+ "y": 1253.9077,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 187.45384,
+ "y": 1020.2827,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 486.71503,
+ "y": 1133.975,
+ "name": "Fort Cumberland"
+ },
+ {
+ "x": 686.2276,
+ "y": 1132.9473,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 629.25372,
+ "y": 1027.8384,
+ "name": "York"
+ },
+ {
+ "x": 723.75372,
+ "y": 936.08838,
+ "name": "Reading"
+ },
+ {
+ "x": 594.50372,
+ "y": 915.83838,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 904.10297,
+ "y": 867.41376,
+ "name": "Morristown"
+ },
+ {
+ "x": 1001.3301,
+ "y": 977.54565,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 1037.3301,
+ "y": 1110.2957,
+ "name": "Monmouth"
+ },
+ {
+ "x": 1186.3301,
+ "y": 904.04565,
+ "name": "Long Island"
+ },
+ {
+ "x": 1128.0801,
+ "y": 772.04565,
+ "name": "New Haven"
+ },
+ {
+ "x": 994.83008,
+ "y": 782.79565,
+ "name": "Westchester"
+ },
+ {
+ "x": 1258.3301,
+ "y": 664.04565,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1434.3301,
+ "y": 741.04565,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1374.0618,
+ "y": 446.47501,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1254.0618,
+ "y": 496.97501,
+ "name": "Concord"
+ },
+ {
+ "x": 1141.3118,
+ "y": 522.47504,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 1031.8118,
+ "y": 531.72504,
+ "name": "Saratoga"
+ },
+ {
+ "x": 808.06177,
+ "y": 459.97504,
+ "name": "Oswego"
+ },
+ {
+ "x": 708.06177,
+ "y": 618.47504,
+ "name": "Genesee"
+ },
+ {
+ "x": 501.56177,
+ "y": 561.97504,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 95.328918,
+ "y": 708.34613,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 219.89716,
+ "y": 2429.5383,
+ "name": "St. Mary's"
+ }
+ ],
+ "sea": [
+ {
+ "x": 399.5,
+ "y": 2393.5,
+ "name": "Sea7"
+ },
+ {
+ "x": 677.5,
+ "y": 2063.5,
+ "name": "Sea6"
+ },
+ {
+ "x": 986.5,
+ "y": 1430.5,
+ "name": "Sea5"
+ },
+ {
+ "x": 1097.5,
+ "y": 1210.5,
+ "name": "Sea4"
+ },
+ {
+ "x": 1253.5,
+ "y": 1016.5,
+ "name": "Sea3"
+ },
+ {
+ "x": 1509.5,
+ "y": 550,
+ "name": "Sea2"
+ },
+ {
+ "x": 1316.5,
+ "y": 101.5,
+ "name": "Sea1"
+ }
+ ],
+ "colony": [
+ {
+ "x": 1204,
+ "y": 1586.5,
+ "name": "GA"
+ },
+ {
+ "x": 1251.5,
+ "y": 1515,
+ "name": "SC"
+ },
+ {
+ "x": 1300,
+ "y": 1443.5,
+ "name": "NC"
+ },
+ {
+ "x": 1281.5,
+ "y": 1373,
+ "name": "VA"
+ },
+ {
+ "x": 1339,
+ "y": 1302.5,
+ "name": "MD"
+ },
+ {
+ "x": 1416,
+ "y": 1302.5,
+ "name": "DE"
+ },
+ {
+ "x": 1339,
+ "y": 1230,
+ "name": "PA"
+ },
+ {
+ "x": 1416,
+ "y": 1225,
+ "name": "NJ"
+ },
+ {
+ "x": 1495,
+ "y": 1192,
+ "name": "CT"
+ },
+ {
+ "x": 1573,
+ "y": 1192,
+ "name": "RI"
+ },
+ {
+ "x": 1531.5,
+ "y": 1117,
+ "name": "MA"
+ },
+ {
+ "x": 1415,
+ "y": 1118,
+ "name": "NY"
+ },
+ {
+ "x": 1498,
+ "y": 1043,
+ "name": "NH"
+ },
+ {
+ "x": 1416,
+ "y": 1003.5,
+ "name": "Canada"
+ }
+ ],
+ "box": [
+ {
+ "x": 1465,
+ "y": 1776,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 401,
+ "y": 361,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 170,
+ "y": 361.5,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 586,
+ "y": 384,
+ "name": "Continental Congress Dispersed"
+ },
+ {
+ "x": 1502.5,
+ "y": 114,
+ "name": "Captured Generals"
+ }
+ ],
+ "Card Boxes": [
+ {
+ "x": 1003.5,
+ "y": 2053.5,
+ "name": "BRC"
+ },
+ {
+ "x": 1236.5,
+ "y": 2053.5,
+ "name": "ARC1"
+ },
+ {
+ "x": 1469.500015,
+ "y": 2053.5,
+ "name": "ARC2"
+ },
+ {
+ "x": 1166,
+ "y": 1778.49999,
+ "name": "War Ends Card"
+ }
+ ],
+ "Game Turn": [
+ {
+ "x": 936,
+ "y": 2404,
+ "name": "1775"
+ },
+ {
+ "x": 1002,
+ "y": 2404,
+ "name": "1776"
+ },
+ {
+ "x": 1068,
+ "y": 2404,
+ "name": "1777"
+ },
+ {
+ "x": 1134,
+ "y": 2404,
+ "name": "1778"
+ },
+ {
+ "x": 1200.5,
+ "y": 2404,
+ "name": "1779"
+ },
+ {
+ "x": 1267,
+ "y": 2404,
+ "name": "1780"
+ },
+ {
+ "x": 1333,
+ "y": 2404,
+ "name": "1781"
+ },
+ {
+ "x": 1399,
+ "y": 2404,
+ "name": "1782"
+ },
+ {
+ "x": 1465,
+ "y": 2404,
+ "name": "1783"
+ }
+ ],
+ "French Alliance Track": [
+ {
+ "x": 937,
+ "y": 2276.5,
+ "name": "0"
+ },
+ {
+ "x": 1003,
+ "y": 2276.5,
+ "name": "1"
+ },
+ {
+ "x": 1069,
+ "y": 2276.5,
+ "name": "2"
+ },
+ {
+ "x": 1135,
+ "y": 2276.5,
+ "name": "3"
+ },
+ {
+ "x": 1201.5,
+ "y": 2276.5,
+ "name": "4"
+ },
+ {
+ "x": 1268,
+ "y": 2276.5,
+ "name": "5"
+ },
+ {
+ "x": 1334,
+ "y": 2276.5,
+ "name": "6"
+ },
+ {
+ "x": 1400,
+ "y": 2276.5,
+ "name": "7"
+ },
+ {
+ "x": 1466.5,
+ "y": 2276.5,
+ "name": "8"
+ },
+ {
+ "x": 1532.5,
+ "y": 2276.5,
+ "name": "9"
+ }
+ ]
+ },
+ "edges": {
+ "path": [
+ {
+ "x1": 227.01265,
+ "y1": 2390.0517,
+ "x2": 242.96720000000002,
+ "y2": 2339.5508,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "Savannah"
+ },
+ {
+ "x1": 199.02401,
+ "y1": 2132.0174,
+ "x2": 254.46493,
+ "y2": 2269.0997,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "Savannah"
+ },
+ {
+ "x1": 276.94694,
+ "y1": 2268.2133,
+ "x2": 450.40404,
+ "y2": 2099.316,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "Charleston"
+ },
+ {
+ "x1": 201.99439,
+ "y1": 2062.6086,
+ "x2": 241.40983,
+ "y2": 2001.6522,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "Ninety Six"
+ },
+ {
+ "x1": 145.20426,
+ "y1": 1830.9903,
+ "x2": 237.45150999999998,
+ "y2": 1937.1538,
+ "name": null,
+ "name1": "Fort Prince George",
+ "name2": "Ninety Six"
+ },
+ {
+ "x1": 284.32538,
+ "y1": 1934.4039,
+ "x2": 357.40648999999996,
+ "y2": 1837.6152,
+ "name": null,
+ "name1": "Ninety Six",
+ "name2": "Camden"
+ },
+ {
+ "x1": 404.96645,
+ "y1": 1843.7387,
+ "x2": 429.42317,
+ "y2": 1904.1378000000002,
+ "name": null,
+ "name1": "Camden",
+ "name2": "Eutaw Springs"
+ },
+ {
+ "x1": 460.98711,
+ "y1": 1978.2779,
+ "x2": 477.36157999999995,
+ "y2": 2045.6090000000002,
+ "name": null,
+ "name1": "Eutaw Springs",
+ "name2": "Charleston"
+ },
+ {
+ "x1": 496.23604,
+ "y1": 2051.5256,
+ "x2": 576.1504,
+ "y2": 1963.1115,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 646.98186,
+ "y1": 1928.7791,
+ "x2": 689.27224,
+ "y2": 1883.0305,
+ "name": null,
+ "name1": "Georgetown",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 556.73449,
+ "y1": 1865.4894,
+ "x2": 590.69173,
+ "y2": 1919.571,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 575.69233,
+ "y1": 1829.9903,
+ "x2": 676.98091,
+ "y2": 1842.365,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 425.11313,
+ "y1": 1812.7409,
+ "x2": 497.1111,
+ "y2": 1822.0322,
+ "name": null,
+ "name1": "Camden",
+ "name2": "Cheraw"
+ },
+ {
+ "x1": 286.90869,
+ "y1": 1713.7435,
+ "x2": 358.4066,
+ "y2": 1780.7,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "Camden"
+ },
+ {
+ "x1": 149.36454,
+ "y1": 1641.7822,
+ "x2": 120.95485000000001,
+ "y2": 1769.7419,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "Fort Prince George"
+ },
+ {
+ "x1": 91.330808,
+ "y1": 1526.2489,
+ "x2": 98.12225600000001,
+ "y2": 1772.4086,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Fort Prince George"
+ },
+ {
+ "x1": 193.54031,
+ "y1": 1630.0024,
+ "x2": 227.19063,
+ "y2": 1659.8424,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "Charlotte"
+ },
+ {
+ "x1": 278.7005,
+ "y1": 1656.8285,
+ "x2": 316.11605,
+ "y2": 1620.4962,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "Salem"
+ },
+ {
+ "x1": 385.32252,
+ "y1": 1600.0801,
+ "x2": 488.73627999999997,
+ "y2": 1612.1214,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Hillsboro"
+ },
+ {
+ "x1": 370.08352,
+ "y1": 1630.7156,
+ "x2": 509.69412,
+ "y2": 1800.5745,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Cheraw"
+ },
+ {
+ "x1": 669.35138,
+ "y1": 1740.1481,
+ "x2": 704.3551299999999,
+ "y2": 1813.8239,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 560.0883,
+ "y1": 1635.6726,
+ "x2": 619.77668,
+ "y2": 1677.2911000000001,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "Wake (Raleigh)"
+ },
+ {
+ "x1": 686.53009,
+ "y1": 1705.2652,
+ "x2": 763.91786,
+ "y2": 1704.3802,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "New Bern"
+ },
+ {
+ "x1": 672.10609,
+ "y1": 1522.7905,
+ "x2": 654.12084,
+ "y2": 1667.7282,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "Wake (Raleigh)"
+ },
+ {
+ "x1": 555.65124,
+ "y1": 1592.7885,
+ "x2": 647.69018,
+ "y2": 1511.7075000000002,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 714.73008,
+ "y1": 1482.1667,
+ "x2": 782.7696100000001,
+ "y2": 1484.375,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "Norfolk"
+ },
+ {
+ "x1": 822.35191,
+ "y1": 1526.7073,
+ "x2": 811.0189,
+ "y2": 1666.6615,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "New Bern"
+ },
+ {
+ "x1": 382.48926,
+ "y1": 1573.8725,
+ "x2": 494.40279,
+ "y2": 1501.6245,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 425.69638,
+ "y1": 1447.0844,
+ "x2": 489.44458999999995,
+ "y2": 1465.5004999999999,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 551.06786,
+ "y1": 1449.2093,
+ "x2": 610.61031,
+ "y2": 1393.6397,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "Richmond"
+ },
+ {
+ "x1": 662.68958,
+ "y1": 1398.8774,
+ "x2": 669.6478999999999,
+ "y2": 1442.3761000000002,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 564.95299,
+ "y1": 1489.0395,
+ "x2": 634.49253,
+ "y2": 1488.5332,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 687.89742,
+ "y1": 1388.0028,
+ "x2": 783.35299,
+ "y2": 1463.584,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Norfolk"
+ },
+ {
+ "x1": 687.6891,
+ "y1": 1357.2536,
+ "x2": 766.5200900000001,
+ "y2": 1354.1287,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Yorktown"
+ },
+ {
+ "x1": 654.48163,
+ "y1": 1323.1295,
+ "x2": 670.77284,
+ "y2": 1290.5471,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Alexandria"
+ },
+ {
+ "x1": 513.48556,
+ "y1": 1299.7969,
+ "x2": 610.02451,
+ "y2": 1338.5457000000001,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Richmond"
+ },
+ {
+ "x1": 504.31918,
+ "y1": 1333.0042,
+ "x2": 534.06834,
+ "y2": 1442.8345000000002,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 403.38632,
+ "y1": 1400.343,
+ "x2": 442.32085,
+ "y2": 1332.546,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "Charlottesville"
+ },
+ {
+ "x1": 186.99475,
+ "y1": 1293.3804,
+ "x2": 237.99332,
+ "y2": 1404.5856,
+ "name": null,
+ "name1": "Point Pleasant",
+ "name2": "Fort Chiswell"
+ },
+ {
+ "x1": 136.12124,
+ "y1": 1468.0004,
+ "x2": 211.86909,
+ "y2": 1448.4593,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Fort Chiswell"
+ },
+ {
+ "x1": 288.28357,
+ "y1": 1440.7096,
+ "x2": 351.32347,
+ "y2": 1440.0012,
+ "name": null,
+ "name1": "Fort Chiswell",
+ "name2": "Fincastle"
+ },
+ {
+ "x1": 137.20438,
+ "y1": 1503.9995,
+ "x2": 165.32871999999998,
+ "y2": 1564.081,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Gilbert Town"
+ },
+ {
+ "x1": 513.91845,
+ "y1": 1258.4465,
+ "x2": 651.77343,
+ "y2": 1152.0509,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Frederick Town"
+ },
+ {
+ "x1": 697.18887,
+ "y1": 1171.3421,
+ "x2": 699.64694,
+ "y2": 1214.8824,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Alexandria"
+ },
+ {
+ "x1": 732.5,
+ "y1": 1218.25,
+ "x2": 773,
+ "y2": 1180.25,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 726.27128,
+ "y1": 1134.3849,
+ "x2": 772.0616600000001,
+ "y2": 1136.1348,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 646.35681,
+ "y1": 1128.5516,
+ "x2": 526.5687,
+ "y2": 1131.7183,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Fort Cumberland"
+ },
+ {
+ "x1": 479.11158,
+ "y1": 1033.8876,
+ "x2": 481.27809,
+ "y2": 1094.6774,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Fort Cumberland"
+ },
+ {
+ "x1": 228.78524,
+ "y1": 1014.3049,
+ "x2": 440.57096,
+ "y2": 999.43028,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "Pittsburgh"
+ },
+ {
+ "x1": 518.94388,
+ "y1": 974.55593,
+ "x2": 562.69245,
+ "y2": 940.5152,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Harrisburg"
+ },
+ {
+ "x1": 619.31595,
+ "y1": 949.01496,
+ "x2": 628.64909,
+ "y2": 988.30569,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "York"
+ },
+ {
+ "x1": 663.85645,
+ "y1": 1006.0968,
+ "x2": 701.35537,
+ "y2": 969.8478600000001,
+ "name": null,
+ "name1": "York",
+ "name2": "Reading"
+ },
+ {
+ "x1": 759.31202,
+ "y1": 949.84833,
+ "x2": 850.2562499999999,
+ "y2": 985.27606,
+ "name": null,
+ "name1": "Reading",
+ "name2": "Philadelphia"
+ },
+ {
+ "x1": 908.63011,
+ "y1": 1030.8842,
+ "x2": 920.09917,
+ "y2": 1078.0530999999999,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Wilmington DE"
+ },
+ {
+ "x1": 849.98819,
+ "y1": 1137.6914,
+ "x2": 886.79237,
+ "y2": 1129.1957,
+ "name": null,
+ "name1": "Baltimore",
+ "name2": "Wilmington DE"
+ },
+ {
+ "x1": 920.40337,
+ "y1": 1023.0968,
+ "x2": 1003.9483,
+ "y2": 1088.1015,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Monmouth"
+ },
+ {
+ "x1": 1017.8464,
+ "y1": 1017.1381,
+ "x2": 1033.8495,
+ "y2": 1070.3896,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "Monmouth"
+ },
+ {
+ "x1": 924.64522,
+ "y1": 988.37335,
+ "x2": 959.76472,
+ "y2": 981.72244,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "New Brunswick"
+ },
+ {
+ "x1": 930.01556,
+ "y1": 893.89157,
+ "x2": 978.18087,
+ "y2": 943.47351,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "New Brunswick"
+ },
+ {
+ "x1": 1023.785,
+ "y1": 945.87857,
+ "x2": 1045.4705999999999,
+ "y2": 913.01603,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "New York"
+ },
+ {
+ "x1": 1104.2595,
+ "y1": 880.08247,
+ "x2": 1148.1712,
+ "y2": 892.11777,
+ "name": null,
+ "name1": "New York",
+ "name2": "Long Island"
+ },
+ {
+ "x1": 757.18708,
+ "y1": 913.72435,
+ "x2": 865.1994500000001,
+ "y2": 873.7064499999999,
+ "name": null,
+ "name1": "Reading",
+ "name2": "Morristown"
+ },
+ {
+ "x1": 875.47542,
+ "y1": 846.43457,
+ "x2": 765.68563,
+ "y2": 792.2419600000001,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "Wyoming Valley"
+ },
+ {
+ "x1": 738.76731,
+ "y1": 823.40775,
+ "x2": 738.06503,
+ "y2": 897.7891099999999,
+ "name": null,
+ "name1": "Wyoming Valley",
+ "name2": "Reading"
+ },
+ {
+ "x1": 631.8156,
+ "y1": 917.26592,
+ "x2": 685.64742,
+ "y2": 927.89062,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "Reading"
+ },
+ {
+ "x1": 472.16664,
+ "y1": 954.99649,
+ "x2": 513.40231,
+ "y2": 600.77474,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Fort Niagara"
+ },
+ {
+ "x1": 539.27641,
+ "y1": 576.31715,
+ "x2": 669.27295,
+ "y2": 609.48294,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "Genesee"
+ },
+ {
+ "x1": 706.18851,
+ "y1": 658.02319,
+ "x2": 715.39658,
+ "y2": 749.39563,
+ "name": null,
+ "name1": "Genesee",
+ "name2": "Wyoming Valley"
+ },
+ {
+ "x1": 132.80092,
+ "y1": 694.85067,
+ "x2": 461.55159,
+ "y2": 564.35025,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Fort Niagara"
+ },
+ {
+ "x1": 539.23485,
+ "y1": 548.69292,
+ "x2": 789.97769,
+ "y2": 496.6111,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "Oswego"
+ },
+ {
+ "x1": 836.16704,
+ "y1": 488.73628,
+ "x2": 878.6646400000001,
+ "y2": 509.9893,
+ "name": null,
+ "name1": "Oswego",
+ "name2": "Fort Stanwix"
+ },
+ {
+ "x1": 878.3123,
+ "y1": 537.08199,
+ "x2": 746.55996,
+ "y2": 607.91092,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "Genesee"
+ },
+ {
+ "x1": 957,
+ "y1": 560,
+ "x2": 991.63883,
+ "y2": 624.02415,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "Albany"
+ },
+ {
+ "x1": 1010.4299,
+ "y1": 624.89909,
+ "x2": 1022.0962999999999,
+ "y2": 570.90064,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1004.3885,
+ "y1": 700.522,
+ "x2": 999.43028,
+ "y2": 744.4374300000001,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 932.1405,
+ "y1": 839.35144,
+ "x2": 964.0133999999999,
+ "y2": 809.60347,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 1023.5129,
+ "y1": 809.60227,
+ "x2": 1036.2685999999999,
+ "y2": 834.04814,
+ "name": null,
+ "name1": "Westchester",
+ "name2": "New York"
+ },
+ {
+ "x1": 939.93195,
+ "y1": 871.22554,
+ "x2": 1024.9296,
+ "y2": 874.0588,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "New York"
+ },
+ {
+ "x1": 1086.554,
+ "y1": 834.75403,
+ "x2": 1104.9714000000001,
+ "y2": 805.7095599999999,
+ "name": null,
+ "name1": "New York",
+ "name2": "New Haven"
+ },
+ {
+ "x1": 1031.3044,
+ "y1": 778.43648,
+ "x2": 1090.0944,
+ "y2": 774.89491,
+ "name": null,
+ "name1": "Westchester",
+ "name2": "New Haven"
+ },
+ {
+ "x1": 1044.054,
+ "y1": 660.14813,
+ "x2": 1096.4692,
+ "y2": 660.85645,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1175,
+ "y1": 699,
+ "x2": 1206.8827,
+ "y2": 748.06237,
+ "name": null,
+ "name1": "Springfield",
+ "name2": "Hartford"
+ },
+ {
+ "x1": 1167.1178,
+ "y1": 782.06644,
+ "x2": 1185.6344,
+ "y2": 783.0435299999999,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "Hartford"
+ },
+ {
+ "x1": 1260.0896,
+ "y1": 777.72817,
+ "x2": 1292.672,
+ "y2": 777.01985,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "Newport"
+ },
+ {
+ "x1": 1302.6717,
+ "y1": 733.18767,
+ "x2": 1279.8807000000002,
+ "y2": 698.3136900000001,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Lexington Concord"
+ },
+ {
+ "x1": 1331.171,
+ "y1": 733.77117,
+ "x2": 1351.0039000000002,
+ "y2": 667.52295,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Boston"
+ },
+ {
+ "x1": 1296.7971,
+ "y1": 651.52331,
+ "x2": 1328.6711,
+ "y2": 640.35704,
+ "name": null,
+ "name1": "Lexington Concord",
+ "name2": "Boston"
+ },
+ {
+ "x1": 1175.6754,
+ "y1": 664.60645,
+ "x2": 1217.9658000000002,
+ "y2": 664.8146399999999,
+ "name": null,
+ "name1": "Springfield",
+ "name2": "Lexington Concord"
+ },
+ {
+ "x1": 1134.7598,
+ "y1": 561.23425,
+ "x2": 1131.1766,
+ "y2": 622.77415,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1394.6692,
+ "y1": 667.23127,
+ "x2": 1414.9186,
+ "y2": 707.23019,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Barnstable"
+ },
+ {
+ "x1": 1364.92,
+ "y1": 593.56667,
+ "x2": 1367.9199,
+ "y2": 485.77797000000004,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Falmouth"
+ },
+ {
+ "x1": 1338.8788,
+ "y1": 466.6535,
+ "x2": 1293.3386,
+ "y2": 488.06953,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "Concord"
+ },
+ {
+ "x1": 1216.5493,
+ "y1": 512.27725,
+ "x2": 1181.9667,
+ "y2": 520.52701,
+ "name": null,
+ "name1": "Concord",
+ "name2": "Brattleboro"
+ },
+ {
+ "x1": 1102.9274,
+ "y1": 532.27665,
+ "x2": 1072.3866,
+ "y2": 535.48497,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1034.1376,
+ "y1": 433.48783,
+ "x2": 1035.5543,
+ "y2": 493.69446999999997,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1073.4544,
+ "y1": 390.62944,
+ "x2": 1126.5731,
+ "y2": 383.19275,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "Norwich"
+ },
+ {
+ "x1": 1162.009,
+ "y1": 418.15493,
+ "x2": 1151.5095000000001,
+ "y2": 483.69482999999997,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "Brattleboro"
+ },
+ {
+ "x1": 1203.25,
+ "y1": 416.5,
+ "x2": 1232.1321,
+ "y2": 462.69531,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "Concord"
+ },
+ {
+ "x1": 1038.3875,
+ "y1": 237.28501,
+ "x2": 1037.6792,
+ "y2": 350.61516,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Ticonderoga"
+ },
+ {
+ "x1": 1006.805,
+ "y1": 219.53548,
+ "x2": 828.01842,
+ "y2": 424.98807,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Oswego"
+ },
+ {
+ "x1": 1073.095,
+ "y1": 174.99511,
+ "x2": 1130,
+ "y2": 122.25,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Quebec"
+ },
+ {
+ "x1": 652.36158,
+ "y1": 1060.8876,
+ "x2": 670.77809,
+ "y2": 1096.1774,
+ "name": null,
+ "name1": "York",
+ "name2": "Frederick Town"
+ }
+ ],
+ "wilderness": [
+ {
+ "x1": 90.648464,
+ "y1": 748.27474,
+ "x2": 167.28328,
+ "y2": 986.1757699999999,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Bassett Town"
+ },
+ {
+ "x1": 196.33447,
+ "y1": 1058.8038,
+ "x2": 170.79522,
+ "y2": 1212.0665999999999,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "Point Pleasant"
+ },
+ {
+ "x1": 1196,
+ "y1": 127,
+ "x2": 1346.2935,
+ "y2": 418.71331,
+ "name": "Quebec-Falmouth",
+ "name1": "Quebec",
+ "name2": "Falmouth"
+ }
+ ],
+ "sea": [
+ {
+ "x1": 1040,
+ "y1": 195,
+ "x2": 1316.5,
+ "y2": 101.5,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Sea1"
+ },
+ {
+ "x1": 1162.5,
+ "y1": 93.5,
+ "x2": 1316.5,
+ "y2": 101.5,
+ "name": null,
+ "name1": "Quebec",
+ "name2": "Sea1"
+ },
+ {
+ "x1": 1374.0618,
+ "y1": 446.47501,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1367.5,
+ "y1": 629,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1434.3301,
+ "y1": 741.04565,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Barnstable",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1330,
+ "y1": 772.5,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1186.3301,
+ "y1": 904.04565,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "Long Island",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 1128.0801,
+ "y1": 772.04565,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "New Haven",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 1064.5,
+ "y1": 874.5,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "New York",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 926,
+ "y1": 1116.5,
+ "x2": 1097.5,
+ "y2": 1210.5,
+ "name": null,
+ "name1": "Wilmington DE",
+ "name2": "Sea4"
+ },
+ {
+ "x1": 886,
+ "y1": 997.5,
+ "x2": 1097.5,
+ "y2": 1210.5,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Sea4"
+ },
+ {
+ "x1": 810.5,
+ "y1": 1142.5,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Baltimore",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 693.5,
+ "y1": 1254,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 806.62952,
+ "y1": 1352.5383,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Yorktown",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 822,
+ "y1": 1487.5,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 803.8092,
+ "y1": 1706.0598,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "New Bern",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 715.5592,
+ "y1": 1852.3098,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "Wilmington",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 484,
+ "y1": 2086,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 267,
+ "y1": 2307,
+ "x2": 399.5,
+ "y2": 2393.5,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "Sea7"
+ },
+ {
+ "x1": 220.5,
+ "y1": 2429.5,
+ "x2": 399.5,
+ "y2": 2393.5,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "Sea7"
+ }
+ ],
+ "colony": [
+ {
+ "x1": 1250.8815,
+ "y1": 498.65267,
+ "x2": 1503.0411,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Concord",
+ "name2": "NH"
+ },
+ {
+ "x1": 1136.1348,
+ "y1": 519.90207,
+ "x2": 1503.0411,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "NH"
+ },
+ {
+ "x1": 1172.9671,
+ "y1": 382.48926,
+ "x2": 1503.0411000000001,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "NH"
+ },
+ {
+ "x1": 1537.0402,
+ "y1": 1120.5519,
+ "x2": 1138.968,
+ "y2": 660.14813,
+ "name": null,
+ "name1": "MA",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1255.1314,
+ "y1": 671.48115,
+ "x2": 1537.0402,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Lexington Concord",
+ "name2": "MA"
+ },
+ {
+ "x1": 1437.8763,
+ "y1": 745.14575,
+ "x2": 1537.0402,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Barnstable",
+ "name2": "MA"
+ },
+ {
+ "x1": 1365.6283,
+ "y1": 633.23222,
+ "x2": 1537.0402000000001,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Boston",
+ "name2": "MA"
+ },
+ {
+ "x1": 1365.6283,
+ "y1": 437.73771,
+ "x2": 1537.0402000000001,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "MA"
+ },
+ {
+ "x1": 1333.0459,
+ "y1": 770.64503,
+ "x2": 1576.7057,
+ "y2": 1192.7998,
+ "name": null,
+ "name1": "Newport",
+ "name2": "RI"
+ },
+ {
+ "x1": 1212.6326,
+ "y1": 780.56142,
+ "x2": 1503.0411,
+ "y2": 1197.0497,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "CT"
+ },
+ {
+ "x1": 1126.2184,
+ "y1": 772.06166,
+ "x2": 1503.0411,
+ "y2": 1197.0497,
+ "name": null,
+ "name1": "New Haven",
+ "name2": "CT"
+ },
+ {
+ "x1": 1408.5453,
+ "y1": 1122.5186,
+ "x2": 1058.6385,
+ "y2": 878.85875,
+ "name": null,
+ "name1": "NY",
+ "name2": "New York"
+ },
+ {
+ "x1": 1416.6269,
+ "y1": 1116.302,
+ "x2": 987.38895,
+ "y2": 781.97805,
+ "name": null,
+ "name1": "NY",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 1002.9718,
+ "y1": 665.81464,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Albany",
+ "name2": "NY"
+ },
+ {
+ "x1": 1031.3044,
+ "y1": 535.48497,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Saratoga",
+ "name2": "NY"
+ },
+ {
+ "x1": 1034.1376,
+ "y1": 390.98902,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "NY"
+ },
+ {
+ "x1": 913.72435,
+ "y1": 511.40231,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "NY"
+ },
+ {
+ "x1": 807.47733,
+ "y1": 461.82037,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Oswego",
+ "name2": "NY"
+ },
+ {
+ "x1": 708.31345,
+ "y1": 623.31583,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Genesee",
+ "name2": "NY"
+ },
+ {
+ "x1": 488.73628,
+ "y1": 558.151,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "NY"
+ },
+ {
+ "x1": 83.580987,
+ "y1": 716.81321,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Canada"
+ },
+ {
+ "x1": 1415.2103,
+ "y1": 1226.7989,
+ "x2": 903.80796,
+ "y2": 859.89253,
+ "name": null,
+ "name1": "NJ",
+ "name2": "Morristown"
+ },
+ {
+ "x1": 993.05545,
+ "y1": 970.38942,
+ "x2": 1415.2103,
+ "y2": 1226.7989,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "NJ"
+ },
+ {
+ "x1": 1045.4706,
+ "y1": 1114.8854,
+ "x2": 1415.2103000000002,
+ "y2": 1226.7988999999998,
+ "name": null,
+ "name1": "Monmouth",
+ "name2": "NJ"
+ },
+ {
+ "x1": 1345.7956,
+ "y1": 1233.882,
+ "x2": 716.81321,
+ "y2": 934.97375,
+ "name": null,
+ "name1": "PA",
+ "name2": "Reading"
+ },
+ {
+ "x1": 1345.7956,
+ "y1": 1233.882,
+ "x2": 628.98234,
+ "y2": 1031.3044,
+ "name": null,
+ "name1": "PA",
+ "name2": "York"
+ },
+ {
+ "x1": 594.9833,
+ "y1": 912.30772,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "PA"
+ },
+ {
+ "x1": 722.47972,
+ "y1": 784.8113,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Wyoming Valley",
+ "name2": "PA"
+ },
+ {
+ "x1": 470.32013,
+ "y1": 995.88871,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "PA"
+ },
+ {
+ "x1": 179.91162,
+ "y1": 1025.6379,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "PA"
+ },
+ {
+ "x1": 925.57679,
+ "y1": 1115.901,
+ "x2": 1425.4283,
+ "y2": 1302.2184,
+ "name": null,
+ "name1": "Wilmington DE",
+ "name2": "DE"
+ },
+ {
+ "x1": 1333.2713,
+ "y1": 1315.2406,
+ "x2": 804.37031,
+ "y2": 1143.9488,
+ "name": null,
+ "name1": "MD",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 672.14505,
+ "y1": 1127.9215,
+ "x2": 1333.2712999999999,
+ "y2": 1315.2405999999999,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "MD"
+ },
+ {
+ "x1": 478.8157,
+ "y1": 1132.93,
+ "x2": 1333.2712999999999,
+ "y2": 1315.2406,
+ "name": null,
+ "name1": "Fort Cumberland",
+ "name2": "MD"
+ },
+ {
+ "x1": 805.37201,
+ "y1": 1355.3089,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Yorktown",
+ "name2": "VA"
+ },
+ {
+ "x1": 820.39761,
+ "y1": 1484.529,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "VA"
+ },
+ {
+ "x1": 672.14505,
+ "y1": 1480.5222,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "VA"
+ },
+ {
+ "x1": 643.09556,
+ "y1": 1356.3106,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "VA"
+ },
+ {
+ "x1": 695.1843,
+ "y1": 1262.1502,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "VA"
+ },
+ {
+ "x1": 479.81741,
+ "y1": 1295.2065,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "VA"
+ },
+ {
+ "x1": 527.89932,
+ "y1": 1483.5273,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "VA"
+ },
+ {
+ "x1": 388.66212,
+ "y1": 1440.4539,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "VA"
+ },
+ {
+ "x1": 248.42321,
+ "y1": 1450.471,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Fort Chiswell",
+ "name2": "VA"
+ },
+ {
+ "x1": 166.28328,
+ "y1": 1249.128,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Point Pleasant",
+ "name2": "VA"
+ },
+ {
+ "x1": 97.165529,
+ "y1": 1485.5307,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "VA"
+ },
+ {
+ "x1": 162.27645,
+ "y1": 1606.7372,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "NC"
+ },
+ {
+ "x1": 335.57167,
+ "y1": 1597.7218,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Salem",
+ "name2": "NC"
+ },
+ {
+ "x1": 244.41638,
+ "y1": 1691.8823,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "NC"
+ },
+ {
+ "x1": 517.88225,
+ "y1": 1624.7679,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "NC"
+ },
+ {
+ "x1": 646.10068,
+ "y1": 1711.9164,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "NC"
+ },
+ {
+ "x1": 802.36689,
+ "y1": 1711.9164,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "New Bern",
+ "name2": "NC"
+ },
+ {
+ "x1": 713.21502,
+ "y1": 1850.1519,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Wilmington",
+ "name2": "NC"
+ },
+ {
+ "x1": 1258.1433,
+ "y1": 1528.6041,
+ "x2": 615.04778,
+ "y2": 1957.3345,
+ "name": null,
+ "name1": "SC",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 482.82253,
+ "y1": 2090.5614,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "SC"
+ },
+ {
+ "x1": 442.75427,
+ "y1": 1942.3089,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Eutaw Springs",
+ "name2": "SC"
+ },
+ {
+ "x1": 534.91126,
+ "y1": 1833.1229,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "SC"
+ },
+ {
+ "x1": 379.64676,
+ "y1": 1809.0819,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Camden",
+ "name2": "SC"
+ },
+ {
+ "x1": 257.43857,
+ "y1": 1972.3601,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Ninety Six",
+ "name2": "SC"
+ },
+ {
+ "x1": 114.19454,
+ "y1": 1813.0887,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Fort Prince George",
+ "name2": "SC"
+ },
+ {
+ "x1": 173.29522,
+ "y1": 2094.5683,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "GA"
+ },
+ {
+ "x1": 266.45392,
+ "y1": 2315.9454,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "GA"
+ },
+ {
+ "x1": 220.37543,
+ "y1": 2437.1519,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "GA"
+ },
+ {
+ "x1": 1408.5453,
+ "y1": 1122.5186,
+ "x2": 1186.3301,
+ "y2": 904.04565,
+ "name": null,
+ "name1": "NY",
+ "name2": "Long Island"
+ },
+ {
+ "x1": 886,
+ "y1": 997.5,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "PA"
+ },
+ {
+ "x1": 1162.5,
+ "y1": 93.5,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Quebec",
+ "name2": "Canada"
+ },
+ {
+ "x1": 1040,
+ "y1": 195,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Canada"
+ }
+ ]
+ },
+ "labels": [
+ {
+ "x": 1527.1014,
+ "y": 2281.8875,
+ "name": "9"
+ },
+ {
+ "x": 1468.5017,
+ "y": 2409.605,
+ "name": "1783"
+ },
+ {
+ "x": 1399.8848,
+ "y": 2412.6101,
+ "name": "1782"
+ },
+ {
+ "x": 1329.2645,
+ "y": 2408.6033,
+ "name": "1781"
+ },
+ {
+ "x": 1265.1553,
+ "y": 2410.1057,
+ "name": "1780"
+ },
+ {
+ "x": 1201.0461,
+ "y": 2410.1057,
+ "name": "1779"
+ },
+ {
+ "x": 1138.4395,
+ "y": 2409.605,
+ "name": "1778"
+ },
+ {
+ "x": 1062.8105,
+ "y": 2408.1025,
+ "name": "1777"
+ },
+ {
+ "x": 998.2005,
+ "y": 2408.6033,
+ "name": "1776"
+ },
+ {
+ "x": 928.08105,
+ "y": 2411.1077,
+ "name": "1775"
+ },
+ {
+ "x": 1476.0145,
+ "y": 2284.8926,
+ "name": "8"
+ },
+ {
+ "x": 1416.9138,
+ "y": 2286.896,
+ "name": "7"
+ },
+ {
+ "x": 1342.2867,
+ "y": 2285.3933,
+ "name": "6"
+ },
+ {
+ "x": 1264.6544,
+ "y": 2282.3882,
+ "name": "5"
+ },
+ {
+ "x": 1213.5674,
+ "y": 2279.884,
+ "name": "4"
+ },
+ {
+ "x": 1144.4497,
+ "y": 2280.3848,
+ "name": "3"
+ },
+ {
+ "x": 1082.3439,
+ "y": 2282.3882,
+ "name": "2"
+ },
+ {
+ "x": 1004.2108,
+ "y": 2285.8943,
+ "name": "1"
+ },
+ {
+ "x": 932.08789,
+ "y": 2283.8909,
+ "name": "0"
+ },
+ {
+ "x": 166.09312,
+ "y": 365.55655,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 395.46118,
+ "y": 363.54544,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 1308.392,
+ "y": 100.05029,
+ "name": "Sea1"
+ },
+ {
+ "x": 1503.4926,
+ "y": 111.18933,
+ "name": "Captured Generals"
+ },
+ {
+ "x": 1155,
+ "y": 95,
+ "name": "Quebec"
+ },
+ {
+ "x": 1030,
+ "y": 200,
+ "name": "Montreal"
+ },
+ {
+ "x": 1170,
+ "y": 380,
+ "name": "Norwich"
+ },
+ {
+ "x": 1030,
+ "y": 400,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 815,
+ "y": 470,
+ "name": "Oswego"
+ },
+ {
+ "x": 910,
+ "y": 515,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 1025,
+ "y": 540,
+ "name": "Saratoga"
+ },
+ {
+ "x": 1145,
+ "y": 535,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 1240,
+ "y": 500,
+ "name": "Concord"
+ },
+ {
+ "x": 1363.8234,
+ "y": 463.28925,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1363.3225,
+ "y": 632.07678,
+ "name": "Boston"
+ },
+ {
+ "x": 1428.9343,
+ "y": 738.75854,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1330,
+ "y": 772.5,
+ "name": "Newport"
+ },
+ {
+ "x": 1254.1365,
+ "y": 673.64758,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1215.0699,
+ "y": 800.36346,
+ "name": "Hartford"
+ },
+ {
+ "x": 1110.3916,
+ "y": 778.82678,
+ "name": "New Haven"
+ },
+ {
+ "x": 1121.9113,
+ "y": 655.61688,
+ "name": "Springfield"
+ },
+ {
+ "x": 997.19879,
+ "y": 667.63739,
+ "name": "Albany"
+ },
+ {
+ "x": 989.18512,
+ "y": 794.85413,
+ "name": "Westchester"
+ },
+ {
+ "x": 1057.802,
+ "y": 875.99231,
+ "name": "New York"
+ },
+ {
+ "x": 1188.0239,
+ "y": 912.55463,
+ "name": "Long Island"
+ },
+ {
+ "x": 1001.3301,
+ "y": 977.54565,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 1033.7611,
+ "y": 1103.8805,
+ "name": "Monmouth"
+ },
+ {
+ "x": 893.0213,
+ "y": 871.98547,
+ "name": "Morristown"
+ },
+ {
+ "x": 715.7193,
+ "y": 630.07336,
+ "name": "Genesee"
+ },
+ {
+ "x": 501.56177,
+ "y": 561.97504,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 83.14164,
+ "y": 710.2099,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 181.30887,
+ "y": 1032.7594,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 471.30289,
+ "y": 1001.2056,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 598.0188,
+ "y": 923.07251,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 723.75372,
+ "y": 936.08838,
+ "name": "Reading"
+ },
+ {
+ "x": 624.56396,
+ "y": 1030.756,
+ "name": "York"
+ },
+ {
+ "x": 718.72443,
+ "y": 786.84045,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 872.98718,
+ "y": 1009.2193,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 909.04865,
+ "y": 1123.4138,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 800.36346,
+ "y": 1153.465,
+ "name": "Baltimore"
+ },
+ {
+ "x": 661.62714,
+ "y": 1143.448,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 682.16211,
+ "y": 1260.1469,
+ "name": "Alexandria"
+ },
+ {
+ "x": 467.79694,
+ "y": 1297.21,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 636.08362,
+ "y": 1367.8302,
+ "name": "Richmond"
+ },
+ {
+ "x": 808.37714,
+ "y": 1357.3123,
+ "name": "Yorktown"
+ },
+ {
+ "x": 819.89679,
+ "y": 1495.5479,
+ "name": "Norfolk"
+ },
+ {
+ "x": 660.62543,
+ "y": 1496.5496,
+ "name": "Petersburg"
+ },
+ {
+ "x": 512.87372,
+ "y": 1485.5306,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 386.15784,
+ "y": 1446.4642,
+ "name": "Fincastle"
+ },
+ {
+ "x": 237.90529,
+ "y": 1447.9667,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 160.7739,
+ "y": 1260.1469,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 91.656143,
+ "y": 1496.5496,
+ "name": "Abingdon"
+ },
+ {
+ "x": 162.8092,
+ "y": 1603.8098,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 341.58191,
+ "y": 1604.7338,
+ "name": "Salem"
+ },
+ {
+ "x": 514.87714,
+ "y": 1625.2688,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 646.3092,
+ "y": 1707.0598,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 815.88995,
+ "y": 1717.4258,
+ "name": "New Bern"
+ },
+ {
+ "x": 713.71588,
+ "y": 1857.1638,
+ "name": "Wilmington"
+ },
+ {
+ "x": 605.0307,
+ "y": 1954.3293,
+ "name": "Georgetown"
+ },
+ {
+ "x": 523.89252,
+ "y": 1833.6237,
+ "name": "Cheraw"
+ },
+ {
+ "x": 368.62799,
+ "y": 1816.5947,
+ "name": "Camden"
+ },
+ {
+ "x": 249.42491,
+ "y": 1701.8993,
+ "name": "Charlotte"
+ },
+ {
+ "x": 110.68857,
+ "y": 1818.5981,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 252.93089,
+ "y": 1970.8575,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 434.7406,
+ "y": 1951.3242,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 478.8157,
+ "y": 2099.0759,
+ "name": "Charleston"
+ },
+ {
+ "x": 264.4505,
+ "y": 2315.4446,
+ "name": "Savannah"
+ },
+ {
+ "x": 179.8063,
+ "y": 2104.0845,
+ "name": "Augusta"
+ },
+ {
+ "x": 215.3669,
+ "y": 2438.6543,
+ "name": "St. Mary's"
+ },
+ {
+ "x": 1008.5179,
+ "y": 2050.7935,
+ "name": "BRC"
+ },
+ {
+ "x": 1231.9423,
+ "y": 2050.9939,
+ "name": "ARC1"
+ },
+ {
+ "x": 1466.2352,
+ "y": 2057.8745,
+ "name": "ARC2"
+ },
+ {
+ "x": 1465,
+ "y": 1776,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 1167.4889,
+ "y": 1789.0479,
+ "name": "War Ends Card"
+ },
+ {
+ "x": 1197.0392,
+ "y": 1587.2039,
+ "name": "GA"
+ },
+ {
+ "x": 1252.1331,
+ "y": 1520.0896,
+ "name": "SC"
+ },
+ {
+ "x": 1300,
+ "y": 1443.5,
+ "name": "NC"
+ },
+ {
+ "x": 1290.6989,
+ "y": 1383.3567,
+ "name": "VA"
+ },
+ {
+ "x": 1339,
+ "y": 1302.5,
+ "name": "MD"
+ },
+ {
+ "x": 1407.3976,
+ "y": 1313.7382,
+ "name": "DE"
+ },
+ {
+ "x": 1414.9104,
+ "y": 1234.1024,
+ "name": "NJ"
+ },
+ {
+ "x": 1339,
+ "y": 1230,
+ "name": "PA"
+ },
+ {
+ "x": 1504.0623,
+ "y": 1195.0358,
+ "name": "CT"
+ },
+ {
+ "x": 1577.6877,
+ "y": 1194.535,
+ "name": "RI"
+ },
+ {
+ "x": 1534.1135,
+ "y": 1122.913,
+ "name": "MA"
+ },
+ {
+ "x": 1406.8969,
+ "y": 1122.4121,
+ "name": "NY"
+ },
+ {
+ "x": 1498,
+ "y": 1043,
+ "name": "NH"
+ },
+ {
+ "x": 1416,
+ "y": 1003.5,
+ "name": "Canada"
+ },
+ {
+ "x": 1509.5,
+ "y": 550,
+ "name": "Sea2"
+ },
+ {
+ "x": 1253.5,
+ "y": 1016.5,
+ "name": "Sea3"
+ },
+ {
+ "x": 1088.8549,
+ "y": 1218.0751,
+ "name": "Sea4"
+ },
+ {
+ "x": 981.17151,
+ "y": 1441.9565,
+ "name": "Sea5"
+ },
+ {
+ "x": 671.14337,
+ "y": 2067.0212,
+ "name": "Sea6"
+ },
+ {
+ "x": 393.67065,
+ "y": 2394.5793,
+ "name": "Sea7"
+ },
+ {
+ "x": 585,
+ "y": 385,
+ "name": "Continental Corgress Dispersed Box"
+ },
+ {
+ "x": 479.92914,
+ "y": 1140.5603,
+ "name": "Fort Cumberland"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tools/layout.svg b/tools/layout.svg
index 506d903..9805857 100644
--- a/tools/layout.svg
+++ b/tools/layout.svg
@@ -40,9 +40,9 @@
inkscape:window-height="480"
id="namedview8"
showgrid="false"
- inkscape:zoom="0.5"
- inkscape:cx="1894.5029"
- inkscape:cy="1424.4221"
+ inkscape:zoom="0.71155804"
+ inkscape:cx="871.00863"
+ inkscape:cy="553.26207"
inkscape:current-layer="svg6"
inkscape:snap-center="false"
inkscape:snap-others="true"
@@ -55,31 +55,32 @@
<image
sodipodi:absref="/home/tor/src/rally/public/washingtons-war/tools/mapmask.png"
xlink:href="mapmask.png"
- x="0"
- y="0"
- width="1650"
- height="2550"
- image-rendering="pixelated"
- sodipodi:insensitive="true"
+ style="display:inline"
id="image2"
- style="display:inline" />
+ sodipodi:insensitive="true"
+ image-rendering="pixelated"
+ height="2550"
+ width="1650"
+ y="0"
+ x="0" />
<image
sodipodi:absref="/home/tor/src/rally/public/washingtons-war/tools/map75.png"
xlink:href="map75.png"
- x="0"
- y="0"
- width="1650"
- height="2550"
- image-rendering="pixelated"
- opacity="0.535871"
- id="image4"
- style="display:inline"
+ sodipodi:insensitive="true"
inkscape:label="texture"
- sodipodi:insensitive="true" />
+ style="display:inline"
+ id="image4"
+ opacity="0.535871"
+ image-rendering="pixelated"
+ height="2550"
+ width="1650"
+ y="0"
+ x="0" />
<g
id="g2693"
- inkscape:label="fortress"
- style="display:none">
+ inkscape:label="fortified_port"
+ style="display:none"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect887"
@@ -112,7 +113,8 @@
<g
id="g2712"
inkscape:label="winter_quarters"
- style="display:none">
+ style="display:none"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect845"
@@ -235,8 +237,9 @@
</g>
<g
id="g2687"
- inkscape:label="space"
- style="display:none">
+ inkscape:label="regular"
+ style="display:none"
+ sodipodi:insensitive="true">
<circle
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="circle910"
@@ -587,7 +590,8 @@
<g
id="g2555"
inkscape:label="sea"
- style="display:inline">
+ style="display:inline"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1000"
@@ -641,7 +645,8 @@
<g
id="g2546"
inkscape:label="colony"
- style="display:inline">
+ style="display:inline"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1016"
@@ -744,85 +749,83 @@
<g
id="g2584"
inkscape:label="box"
- style="display:inline"
- sodipodi:insensitive="true">
+ style="display:inline">
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.99946"
+ id="rect1092"
+ width="214"
+ height="206"
+ x="1358"
+ y="1673"
+ inkscape:label="British Reinforcement Box" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.00286"
+ id="rect1096"
+ width="214"
+ height="206"
+ x="294"
+ y="258"
+ inkscape:label="American Leader Reinforcements" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.08098"
+ id="rect1098"
+ width="214"
+ height="207"
+ x="63"
+ y="258"
+ inkscape:label="French Reinforcements" />
<rect
style="opacity:1;fill:#000000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1606"
width="88"
height="104"
x="542"
- y="332" />
+ y="332"
+ inkscape:label="Continental Congress Dispersed" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1044"
- width="64"
- height="71"
- x="905"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1046"
- width="64"
- height="71"
- x="971"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1048"
- width="64"
- height="71"
- x="1037"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1050"
- width="64"
- height="71"
- x="1103"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1052"
- width="65"
- height="71"
- x="1169"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1054"
- width="64"
- height="71"
- x="1236"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.23342"
+ id="rect1094"
+ width="205"
+ height="136"
+ x="1400"
+ y="46"
+ inkscape:label="Captured Generals" />
+ </g>
+ <g
+ id="g607"
+ inkscape:label="Card Boxes">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1056"
- width="64"
- height="71"
- x="1302"
- y="2241" />
+ id="rect1084"
+ width="199"
+ height="277"
+ x="904"
+ y="1915" />
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1058"
- width="64"
- height="71"
- x="1368"
- y="2241" />
+ id="rect1086"
+ width="199"
+ height="277"
+ x="1137"
+ y="1915" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1060"
- width="65"
- height="71"
- x="1434"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.97641"
+ id="rect1088"
+ width="199.00003"
+ height="277"
+ x="1370"
+ y="1915" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1062"
- width="63"
- height="71"
- x="1501"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.0365"
+ id="rect1090"
+ width="278"
+ height="198.99998"
+ x="1027"
+ y="1679" />
+ </g>
+ <g
+ id="g580"
+ inkscape:label="Game Turn">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1066"
@@ -886,62 +889,80 @@
height="72"
x="1433"
y="2368" />
+ </g>
+ <g
+ id="g569"
+ inkscape:label="French Alliance Track">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1084"
- width="199"
- height="277"
- x="904"
- y="1915" />
+ id="rect1044"
+ width="64"
+ height="71"
+ x="905"
+ y="2241" />
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1086"
- width="199"
- height="277"
- x="1137"
- y="1915" />
+ id="rect1046"
+ width="64"
+ height="71"
+ x="971"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.97641"
- id="rect1088"
- width="199.00003"
- height="277"
- x="1370"
- y="1915" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1048"
+ width="64"
+ height="71"
+ x="1037"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.0365"
- id="rect1090"
- width="278"
- height="198.99998"
- x="1027"
- y="1679" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1050"
+ width="64"
+ height="71"
+ x="1103"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.99946"
- id="rect1092"
- width="214"
- height="206"
- x="1358"
- y="1673" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1052"
+ width="65"
+ height="71"
+ x="1169"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.23342"
- id="rect1094"
- width="205"
- height="136"
- x="1400"
- y="46" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1054"
+ width="64"
+ height="71"
+ x="1236"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.00286"
- id="rect1096"
- width="214"
- height="206"
- x="294"
- y="258" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1056"
+ width="64"
+ height="71"
+ x="1302"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.08098"
- id="rect1098"
- width="214"
- height="207"
- x="63"
- y="258" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1058"
+ width="64"
+ height="71"
+ x="1368"
+ y="2241" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1060"
+ width="65"
+ height="71"
+ x="1434"
+ y="2241" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1062"
+ width="63"
+ height="71"
+ x="1501"
+ y="2241" />
</g>
<g
id="g2117"
@@ -1202,36 +1223,43 @@
sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 759.31202,949.84833 92.08074,31.1658"
- id="path1918" />
+ d="m 759.31202,949.84833 90.94423,35.42773"
+ id="path1918"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 905.22459,1026.3462 1.41662,2.8332 13.45796,48.8737"
- id="path1920" />
+ d="m 908.63011,1030.8842 11.46906,47.1689"
+ id="path1920"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 845.72626,1138.2597 46.74868,-9.9164"
- id="path1922" />
+ d="m 849.98819,1137.6914 36.80418,-8.4957"
+ id="path1922"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 913.01603,1019.9714 96.33067,71.5396"
- id="path1924" />
+ d="m 920.40337,1023.0968 83.54493,65.0047"
+ id="path1924"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 1017.8464,1017.1381 17.7079,58.0817"
- id="path1926" />
+ d="m 1017.8464,1017.1381 16.0031,53.2515"
+ id="path1926"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 920.09917,990.93051 39.66555,-9.20807"
- id="path1928" />
+ d="m 924.64522,988.37335 35.1195,-6.65091"
+ id="path1928"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 930.01556,893.89157 48.16531,49.58194"
id="path1930" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 1027.7628,947.01508 17.7078,-33.99905"
- id="path1932" />
+ d="m 1023.785,945.87857 21.6856,-32.86254"
+ id="path1932"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1104.2595,880.08247 43.9117,12.0353"
@@ -1451,7 +1479,8 @@
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:5, 5;stroke-dashoffset:0;stroke-opacity:1"
d="m 1196,127 c 74.0155,102.10344 61.3742,165.34334 150.2935,291.71331"
id="path2123"
- sodipodi:nodetypes="cc" />
+ sodipodi:nodetypes="cc"
+ inkscape:label="Quebec-Falmouth" />
</g>
<g
id="g2298"
@@ -1542,7 +1571,8 @@
<g
id="g2530"
inkscape:label="colony"
- style="display:none">
+ style="display:none"
+ sodipodi:insensitive="true">
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#f50000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
d="m 1250.8815,498.65267 252.1596,543.98473"
@@ -1816,7 +1846,8 @@
<g
id="g1810"
inkscape:label="labels"
- style="display:none">
+ style="display:inline"
+ sodipodi:insensitive="true">
<text
xml:space="preserve"
style="font-size:14px;font-family:sans-serif;-inkscape-font-specification:sans-serif;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:12, 6, 3, 6;stroke-dashoffset:0;stroke-opacity:1"
@@ -2406,7 +2437,7 @@
sodipodi:role="line"
id="tspan1376"
x="909.04865"
- y="1123.4138">Wilmington</tspan></text>
+ y="1123.4138">Wilmington DE</tspan></text>
<text
xml:space="preserve"
style="font-size:14px;font-family:sans-serif;-inkscape-font-specification:sans-serif;opacity:1;fill:#000000;fill-opacity:0.46748;stroke:none;stroke-width:3"
diff --git a/tools/parse-layout-old.js b/tools/parse-layout-old.js
new file mode 100644
index 0000000..b382849
--- /dev/null
+++ b/tools/parse-layout-old.js
@@ -0,0 +1,466 @@
+"use strict"
+
+/* COMMON PARSING */
+
+const fs = require("fs")
+
+let points = {}
+let circles = {}
+let rects = {}
+let edges = {}
+let labels = []
+
+let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2
+
+function array_insert(array, index, item) {
+ for (let i = array.length; i > index; --i)
+ array[i] = array[i - 1]
+ array[index] = item
+}
+
+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 add_point(x, y) {
+ if (!(name in points))
+ points[name] = []
+ points[name].push({x,y})
+}
+
+function add_circle(cx, cy, rx, ry) {
+ if (!(name in circles))
+ circles[name] = []
+ circles[name].push({x:cx-rx,y:cy-ry,w:rx*2,h:ry*2})
+}
+
+function add_rect(x, y, w, h) {
+ if (!(name in rects))
+ rects[name] = []
+ rects[name].push({x,y,w,h})
+}
+
+function add_edge(x1, y1, x2, y2) {
+ if (!(name in edges))
+ edges[name] = []
+ edges[name].push({x1,y1,x2,y2})
+}
+
+function flush() {
+ if (mode === 'path') {
+ add_edge(x, y, x2, y2)
+ }
+ if (mode === 'rect') {
+ add_rect(x, y, w, h)
+ add_point(x + w/2, y + h/2)
+ }
+ if (mode === 'circle') {
+ add_circle(cx, cy, rx, ry)
+ add_point(cx, cy)
+ }
+ x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0
+}
+
+function parse_path_data(path) {
+ let cx = 0
+ let cy = 0
+ let abs = 0
+ for (let i = 0; i < path.length;) {
+ switch (path[i]) {
+ case 'M':
+ x2 = x = cx = Number(path[i+1])
+ y2 = y = cy = Number(path[i+2])
+ i += 3
+ abs = true
+ break
+ case 'm':
+ x2 = x = cx = cx + Number(path[i+1])
+ y2 = y = cy = cy + Number(path[i+2])
+ i += 3
+ abs = false
+ break
+ case 'C':
+ x2 = cx = Number(path[i+5])
+ y2 = cy = Number(path[i+6])
+ i += 7
+ abs = true
+ break
+ case 'L':
+ i += 1
+ abs = true
+ break
+ case 'H':
+ x2 = cx = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'V':
+ y2 = cy = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'c':
+ x2 = cx = cx + Number(path[i+5])
+ y2 = cy = cy + Number(path[i+6])
+ i += 7
+ abs = false
+ break
+ case 'l':
+ i += 1
+ abs = false
+ break
+ case 'h':
+ x2 = cx = cx + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ case 'v':
+ y2 = cy = cy + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ default:
+ if (abs) {
+ x2 = cx = Number(path[i+0])
+ y2 = cy = Number(path[i+1])
+ } else {
+ x2 = cx = cx + Number(path[i+0])
+ y2 = cy = cy + Number(path[i+1])
+ }
+ i += 2
+ break
+ }
+ }
+}
+
+for (let line of fs.readFileSync("tools/layout.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("<path")) {
+ flush()
+ mode = "path"
+ }
+ else if (line.startsWith("<g")) {
+ flush()
+ mode = "g"
+ }
+ else if (line.startsWith('x="'))
+ x = (Number(line.split('"')[1]))
+ else if (line.startsWith('y="'))
+ y = (Number(line.split('"')[1]))
+ else if (line.startsWith('width="'))
+ w = (Number(line.split('"')[1]))
+ else if (line.startsWith('height="'))
+ h = (Number(line.split('"')[1]))
+ else if (line.startsWith('cx="'))
+ cx = (Number(line.split('"')[1]))
+ else if (line.startsWith('cy="'))
+ cy = (Number(line.split('"')[1]))
+ else if (line.startsWith('r="'))
+ rx = ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('rx="'))
+ rx = (Number(line.split('"')[1]))
+ else if (line.startsWith('ry="'))
+ ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('inkscape:label="') && mode === "g")
+ name = line.split('"')[1]
+ else if (line.startsWith('d="'))
+ parse_path_data(line.split('"')[1].split(/[ ,]/))
+ if (line.includes("</tspan>")) {
+ let name = line.replace(/^[^>]*>/, "").replace(/<\/tspan.*/, "")
+ labels.push({x, y, name})
+ }
+}
+
+flush()
+
+function find_closest_label(x, y) {
+ let nd = Infinity, nn = null
+
+ for (let n of labels) {
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = n
+ }
+ }
+
+ if (!nn) {
+ console.log("NOT FOUND", x, y)
+ return null
+ }
+
+ if (nd > 50) {
+ console.log("NO LABEL", x, y, nd)
+ return null
+ }
+
+ return nn.name
+}
+
+function find_closest_node(nodes, x, y) {
+ let nd = Infinity, nn = -1
+
+ for (let i = 0; i < nodes.length; ++i) {
+ let n = nodes[i]
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = i
+ }
+ }
+
+ if (nd > 100)
+ return -1
+
+ return nn
+}
+
+function label_boxes(top) {
+ for (let key in top) {
+ console.log("BOX", key)
+ for (let item of top[key])
+ item.name = find_closest_label(item.x + item.w/2, item.y + item.h/2)
+ }
+}
+
+function label_points(top) {
+ for (let key in top) {
+ console.log("POINT", key)
+ for (let item of top[key])
+ item.name = find_closest_label(item.x, item.y)
+ }
+}
+
+label_boxes(rects)
+label_boxes(circles)
+label_points(points)
+
+function connect_edge_2way(node_list, edge_name) {
+ console.log("EDGE", edge_name)
+ for (let e of edges[edge_name]) {
+ let a = find_closest_node(node_list, e.x1, e.y1)
+ let b = find_closest_node(node_list, e.x2, e.y2)
+ if (a < 0 || b < 0)
+ console.log("CANNOT FIND EDGE", e, node_list[a], node_list[b])
+ if (!node_list[a][edge_name])
+ node_list[a][edge_name] = []
+ if (!node_list[b][edge_name])
+ node_list[b][edge_name] = []
+ set_add(node_list[a][edge_name], b)
+ set_add(node_list[b][edge_name], a)
+ }
+}
+
+function connect_edge_1way(a_list, b_list, edge_name, prop_name) {
+ console.log("EDGE", edge_name)
+ for (let e of edges[edge_name]) {
+ let a1 = find_closest_node(a_list, e.x1, e.y1)
+ let a2 = find_closest_node(a_list, e.x2, e.y2)
+ let b1 = find_closest_node(b_list, e.x1, e.y1)
+ let b2 = find_closest_node(b_list, e.x2, e.y2)
+ let a = a1 >= 0 ? a1 : a2
+ let b = b1 >= 0 ? b1 : b2
+ if (a < 0 || b < 0)
+ console.log("CANNOT FIND EDGE", e, a_list[a], b_list[b])
+ if (!a_list[a][prop_name])
+ a_list[a][prop_name] = []
+ set_add(a_list[a][prop_name], b)
+ }
+}
+
+/* WASHINGTON'S WAR */
+
+function sort_alpha(list) {
+ list.sort((a,b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
+}
+
+sort_alpha(points.fortress)
+sort_alpha(points.winter_quarters)
+sort_alpha(points.space)
+points.colony.reverse()
+
+const data = {}
+
+data.spaces = [ ...points.fortress, ...points.winter_quarters, ...points.space ]
+data.colonies = [ ...points.colony ]
+data.seas = [ ...points.sea ]
+
+connect_edge_2way(data.spaces, "path")
+connect_edge_2way(data.spaces, "wilderness")
+connect_edge_1way(data.colonies, data.spaces, "colony", "spaces")
+connect_edge_1way(data.seas, data.spaces, "sea", "spaces")
+
+console.log(JSON.stringify(data,0,4))
+
+/*
+function find_closest_node(list, x, y) {
+ let nd = Infinity, nn = null
+
+ for (let n of list) {
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = n
+ }
+ }
+
+ if (!nn) {
+ console.log("NOT FOUND", x, y)
+ return [ null, 0 ]
+ }
+
+ return [ nn, nd ]
+}
+
+function find_enclosing_rect(list, x, y) {
+ for (let [x1, y1, x2, y2] of list) {
+ if (x >= x1 && x <= x2)
+ if (y >= y1 && y <= y2)
+ return true
+ }
+ return false
+}
+
+
+function make_spaces(points) {
+ let spaces = []
+ for (let [x,y] of points) {
+ let [ name, dist ] = find_closest_node(labels, x, y)
+ if (dist > 50) console.log("DISTANCE TOO FAR", x, y, dist)
+
+ spaces.push({ name: name.name, x, y })
+ }
+ return spaces
+}
+
+let data = {}
+
+data.spaces = make_spaces([ ...points.fortress, ...points.winter_quarters, ...points.space ])
+
+console.log(data)
+
+function find_closest_point(x, y) {
+ let nd = Infinity, nn = -1
+
+ for (let i = 0; i < points.length; ++i) {
+ let n = points[i]
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = i
+ }
+ }
+
+ return nn
+}
+
+// FIND and label all points!
+let all_labels = labels.slice()
+let cities = []
+for (let key in points) {
+ for (let [x, y] of points[key]) {
+ let [ node, dist ] = find_closest_node(labels, x, y)
+ if (dist > 15) {
+ console.log("DISTANCE TOO FAR", key,x,y, "dist=" + dist, "name=" + node.name)
+ }
+ if (node) {
+ labels = labels.filter(x => x !== node)
+ let suit = "UNKNOWN"
+
+ if (find_enclosing_rect(rects.$CLUBS, x, y))
+ suit = CLUBS
+ else if (find_enclosing_rect(rects.$HEARTS, x, y))
+ suit = HEARTS
+ else if (find_enclosing_rect(rects.$DIAMONDS, x, y))
+ suit = DIAMONDS
+ else if (find_enclosing_rect(rects.$SPADES, x, y))
+ suit = SPADES
+ else
+ console.log("NOT ASSIGNED SUIT", x, y)
+
+ let country = "UNKNOWN"
+ if (find_enclosing_rect(rects.$Empire, x, y)) {
+ country = EMPIRE
+ }
+ else if (find_enclosing_rect(rects.$Austria, x, y)) {
+ country = AUSTRIA
+ }
+ else if (find_enclosing_rect(rects.$Hanover, x, y)) {
+ country = HANOVER
+ }
+ else if (find_enclosing_rect(rects.$Saxony, x, y)) {
+ country = SAXONY
+ }
+ else if (find_enclosing_rect(rects.$Sweden, x, y)) {
+ country = SWEDEN
+ }
+ else if (find_enclosing_rect(rects.$Poland, x, y)) {
+ country = POLAND
+ }
+ else if (find_enclosing_rect(rects.$Prussia, x, y)) {
+ country = PRUSSIA
+ }
+
+ if (country === "UNKNOWN")
+ console.log("no country:", node)
+
+ cities.push({
+ name: node.name,
+ country,
+ suit,
+ type: key,
+ x: Math.round(x),
+ y: Math.round(y),
+ adjacent: [],
+ major_roads: [],
+ roads: [],
+ })
+ } else {
+ let [ dupname, dupdist ] = find_closest_node(all_labels, x, y)
+ console.log("ALREADY USED", dupname, dupdist, x, y)
+ }
+ }
+}
+
+for (let e of edges.major_road) {
+ let a = find_closest_point(e.x1, e.y1)
+ let b = find_closest_point(e.x2, e.y2)
+ set_add(cities[a].major_roads, b)
+ set_add(cities[b].major_roads, a)
+ set_add(cities[a].adjacent, b)
+ set_add(cities[b].adjacent, a)
+}
+
+for (let e of edges.road) {
+ let a = find_closest_point(e.x1, e.y1)
+ let b = find_closest_point(e.x2, e.y2)
+ set_add(cities[a].roads, b)
+ set_add(cities[b].roads, a)
+ set_add(cities[a].adjacent, b)
+ set_add(cities[b].adjacent, a)
+}
+
+console.log("if (typeof module === 'object') module.exports = data")
+*/
diff --git a/tools/parse-layout.js b/tools/parse-layout.js
index b382849..6f77adf 100644
--- a/tools/parse-layout.js
+++ b/tools/parse-layout.js
@@ -1,61 +1,30 @@
"use strict"
-/* COMMON PARSING */
-
const fs = require("fs")
let points = {}
-let circles = {}
-let rects = {}
+let boxes = {}
let edges = {}
+let mode, group, name, x, y, w, h, cx, cy, rx, ry, x2, y2
let labels = []
-
-let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2
-
-function array_insert(array, index, item) {
- for (let i = array.length; i > index; --i)
- array[i] = array[i - 1]
- array[index] = item
-}
-
-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)
-}
+let labels_uniq = {}
function add_point(x, y) {
- if (!(name in points))
- points[name] = []
- points[name].push({x,y})
-}
-
-function add_circle(cx, cy, rx, ry) {
- if (!(name in circles))
- circles[name] = []
- circles[name].push({x:cx-rx,y:cy-ry,w:rx*2,h:ry*2})
+ if (!(group in points))
+ points[group] = []
+ points[group].push({x,y,name})
}
function add_rect(x, y, w, h) {
- if (!(name in rects))
- rects[name] = []
- rects[name].push({x,y,w,h})
+ if (!(group in boxes))
+ boxes[group] = []
+ boxes[group].push({x,y,w,h,name})
}
function add_edge(x1, y1, x2, y2) {
- if (!(name in edges))
- edges[name] = []
- edges[name].push({x1,y1,x2,y2})
+ if (!(group in edges))
+ edges[group] = []
+ edges[group].push({x1,y1,x2,y2,name})
}
function flush() {
@@ -64,13 +33,14 @@ function flush() {
}
if (mode === 'rect') {
add_rect(x, y, w, h)
- add_point(x + w/2, y + h/2)
+ add_point( x + w/2, y + h/2 )
}
if (mode === 'circle') {
- add_circle(cx, cy, rx, ry)
- add_point(cx, cy)
+ add_rect(cx - rx, cy - ry, rx * 2, ry * 2)
+ add_point( cx, cy )
}
x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0
+ name = null
}
function parse_path_data(path) {
@@ -184,18 +154,23 @@ for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) {
else if (line.startsWith('ry="'))
ry = (Number(line.split('"')[1]))
else if (line.startsWith('inkscape:label="') && mode === "g")
+ group = line.split('"')[1]
+ else if (line.startsWith('inkscape:label="') && mode !== "g")
name = line.split('"')[1]
else if (line.startsWith('d="'))
parse_path_data(line.split('"')[1].split(/[ ,]/))
if (line.includes("</tspan>")) {
let name = line.replace(/^[^>]*>/, "").replace(/<\/tspan.*/, "")
+ if (name in labels_uniq)
+ console.log("DUPLICATE LABEL", name)
labels.push({x, y, name})
+ labels_uniq[name] = 1
}
}
flush()
-function find_closest_label(x, y) {
+function find_label(x, y, limit) {
let nd = Infinity, nn = null
for (let n of labels) {
@@ -206,261 +181,35 @@ function find_closest_label(x, y) {
}
}
- if (!nn) {
- console.log("NOT FOUND", x, y)
- return null
- }
-
- if (nd > 50) {
- console.log("NO LABEL", x, y, nd)
+ if (!nn || nd > limit) {
+ console.log("LABEL NOT FOUND", x, y)
return null
}
return nn.name
}
-function find_closest_node(nodes, x, y) {
- let nd = Infinity, nn = -1
-
- for (let i = 0; i < nodes.length; ++i) {
- let n = nodes[i]
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = i
+for (let group in points) {
+ for (let item of points[group]) {
+ if (item.name === null) {
+ item.name = find_label(item.x, item.y, 72)
}
}
-
- if (nd > 100)
- return -1
-
- return nn
}
-function label_boxes(top) {
- for (let key in top) {
- console.log("BOX", key)
- for (let item of top[key])
- item.name = find_closest_label(item.x + item.w/2, item.y + item.h/2)
- }
-}
-
-function label_points(top) {
- for (let key in top) {
- console.log("POINT", key)
- for (let item of top[key])
- item.name = find_closest_label(item.x, item.y)
- }
-}
-
-label_boxes(rects)
-label_boxes(circles)
-label_points(points)
-
-function connect_edge_2way(node_list, edge_name) {
- console.log("EDGE", edge_name)
- for (let e of edges[edge_name]) {
- let a = find_closest_node(node_list, e.x1, e.y1)
- let b = find_closest_node(node_list, e.x2, e.y2)
- if (a < 0 || b < 0)
- console.log("CANNOT FIND EDGE", e, node_list[a], node_list[b])
- if (!node_list[a][edge_name])
- node_list[a][edge_name] = []
- if (!node_list[b][edge_name])
- node_list[b][edge_name] = []
- set_add(node_list[a][edge_name], b)
- set_add(node_list[b][edge_name], a)
- }
-}
-
-function connect_edge_1way(a_list, b_list, edge_name, prop_name) {
- console.log("EDGE", edge_name)
- for (let e of edges[edge_name]) {
- let a1 = find_closest_node(a_list, e.x1, e.y1)
- let a2 = find_closest_node(a_list, e.x2, e.y2)
- let b1 = find_closest_node(b_list, e.x1, e.y1)
- let b2 = find_closest_node(b_list, e.x2, e.y2)
- let a = a1 >= 0 ? a1 : a2
- let b = b1 >= 0 ? b1 : b2
- if (a < 0 || b < 0)
- console.log("CANNOT FIND EDGE", e, a_list[a], b_list[b])
- if (!a_list[a][prop_name])
- a_list[a][prop_name] = []
- set_add(a_list[a][prop_name], b)
- }
-}
-
-/* WASHINGTON'S WAR */
-
-function sort_alpha(list) {
- list.sort((a,b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
-}
-
-sort_alpha(points.fortress)
-sort_alpha(points.winter_quarters)
-sort_alpha(points.space)
-points.colony.reverse()
-
-const data = {}
-
-data.spaces = [ ...points.fortress, ...points.winter_quarters, ...points.space ]
-data.colonies = [ ...points.colony ]
-data.seas = [ ...points.sea ]
-
-connect_edge_2way(data.spaces, "path")
-connect_edge_2way(data.spaces, "wilderness")
-connect_edge_1way(data.colonies, data.spaces, "colony", "spaces")
-connect_edge_1way(data.seas, data.spaces, "sea", "spaces")
-
-console.log(JSON.stringify(data,0,4))
-
-/*
-function find_closest_node(list, x, y) {
- let nd = Infinity, nn = null
-
- for (let n of list) {
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = n
- }
- }
-
- if (!nn) {
- console.log("NOT FOUND", x, y)
- return [ null, 0 ]
- }
-
- return [ nn, nd ]
-}
-
-function find_enclosing_rect(list, x, y) {
- for (let [x1, y1, x2, y2] of list) {
- if (x >= x1 && x <= x2)
- if (y >= y1 && y <= y2)
- return true
- }
- return false
-}
-
-
-function make_spaces(points) {
- let spaces = []
- for (let [x,y] of points) {
- let [ name, dist ] = find_closest_node(labels, x, y)
- if (dist > 50) console.log("DISTANCE TOO FAR", x, y, dist)
-
- spaces.push({ name: name.name, x, y })
- }
- return spaces
-}
-
-let data = {}
-
-data.spaces = make_spaces([ ...points.fortress, ...points.winter_quarters, ...points.space ])
-
-console.log(data)
-
-function find_closest_point(x, y) {
- let nd = Infinity, nn = -1
-
- for (let i = 0; i < points.length; ++i) {
- let n = points[i]
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = i
+for (let group in boxes) {
+ for (let item of boxes[group]) {
+ if (item.name === null) {
+ item.name = find_label(item.x+item.w/2, item.y+item.w/2, 72)
}
}
-
- return nn
}
-// FIND and label all points!
-let all_labels = labels.slice()
-let cities = []
-for (let key in points) {
- for (let [x, y] of points[key]) {
- let [ node, dist ] = find_closest_node(labels, x, y)
- if (dist > 15) {
- console.log("DISTANCE TOO FAR", key,x,y, "dist=" + dist, "name=" + node.name)
- }
- if (node) {
- labels = labels.filter(x => x !== node)
- let suit = "UNKNOWN"
-
- if (find_enclosing_rect(rects.$CLUBS, x, y))
- suit = CLUBS
- else if (find_enclosing_rect(rects.$HEARTS, x, y))
- suit = HEARTS
- else if (find_enclosing_rect(rects.$DIAMONDS, x, y))
- suit = DIAMONDS
- else if (find_enclosing_rect(rects.$SPADES, x, y))
- suit = SPADES
- else
- console.log("NOT ASSIGNED SUIT", x, y)
-
- let country = "UNKNOWN"
- if (find_enclosing_rect(rects.$Empire, x, y)) {
- country = EMPIRE
- }
- else if (find_enclosing_rect(rects.$Austria, x, y)) {
- country = AUSTRIA
- }
- else if (find_enclosing_rect(rects.$Hanover, x, y)) {
- country = HANOVER
- }
- else if (find_enclosing_rect(rects.$Saxony, x, y)) {
- country = SAXONY
- }
- else if (find_enclosing_rect(rects.$Sweden, x, y)) {
- country = SWEDEN
- }
- else if (find_enclosing_rect(rects.$Poland, x, y)) {
- country = POLAND
- }
- else if (find_enclosing_rect(rects.$Prussia, x, y)) {
- country = PRUSSIA
- }
-
- if (country === "UNKNOWN")
- console.log("no country:", node)
-
- cities.push({
- name: node.name,
- country,
- suit,
- type: key,
- x: Math.round(x),
- y: Math.round(y),
- adjacent: [],
- major_roads: [],
- roads: [],
- })
- } else {
- let [ dupname, dupdist ] = find_closest_node(all_labels, x, y)
- console.log("ALREADY USED", dupname, dupdist, x, y)
- }
+for (let group in edges) {
+ for (let item of edges[group]) {
+ item.name1 = find_label(item.x1, item.y1, 72)
+ item.name2 = find_label(item.x2, item.y2, 72)
}
}
-for (let e of edges.major_road) {
- let a = find_closest_point(e.x1, e.y1)
- let b = find_closest_point(e.x2, e.y2)
- set_add(cities[a].major_roads, b)
- set_add(cities[b].major_roads, a)
- set_add(cities[a].adjacent, b)
- set_add(cities[b].adjacent, a)
-}
-
-for (let e of edges.road) {
- let a = find_closest_point(e.x1, e.y1)
- let b = find_closest_point(e.x2, e.y2)
- set_add(cities[a].roads, b)
- set_add(cities[b].roads, a)
- set_add(cities[a].adjacent, b)
- set_add(cities[b].adjacent, a)
-}
-
-console.log("if (typeof module === 'object') module.exports = data")
-*/
+fs.writeFileSync("tools/layout.json", JSON.stringify({boxes,points,edges,labels}, null, 4))
diff --git a/tools/process-layout.js b/tools/process-layout.js
new file mode 100644
index 0000000..6de0844
--- /dev/null
+++ b/tools/process-layout.js
@@ -0,0 +1,164 @@
+"use strict"
+
+const fs = require("fs")
+
+let layout = JSON.parse(fs.readFileSync("tools/layout.json", "utf-8"))
+
+function array_insert(array, index, item) {
+ for (let i = array.length; i > index; --i)
+ array[i] = array[i - 1]
+ array[index] = item
+}
+
+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 find_enclosing_rect(list, x, y) {
+ for (let {x1, y1, x2, y2} of list) {
+ if (x >= x1 && x <= x2)
+ if (y >= y1 && y <= y2)
+ return true
+ }
+ return false
+}
+
+const SEAS = [ "Sea1", "Sea2", "Sea3", "Sea4", "Sea5", "Sea6", "Sea7" ]
+const COLONIES = [ "Canada", "NH", "NY", "MA", "CT", "RI", "PA", "NJ", "MD", "DE", "VA", "NC", "SC", "GA", ]
+
+let seas = SEAS.map(x => [])
+let colonies = COLONIES.map(x => [])
+
+let spaces = []
+let space_index = {}
+
+function add_space(type, name, x, y) {
+ let id = spaces.length
+ spaces.push({
+ name,
+ type,
+ adjacent: [],
+ path: [],
+ wilderness: [],
+ port: -1,
+ colony: -1,
+ x: Math.round(x),
+ y: Math.round(y),
+ })
+}
+
+function add_edge(type, a, b) {
+ let ax = space_index[a]
+ let bx = space_index[b]
+ set_add(spaces[ax][type], bx)
+ set_add(spaces[bx][type], ax)
+ set_add(spaces[ax].adjacent, bx)
+ set_add(spaces[bx].adjacent, ax)
+}
+
+function add_oneway(type, a, b, list2, set2) {
+ let ax = space_index[a]
+ let bx = space_index[b]
+ if (ax !== undefined) {
+ let k = list2.indexOf(b)
+ spaces[ax][type] = k
+ set_add(set2[k], ax)
+ }
+ if (bx !== undefined) {
+ let k = list2.indexOf(a)
+ spaces[bx][type] = k
+ set_add(set2[k], bx)
+ }
+}
+
+for (let item of layout.points.fortified_port)
+ add_space("fortified_port", item.name, item.x, item.y)
+for (let item of layout.points.winter_quarters)
+ add_space("winter_quarters", item.name, item.x, item.y)
+for (let item of layout.points.regular)
+ add_space("regular", item.name, item.x, item.y)
+for (let item of layout.points.box)
+ add_space("box", item.name, item.x, item.y)
+
+const TYPE_SORT = [ "fortified_port", "winter_quarters", "regular", "box" ]
+
+spaces.sort((a,b) => {
+ let at = TYPE_SORT.indexOf(a.type)
+ let bt = TYPE_SORT.indexOf(b.type)
+ if (at < bt) return -1
+ if (at > bt) return 1
+ if (a.name < b.name) return -1
+ if (a.name > b.name) return 1
+ return b.y - a.y
+})
+
+for (let i = 0; i < spaces.length; ++i)
+ space_index[spaces[i].name] = i
+
+for (let item of layout.edges.sea)
+ add_oneway("port", item.name1, item.name2, SEAS, seas)
+for (let item of layout.edges.colony)
+ add_oneway("colony", item.name1, item.name2, COLONIES, colonies)
+
+for (let item of layout.edges.path)
+ add_edge("path", item.name1, item.name2)
+for (let item of layout.edges.wilderness)
+ add_edge("wilderness", item.name1, item.name2)
+
+
+function map_point(group, name) {
+ let item = layout.points[group].find(item => item.name === name)
+ return [ item.x, item.y ].map(Math.round)
+}
+
+function map_box(group, name) {
+ let item = layout.boxes[group].find(item => item.name === name)
+ return [ item.x, item.y, item.w, item.h ].map(Math.round)
+}
+
+function map_point_list(group, names) {
+ return names.map(n => map_point(group, n))
+}
+
+function map_box_list(group, names) {
+ return names.map(n => map_box(group, n))
+}
+
+function map_box_dict(list) {
+ let out = {}
+ for (let item of list)
+ out[item.name] = [ item.x, item.y, item.w, item.h ].map(Math.round)
+ return out
+}
+
+function map_point_dict(list) {
+ let out = {}
+ for (let item of list)
+ out[item.name] = [ item.x, item.y ].map(Math.round)
+ return out
+}
+
+let boxes = {
+ sea: map_box_list("sea", SEAS),
+ colony: map_point_list("colony", COLONIES),
+ french_alliance_track: map_point_dict(layout.points["French Alliance Track"]),
+ turn: map_point_dict(layout.points["Game Turn"]),
+ card_box: map_point_dict(layout.points["Card Boxes"]),
+ box: map_box_dict(layout.boxes.box),
+}
+
+let data = { layout: boxes, spaces, space_index, colonies, seas }
+
+fs.writeFileSync("tools/data.json", JSON.stringify(data))
diff --git a/tools/rotate_year.sh b/tools/rotate_year.sh
new file mode 100644
index 0000000..96a6c2b
--- /dev/null
+++ b/tools/rotate_year.sh
@@ -0,0 +1,8 @@
+for DIR in cards75 cards100 cards150 cards200
+do
+ convert -rotate 90 $DIR/card_7.png $DIR/card_7_rot.png
+ convert -rotate 90 $DIR/card_8.png $DIR/card_8_rot.png
+ convert -rotate 90 $DIR/card_9.png $DIR/card_9_rot.png
+ convert -rotate 90 $DIR/card_10.png $DIR/card_10_rot.png
+ convert -rotate 90 $DIR/card_11.png $DIR/card_11_rot.png
+done