summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--const.js36
-rw-r--r--data.js2
-rw-r--r--play.html1
-rw-r--r--tools/gendata.js242
-rw-r--r--tools/genlayout.py51
-rw-r--r--tools/makelayout.js59
-rw-r--r--tools/pieces_layout.svg619
8 files changed, 1013 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0af05bc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,3 @@
+default: rules.js
+rules.js:
+ sed -i -ne '/\/\/ === CONST ===/ {p; r const.js' -e ':a; n; /\/\/ === CONST ===/ {p; b}; ba}; p' rules.js \ No newline at end of file
diff --git a/const.js b/const.js
new file mode 100644
index 0000000..32003b8
--- /dev/null
+++ b/const.js
@@ -0,0 +1,36 @@
+
+// Factions
+const DS = 0
+const BK = 1
+const VE = 2
+const MI = 3
+
+// Role names
+const NAME_DS = "DS"
+const NAME_BK = "BK"
+const NAME_VE = "VE"
+const NAME_SOLO = "Solo"
+
+// Player pieces types
+const DISC = 0
+const ELITE = 1
+const TROOPS = 2
+
+// Pieces status
+const AVAILABLE = -1
+const OUT_OF_PLAY = -2
+const ANY_PIECES = [ DISC, ELITE, TROOPS ]
+const PIECE_FACTION_TYPE_NAME = [
+ [ "Qasbah", "Governors", "Troops" ],
+ [ "Fort", "Amirs", null ],
+ [ "Temple", "Rajas", null ],
+ [ null, null, "Invaders"]
+]
+
+// Sequence of Play options
+const ELIGIBLE = 0
+const SOP_LIMITED_COMMAND = 1
+const SOP_COMMAND_DECREE = 2
+const SOP_EVENT_OR_COMMAND = 3
+const SOP_PASS = 4
+const INELIGIBLE = 5
diff --git a/data.js b/data.js
new file mode 100644
index 0000000..9c7dbaa
--- /dev/null
+++ b/data.js
@@ -0,0 +1,2 @@
+const data = {"card_title":[null,"Malik Kafur","Mongol Army Repelled","Diamond Mines of Golconda","Ears of the Sultan","Siege of Chittor","Siege of Warangal","The Conquest of Madurai","Yadava Kingdom Annexed","Kakatiya Empire Extinguished","Capital Relocated","Hindu Kush Mountains","Musunuri Nayakas","Sage of Vidyaranya","Last Great King of the Hoysalas","Uprising in Daulatabad","Gulbarga Fort","Sufi Shaikh Relocates","Center of High Culture","Bengali Resistance","Eastern Ganga Dynasty","Vindhya Range","A New Calculus","Virupaksha Temple","Stone Temple Chariots","Empire Building","Of Gods and Kings","Taghi the Elusive","The Turquoise Throne","Ashvapati, Lord of Horses","Bara Gazi Toph","The Raichur Doab","The Hare and the Hounds","Commercial Port of Goa","Bahmani Sultan Assassinated","Hindu-Muslim Marriages","Northern Alliances"],"card_order":[null,[0,1,2],[0,1,2],[1,0,2],[0,2,1],[2,0,1],[0,2,1],[0,2,1],[0,1,2],[0,2,1],[1,0,2],[0,1,2],[2,0,1],[2,1,0],[2,1,0],[1,0,2],[1,2,0],[1,2,0],[1,2,0],[1,0,2],[0,1,2],[0,1,2],[0,2,1],[2,0,1],[2,0,1],[2,1,0],[2,1,0],[0,2,1],[1,2,0],[1,0,2],[1,0,2],[1,2,0],[2,1,0],[2,1,0],[2,0,1],[1,2,0],[2,0,1]],"card_flavor":[null,"General assassinated, power struggle ensues","Pyrrhic victory","Untold riches lie just beneath the surface","Sultan’s plans intercepted","Hammir Singh reclaims a Rajput Kingdom","Continual looting encourages resistance","Tale of Madurai Sultan’s defeat chronicled in epic Sanskrit poem","Multi-ethnic polity seeds development","Telugu kingdom leaves a mythic legacy","Political damage and chaos ensues as the Delhi elite is forced to migrate","Sultanate army perishes in the snow on a scheme of foreign conquest","“Warrior kings” rise in the shadow of the Kakatiya Empire","Meeting with revered jagadguru in Sringeri sparks a foundational myth","Vijayanagara emerges from the crumbling kingdom of Veera Ballala III","Delhi resentment reaches breaking point","Defenses expanded in the first Bahmani capital","Siraj-al-Din Junaidi takes up residence","Bahmani Kingdom attracts great minds from afar; culture flourishes in the Deccan","Governors repeatedly assert independence","Prosperous kingdom falls into decline","Mountainous region provides a natural buffer from Delhi","Madhava of Sangamagrama founds the Kerala School of Astronomy and Mathematics","Temple to Shiva merges regional goddess cults","Chariots carry representations of Puranic Hindu gods","Lords of the Eastern and Western Oceans","Telugu poet Srinatha revolutionizes the craft and weaves the tapestry of an Empire, while Sufi devotional songs of Amir Khusrau praise the Sultans in Delhi","Fugitive rebel an expensive distraction","Bahmanis cross the Krishna river into Telangana","Bahmani rulers likened to Hindu god","Gigantic cannons defend Bahmani forts","Repeated raids over fertile lands","Identical empire origin stories lean on regional cult mythologies","Struggle for critical maritime routes","Vijayanagara captures Goa while the Bahmanis are destabilized","Bahmani Sultan weds a Hindu bride","Vijayanagara probes an alliance with Delhi"],"card_flavor_shaded":[null,"Favored slave-general brilliant in battle","Sultan’s mercenary army victorious","Sultan’s oppressive taxation","Network of spies covers the Deccan","Massacre at Chittor","Koh-i-Noor diamond among war spoils","Sultan’s generals plunder Pandyan kingdom","Sultanate reclaims natural stronghold","Sultanate tires of awaiting tribute","Sultan shortens his reach into the Deccan","Grandiose schemes pay dividends","Telugu warriors no match for siege technology from Central Asia","Inferior military suffers early defeats","Delhi’s armies plunder the Hoysala Capital","Commanders sentenced to death","Bahmani Kingdom threatens control","Relationships sour between Bahmani rulers and Sufi shaikhs","Divisions among Deccanis and newcomers","Criminals conscripted to reclaim Bengal","Sultanate invades Orissa","Long campaigns go unchallenged","Narayana Pandita’s mathematical treatises offer new insights of immediate use","Symbols of sovereignty destroyed","Cultural development draws interest","Sultan’s new roads thrust into the Deccan",null,"The Sultan marches west in pursuit","Telangana Nayakas implore allies to attack","War horses and siege technology imported from overseas","Gunpowder and cannons appear suddenly in the subcontinent","Massive casualties in both kingdoms","Persian values inherited from Delhi","Competition over ports boils over","Bahmani successor ushers in a period of social reform and cultural revival","Diffusion and dilution of culture","Alliance rejected"],"spaces":[{"type":"province","id":"Andhra","pop":1,"adjacent":[2,5,6,7,9,12]},{"type":"province","id":"Bengal","pop":2,"adjacent":[2,4,9]},{"type":"province","id":"Gondwana","pop":1,"adjacent":[0,1,4,6,9]},{"type":"province","id":"Gujarat","pop":2,"adjacent":[6,7,8,10,11]},{"type":"province","id":"Jaunpur","pop":1,"adjacent":[1,2,13,8]},{"type":"province","id":"Karnataka","pop":2,"adjacent":[0,7,12]},{"type":"province","id":"Madhyadesh","pop":1,"adjacent":[0,2,3,8,7,9]},{"type":"province","id":"Maharashtra","pop":2,"adjacent":[0,3,5,6,8]},{"type":"province","id":"Malwa","pop":2,"adjacent":[3,4,6,7,13,10]},{"type":"province","id":"Orissa","pop":1,"adjacent":[0,1,2,6]},{"type":"province","id":"Rajput Kingdoms","pop":1,"adjacent":[3,8,13,15,11]},{"type":"province","id":"Sindh","pop":1,"adjacent":[3,10,14,15]},{"type":"province","id":"Tamilakam","pop":1,"adjacent":[0,5]},{"type":"capital","id":"Delhi","pop":0,"adjacent":[4,8,10,15]},{"type":"mongol","id":"Mountain Passes","pop":0,"adjacent":[11,15]},{"type":"mongol","id":"Punjab","pop":0,"adjacent":[10,11,13,14]}],"space_name":["Andhra","Bengal","Gondwana","Gujarat","Jaunpur","Karnataka","Madhyadesh","Maharashtra","Malwa","Orissa","Rajput Kingdoms","Sindh","Tamilakam","Delhi","Mountain Passes","Punjab"],"first_piece":[[0,5,10],[42,47,null],[65,70,null],[null,null,92]],"last_piece":[[4,9,41],[46,64,null],[69,91,null],[null,null,103]]}
+if (typeof module !== 'undefined') module.exports = data
diff --git a/play.html b/play.html
index f0b502b..773e578 100644
--- a/play.html
+++ b/play.html
@@ -11,6 +11,7 @@
<link rel="stylesheet" href="/common/client.css">
<link rel="stylesheet" href="play.css">
<script defer src="/common/client.js"></script>
+<script defer src ="const.js"></script>
<script defer src="data.js"></script>
<script defer src="play.js"></script>
</head>
diff --git a/tools/gendata.js b/tools/gendata.js
new file mode 100644
index 0000000..b6eb19f
--- /dev/null
+++ b/tools/gendata.js
@@ -0,0 +1,242 @@
+let fs = require("fs")
+
+let data = {}
+
+// Factions
+const DS = 0
+const BK = 1
+const VE = 2
+const MI = 3
+
+// Pieces
+const DISC = 0
+const ELITE = 1
+const TROOPS = 2
+
+// Creating cards
+const IMAP = { D: DS, B: BK, V: VE }
+let order = null
+data.card_title = [ null ]
+data.card_order = [ null ]
+data.card_flavor = []
+data.card_flavor_shaded = []
+
+function def_order(s) {
+ order = [ IMAP[s[0]], IMAP[s[1]], IMAP[s[2]] ]
+}
+
+function def_card(number, name) {
+ data.card_title[number] = name
+ data.card_order[number] = order
+}
+
+function flavor(id, unshaded, shaded) {
+ id = parseInt(id)
+ if (unshaded)
+ data.card_flavor[id] = unshaded
+ if (shaded)
+ data.card_flavor_shaded[id] = shaded
+}
+
+def_order("BDV")
+def_card(3, "Diamond Mines of Golconda")
+def_card(10, "Capital Relocated")
+def_card(15, "Uprising in Daulatabad")
+def_card(19, "Bengali Resistance")
+def_card(29, "Ashvapati, Lord of Horses")
+def_card(30, "Bara Gazi Toph")
+def_order("BVD")
+def_card(16, "Gulbarga Fort")
+def_card(17, "Sufi Shaikh Relocates")
+def_card(18, "Center of High Culture")
+def_card(28, "The Turquoise Throne")
+def_card(31, "The Raichur Doab")
+def_card(35, "Hindu-Muslim Marriages")
+def_order("DBV")
+def_card(1, "Malik Kafur")
+def_card(2, "Mongol Army Repelled")
+def_card(8, "Yadava Kingdom Annexed")
+def_card(11, "Hindu Kush Mountains")
+def_card(20, "Eastern Ganga Dynasty")
+def_card(21, "Vindhya Range")
+def_order("DVB")
+def_card(4, "Ears of the Sultan")
+def_card(6, "Siege of Warangal")
+def_card(7, "The Conquest of Madurai")
+def_card(9, "Kakatiya Empire Extinguished")
+def_card(22, "A New Calculus")
+def_card(27, "Taghi the Elusive")
+def_order("VBD")
+def_card(13, "Sage of Vidyaranya")
+def_card(14, "Last Great King of the Hoysalas")
+def_card(25, "Empire Building")
+def_card(26, "Of Gods and Kings")
+def_card(32, "The Hare and the Hounds")
+def_card(33, "Commercial Port of Goa")
+def_order("VDB")
+def_card(5, "Siege of Chittor")
+def_card(12, "Musunuri Nayakas")
+def_card(23, "Virupaksha Temple")
+def_card(24, "Stone Temple Chariots")
+def_card(34, "Bahmani Sultan Assassinated")
+def_card(36, "Northern Alliances")
+
+
+flavor("1. Malik Kafur", "General assassinated, power struggle ensues", "Favored slave-general brilliant in battle")
+flavor("2. Mongol Army Repelled", "Pyrrhic victory", "Sultan’s mercenary army victorious")
+flavor("3. Diamond Mines of Golconda", "Untold riches lie just beneath the surface", "Sultan’s oppressive taxation")
+flavor("4. Ears of the Sultan", "Sultan’s plans intercepted", "Network of spies covers the Deccan")
+flavor("5. Siege of Chittor", "Hammir Singh reclaims a Rajput Kingdom", "Massacre at Chittor")
+flavor("6. Siege of Warangal", "Continual looting encourages resistance", "Koh-i-Noor diamond among war spoils")
+flavor("7. The Conquest of Madurai", "Tale of Madurai Sultan’s defeat chronicled in epic Sanskrit poem", "Sultan’s generals plunder Pandyan kingdom")
+flavor("8. Yadava Kingdom Annexed", "Multi-ethnic polity seeds development", "Sultanate reclaims natural stronghold")
+flavor("9. Kakatiya Empire Extinguished", "Telugu kingdom leaves a mythic legacy", "Sultanate tires of awaiting tribute")
+flavor("10. Capital Relocated", "Political damage and chaos ensues as the Delhi elite is forced to migrate", "Sultan shortens his reach into the Deccan")
+flavor("11. Hindu Kush Mountains", "Sultanate army perishes in the snow on a scheme of foreign conquest", "Grandiose schemes pay dividends")
+flavor("12. Musunuri Nayakas", "“Warrior kings” rise in the shadow of the Kakatiya Empire", "Telugu warriors no match for siege technology from Central Asia")
+flavor("13. Sage of Vidyaranya", "Meeting with revered jagadguru in Sringeri sparks a foundational myth", "Inferior military suffers early defeats")
+flavor("14. Last Great King of the Hoysalas", "Vijayanagara emerges from the crumbling kingdom of Veera Ballala III", "Delhi’s armies plunder the Hoysala Capital")
+flavor("15. Uprising in Daulatabad", "Delhi resentment reaches breaking point", "Commanders sentenced to death")
+flavor("16. Gulbarga Fort", "Defenses expanded in the first Bahmani capital", "Bahmani Kingdom threatens control")
+flavor("17. Sufi Shaikh Relocates", "Siraj-al-Din Junaidi takes up residence", "Relationships sour between Bahmani rulers and Sufi shaikhs")
+flavor("18. Center of High Culture", "Bahmani Kingdom attracts great minds from afar; culture flourishes in the Deccan", "Divisions among Deccanis and newcomers")
+flavor("19. Bengali Resistance", "Governors repeatedly assert independence", "Criminals conscripted to reclaim Bengal")
+flavor("20. Eastern Ganga Dynasty", "Prosperous kingdom falls into decline", "Sultanate invades Orissa")
+flavor("21. Vindhya Range", "Mountainous region provides a natural buffer from Delhi", "Long campaigns go unchallenged")
+flavor("22. A New Calculus", "Madhava of Sangamagrama founds the Kerala School of Astronomy and Mathematics", "Narayana Pandita’s mathematical treatises offer new insights of immediate use")
+flavor("23. Virupaksha Temple", "Temple to Shiva merges regional goddess cults", "Symbols of sovereignty destroyed")
+flavor("24. Stone Temple Chariots", "Chariots carry representations of Puranic Hindu gods", "Cultural development draws interest")
+flavor("25. Empire Building", "Lords of the Eastern and Western Oceans", "Sultan’s new roads thrust into the Deccan")
+flavor("26. Of Gods and Kings", "Telugu poet Srinatha revolutionizes the craft and weaves the tapestry of an Empire, while Sufi devotional songs of Amir Khusrau praise the Sultans in Delhi", "")
+flavor("27. Taghi the Elusive", "Fugitive rebel an expensive distraction", "The Sultan marches west in pursuit")
+flavor("28. The Turquoise Throne", "Bahmanis cross the Krishna river into Telangana", "Telangana Nayakas implore allies to attack")
+flavor("29. Ashvapati, Lord of Horses", "Bahmani rulers likened to Hindu god", "War horses and siege technology imported from overseas")
+flavor("30. Bara Gazi Toph", "Gigantic cannons defend Bahmani forts", "Gunpowder and cannons appear suddenly in the subcontinent")
+flavor("31. The Raichur Doab", "Repeated raids over fertile lands", "Massive casualties in both kingdoms")
+flavor("32. The Hare and the Hounds", "Identical empire origin stories lean on regional cult mythologies", "Persian values inherited from Delhi")
+flavor("33. Commercial Port of Goa", "Struggle for critical maritime routes", "Competition over ports boils over")
+flavor("34. Bahmani Sultan Assassinated", "Vijayanagara captures Goa while the Bahmanis are destabilized", "Bahmani successor ushers in a period of social reform and cultural revival")
+flavor("35. Hindu-Muslim Marriages", "Bahmani Sultan weds a Hindu bride", "Diffusion and dilution of culture")
+flavor("36. Northern Alliances", "Vijayanagara probes an alliance with Delhi", "Alliance rejected")
+
+// Defining spaces
+data.spaces = [ ]
+data.space_name = [ ]
+
+function def_space(type, pop, name) {
+ data.spaces.push({ type, id: to_ascii(name), pop, adjacent: [] })
+ data.space_name.push(name)
+}
+
+function adjacent(an, bn) {
+ ax = data.space_name.indexOf(an)
+ bx = data.space_name.indexOf(bn)
+ add(data.spaces[ax].adjacent, bx)
+ add(data.spaces[bx].adjacent, ax)
+}
+
+def_space("province", 1, "Andhra")
+def_space("province", 2, "Bengal")
+def_space("province", 1, "Gondwana")
+def_space("province", 2, "Gujarat")
+def_space("province", 1, "Jaunpur")
+def_space("province", 2, "Karnataka")
+def_space("province", 1, "Madhyadesh")
+def_space("province", 2, "Maharashtra")
+def_space("province", 2, "Malwa")
+def_space("province", 1, "Orissa")
+def_space("province", 1, "Rajput Kingdoms")
+def_space("province", 1, "Sindh")
+def_space("province", 1, "Tamilakam")
+def_space("capital", 0, "Delhi")
+def_space("mongol", 0, "Mountain Passes")
+def_space("mongol", 0, "Punjab")
+
+
+adjacent("Andhra", "Gondwana")
+adjacent("Andhra", "Karnataka")
+adjacent("Andhra", "Madhyadesh")
+adjacent("Andhra", "Maharashtra")
+adjacent("Andhra", "Orissa")
+adjacent("Andhra", "Tamilakam")
+
+adjacent("Bengal", "Gondwana")
+adjacent("Bengal", "Jaunpur")
+adjacent("Bengal", "Orissa")
+
+adjacent("Gondwana", "Jaunpur")
+adjacent("Gondwana", "Madhyadesh")
+adjacent("Gondwana", "Orissa")
+
+adjacent("Gujarat", "Madhyadesh")
+adjacent("Gujarat", "Maharashtra")
+adjacent("Gujarat", "Malwa")
+adjacent("Gujarat", "Rajput Kingdoms")
+adjacent("Gujarat", "Sindh")
+
+adjacent("Jaunpur", "Delhi")
+adjacent("Jaunpur", "Malwa")
+
+adjacent("Karnataka", "Maharashtra")
+adjacent("Karnataka", "Tamilakam")
+
+adjacent("Madhyadesh", "Malwa")
+adjacent("Madhyadesh", "Maharashtra")
+adjacent("Madhyadesh", "Orissa")
+
+adjacent("Maharashtra", "Malwa")
+
+adjacent("Malwa", "Delhi")
+adjacent("Malwa", "Rajput Kingdoms")
+
+adjacent("Rajput Kingdoms", "Delhi")
+adjacent("Rajput Kingdoms", "Punjab")
+adjacent("Rajput Kingdoms", "Sindh")
+
+adjacent("Sindh", "Mountain Passes")
+adjacent("Sindh", "Punjab")
+
+adjacent("Punjab", "Delhi")
+adjacent("Punjab", "Mountain Passes")
+
+// Pieces numbers
+function def_piece(faction, type, count) {
+ if (count == 0) {
+ data.first_piece[faction][type] = null
+ data.last_piece[faction][type] = null
+ } else {
+ data.first_piece[faction][type] = pc_index
+ data.last_piece[faction][type] = pc_index + count - 1
+ pc_index += count
+ }
+}
+
+pc_index = 0
+data.first_piece = [ [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0] ]
+data.last_piece = [ [-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1] ]
+def_piece(DS, DISC, 5)
+def_piece(DS, ELITE, 5)
+def_piece(DS, TROOPS, 32)
+def_piece(BK, DISC, 5)
+def_piece(BK, ELITE, 18)
+def_piece(BK, TROOPS, 0)
+def_piece(VE, DISC, 5)
+def_piece(VE, ELITE, 22)
+def_piece(VE, TROOPS, 0)
+def_piece(MI, DISC, 0)
+def_piece(MI, ELITE, 0)
+def_piece(MI, TROOPS, 12)
+
+
+// Tools
+function add(list, item) {
+ if (!list.includes(item))
+ list.push(item)
+}
+
+function to_ascii(s) {
+ return s.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
+}
+
+// Output data file
+fs.writeFileSync("data.js", "const data = " + JSON.stringify(data, 0, 0) + "\nif (typeof module !== 'undefined') module.exports = data\n")
diff --git a/tools/genlayout.py b/tools/genlayout.py
new file mode 100644
index 0000000..54b1724
--- /dev/null
+++ b/tools/genlayout.py
@@ -0,0 +1,51 @@
+list = []
+
+def flush():
+ global mode, name, x, y, w, h
+ if mode == 'rect':
+ list.append((name, round(x+w/2), round(y+h/2)))
+ if mode == 'circle':
+ list.append((name, round(x), round(y)))
+ mode = None
+
+def readsvg(filename):
+ global mode, name, x, y, w, h
+ mode = None
+ name = None
+ x = y = w = h = 0
+ for line in open(filename).readlines():
+ line = line.strip()
+ if line == "<rect":
+ flush()
+ mode = 'rect'
+ x = y = w = h = 0
+ name = None
+ elif line == "<ellipse" or line == "<circle":
+ flush()
+ mode = 'circle'
+ x = y = w = h = 0
+ name = None
+ elif line == "<text":
+ flush()
+ mode = None
+ if line.startswith('x="'): x = round(float(line.split('"')[1]))
+ if line.startswith('y="'): y = round(float(line.split('"')[1]))
+ if line.startswith('width="'): w = round(float(line.split('"')[1]))
+ if line.startswith('height="'): h = round(float(line.split('"')[1]))
+ if line.startswith('cx="'): x = round(float(line.split('"')[1]))
+ if line.startswith('cy="'): y = round(float(line.split('"')[1]))
+ if line.startswith('inkscape:label="'):
+ name = line.split('"')[1]
+ flush()
+
+readsvg("tools/pieces_layout.svg")
+
+def print_list():
+ print("const LAYOUT = {")
+ for (name,x,y) in list:
+ xc = round((x+w/2.0))
+ yc = round((y+h/2.0))
+ print(f'\t"{name}": [{x}, {y}],')
+ print("}")
+
+print_list()
diff --git a/tools/makelayout.js b/tools/makelayout.js
new file mode 100644
index 0000000..c187254
--- /dev/null
+++ b/tools/makelayout.js
@@ -0,0 +1,59 @@
+const PROVINCES = [
+ "Andhra",
+ "Bengal",
+ "Gondwana",
+ "Gujarat",
+ "Jaunpur",
+ "Karnataka",
+ "Madhyadesh",
+ "Maharashtra",
+ "Malwa",
+ "Orissa",
+ "Rajput Kingdoms",
+ "Sindh",
+ "Tamilakam",
+ "Delhi",
+ "Mountain Passes",
+ "Punjab",
+]
+
+const print = console.log
+
+print('<?xml version="1.0" encoding="UTF-8"?>')
+print('<svg')
+print('\txmlns="http://www.w3.org/2000/svg"')
+print('\txmlns:xlink="http://www.w3.org/1999/xlink"')
+print('\txmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"')
+print('\txmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"')
+print('\twidth="1275" height="1650">')
+print('<image xlink:href="map75.jpg" x="0" y="0" width="1275" height="1650" image-rendering="pixelated" sodipodi:insensitive="true" />')
+
+const COLORS = {
+ DS: "black",
+ BK: "cyan",
+ VE: "yellow",
+ mongols: "red",
+}
+
+let x = -700, y = 100
+
+function advancex() {
+ x += 150
+}
+
+function advancey() {
+ x -= 150 * 4
+ y += 100
+}
+
+for (let s of PROVINCES) {
+ // faction holdings - 100x80 ellipse
+ print(`<text x="${x-100}" y="${y}" text-anchor="end" font-size="40">${s}</text>`)
+ for (let f of [ "DS", "BK", "VE", "mongols" ]) {
+ print(`<ellipse inkscape:label="${s} ${f}" cx="${x}" cy="${y}" rx="40" ry="30" fill="${COLORS[f]}" fill-opacity="0.5" />`)
+ advancex()
+ }
+ advancey()
+}
+
+print('</svg>')
diff --git a/tools/pieces_layout.svg b/tools/pieces_layout.svg
new file mode 100644
index 0000000..c4d2cc2
--- /dev/null
+++ b/tools/pieces_layout.svg
@@ -0,0 +1,619 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="1275"
+ height="1650"
+ version="1.1"
+ id="svg64"
+ sodipodi:docname="test.svg"
+ inkscape:version="1.3.2 (091e20e, 2023-11-25)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs64" />
+ <sodipodi:namedview
+ id="namedview64"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="0.24727273"
+ inkscape:cx="-264.88971"
+ inkscape:cy="598.52941"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg64" />
+ <image
+ xlink:href="../map75.jpg"
+ x="0"
+ y="0"
+ width="1275"
+ height="1650"
+ image-rendering="pixelated"
+ sodipodi:insensitive="true"
+ id="image1" />
+ <ellipse
+ inkscape:label="Andhra DS"
+ cx="785.10834"
+ cy="1013.6342"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse1" />
+ <ellipse
+ inkscape:label="Andhra BK"
+ cx="678.47357"
+ cy="1060.1261"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse2" />
+ <ellipse
+ inkscape:label="Andhra VE"
+ cx="653.30853"
+ cy="1165.0927"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse3" />
+ <ellipse
+ inkscape:label="Andhra mongols"
+ cx="747.90259"
+ cy="1214.5952"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse4" />
+ <ellipse
+ inkscape:label="Bengal DS"
+ cx="1147.8877"
+ cy="454.87421"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse5" />
+ <ellipse
+ inkscape:label="Bengal BK"
+ cx="1078.7566"
+ cy="536.22742"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse6" />
+ <ellipse
+ inkscape:label="Bengal VE"
+ cx="1122.0199"
+ cy="626.24115"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse7" />
+ <ellipse
+ inkscape:label="Bengal mongols"
+ cx="1208.5535"
+ cy="663.23492"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse8" />
+ <ellipse
+ inkscape:label="Gondwana DS"
+ cx="991.91602"
+ cy="685.04767"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse9" />
+ <ellipse
+ inkscape:label="Gondwana BK"
+ cx="848.12048"
+ cy="695.11127"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse10" />
+ <ellipse
+ inkscape:label="Gondwana VE"
+ cx="863.57416"
+ cy="842.24976"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse11" />
+ <ellipse
+ inkscape:label="Gondwana mongols"
+ cx="990.3092"
+ cy="743.26917"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse12" />
+ <ellipse
+ inkscape:label="Gujarat DS"
+ cx="362.35681"
+ cy="611.13867"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse13" />
+ <ellipse
+ inkscape:label="Gujarat BK"
+ cx="250.2686"
+ cy="601.49054"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse14" />
+ <ellipse
+ inkscape:label="Gujarat VE"
+ cx="385.84372"
+ cy="722.84753"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse15" />
+ <ellipse
+ inkscape:label="Gujarat mongols"
+ cx="133.53917"
+ cy="611.11877"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse16" />
+ <ellipse
+ inkscape:label="Jaunpur DS"
+ cx="979.46338"
+ cy="422.46359"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse17" />
+ <ellipse
+ inkscape:label="Jaunpur BK"
+ cx="787.50323"
+ cy="525.53986"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse18" />
+ <ellipse
+ inkscape:label="Jaunpur VE"
+ cx="914.74194"
+ cy="586.41663"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse19" />
+ <ellipse
+ inkscape:label="Jaunpur mongols"
+ cx="867.44952"
+ cy="385.47809"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse20" />
+ <ellipse
+ inkscape:label="Karnataka DS"
+ cx="551.49963"
+ cy="1212.6781"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse21" />
+ <ellipse
+ inkscape:label="Karnataka BK"
+ cx="651.41888"
+ cy="1298.4513"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse22" />
+ <ellipse
+ inkscape:label="Karnataka VE"
+ cx="572.3526"
+ cy="1389.6414"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse23" />
+ <ellipse
+ inkscape:label="Karnataka mongols"
+ cx="482.74741"
+ cy="1253.7037"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse24" />
+ <ellipse
+ inkscape:label="Madhyadesh DS"
+ cx="724.0636"
+ cy="746.15338"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse25" />
+ <ellipse
+ inkscape:label="Madhyadesh BK"
+ cx="571.19043"
+ cy="868.23297"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse26" />
+ <ellipse
+ inkscape:label="Madhyadesh VE"
+ cx="652.80389"
+ cy="940.88025"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse27" />
+ <ellipse
+ inkscape:label="Madhyadesh mongols"
+ cx="613.45172"
+ cy="769.71881"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse28" />
+ <ellipse
+ inkscape:label="Maharashtra DS"
+ cx="464.92444"
+ cy="907.37817"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse29" />
+ <ellipse
+ inkscape:label="Maharashtra BK"
+ cx="531.46307"
+ cy="997.39044"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse30" />
+ <ellipse
+ inkscape:label="Maharashtra VE"
+ cx="524.80768"
+ cy="1083.5806"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse31" />
+ <ellipse
+ inkscape:label="Maharashtra mongols"
+ cx="386.88681"
+ cy="900.46082"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse32" />
+ <ellipse
+ inkscape:label="Malwa DS"
+ cx="681.62103"
+ cy="573.92773"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse33" />
+ <ellipse
+ inkscape:label="Malwa BK"
+ cx="514.99274"
+ cy="622.97754"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse34" />
+ <ellipse
+ inkscape:label="Malwa VE"
+ cx="510.99982"
+ cy="735.04401"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse35" />
+ <ellipse
+ inkscape:label="Malwa mongols"
+ cx="536.92621"
+ cy="556.5993"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse36" />
+ <ellipse
+ inkscape:label="Orissa DS"
+ cx="1167.697"
+ cy="797.57922"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse37" />
+ <ellipse
+ inkscape:label="Orissa BK"
+ cx="1081.6849"
+ cy="799.6156"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse38" />
+ <ellipse
+ inkscape:label="Orissa VE"
+ cx="955.17651"
+ cy="929.42145"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse39" />
+ <ellipse
+ inkscape:label="Orissa mongols"
+ cx="935.16193"
+ cy="990.98254"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse40" />
+ <ellipse
+ inkscape:label="Rajput Kingdoms DS"
+ cx="427.15005"
+ cy="366.9664"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse41" />
+ <ellipse
+ inkscape:label="Rajput Kingdoms BK"
+ cx="205.18614"
+ cy="482.89713"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse42" />
+ <ellipse
+ inkscape:label="Rajput Kingdoms VE"
+ cx="433.16797"
+ cy="502.22614"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse43" />
+ <ellipse
+ inkscape:label="Rajput Kingdoms mongols"
+ cx="228.93816"
+ cy="382.51443"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse44" />
+ <ellipse
+ inkscape:label="Sindh DS"
+ cx="110.45609"
+ cy="327.46213"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse45" />
+ <ellipse
+ inkscape:label="Sindh BK"
+ cx="40.239883"
+ cy="491.85406"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse46" />
+ <ellipse
+ inkscape:label="Sindh VE"
+ cx="42.381397"
+ cy="543.638"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse47" />
+ <ellipse
+ inkscape:label="Sindh mongols"
+ cx="36.135269"
+ cy="344.03363"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse48" />
+ <ellipse
+ inkscape:label="Tamilakam DS"
+ cx="756.05219"
+ cy="1337.683"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse49" />
+ <ellipse
+ inkscape:label="Tamilakam BK"
+ cx="647.92712"
+ cy="1477.6115"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse50" />
+ <ellipse
+ inkscape:label="Tamilakam VE"
+ cx="657.41528"
+ cy="1543.4928"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse51" />
+ <ellipse
+ inkscape:label="Tamilakam mongols"
+ cx="752.04889"
+ cy="1394.1047"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse52" />
+ <ellipse
+ inkscape:label="Delhi DS"
+ cx="717.75586"
+ cy="315.85837"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse53" />
+ <ellipse
+ inkscape:label="Delhi BK"
+ cx="570.71161"
+ cy="422.11594"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse54" />
+ <ellipse
+ inkscape:label="Delhi VE"
+ cx="723.77979"
+ cy="414.29138"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse55" />
+ <ellipse
+ inkscape:label="Delhi mongols"
+ cx="572.69818"
+ cy="323.68002"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse56" />
+ <ellipse
+ inkscape:label="Mountain Passes DS"
+ cx="403.78482"
+ cy="105.72476"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse57" />
+ <ellipse
+ inkscape:label="Mountain Passes BK"
+ cx="235.53142"
+ cy="110.03997"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse58" />
+ <ellipse
+ inkscape:label="Mountain Passes VE"
+ cx="318.04935"
+ cy="105.33498"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse59" />
+ <ellipse
+ inkscape:label="Mountain Passes mongols"
+ cx="262.96384"
+ cy="182.53125"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse60" />
+ <ellipse
+ inkscape:label="Punjab DS"
+ cx="503.7612"
+ cy="170.15195"
+ rx="40"
+ ry="30"
+ fill="#000000"
+ fill-opacity="0.5"
+ id="ellipse61" />
+ <ellipse
+ inkscape:label="Punjab BK"
+ cx="278.87726"
+ cy="262.32489"
+ rx="40"
+ ry="30"
+ fill="#00ffff"
+ fill-opacity="0.5"
+ id="ellipse62" />
+ <ellipse
+ inkscape:label="Punjab VE"
+ cx="476.74246"
+ cy="265.74405"
+ rx="40"
+ ry="30"
+ fill="#ffff00"
+ fill-opacity="0.5"
+ id="ellipse63" />
+ <ellipse
+ inkscape:label="Punjab mongols"
+ cx="370.125"
+ cy="233.37929"
+ rx="40"
+ ry="30"
+ fill="#ff0000"
+ fill-opacity="0.5"
+ id="ellipse64" />
+</svg>