summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--events.txt15
-rw-r--r--play.html16
-rw-r--r--play.js14
-rw-r--r--rules.js327
4 files changed, 349 insertions, 23 deletions
diff --git a/events.txt b/events.txt
index 2e0d144..0bea465 100644
--- a/events.txt
+++ b/events.txt
@@ -2,9 +2,12 @@
CARD 1 - Seneca Falls Convention
# Add 1 :purple_campaigner and 1 :yellow_campaigner in the Northeast region. Receive 2 :button and add 2 :purple_or_yellow_cube in New York.
- add_campaigner 1 PURPLE NORTHEAST
- add_campaigner 1 YELLOW NORTHEAST
+ prompt "Add 1 :purple_campaigner and 1 :yellow_campaigner in the Northeast region."
+ add_campaigner PURPLE NORTHEAST
+ add_campaigner YELLOW NORTHEAST
+ prompt "Receive 2 :button."
receive_buttons 2
+ prompt "Add 2 :purple_or_yellow_cube in New York."
add_cubes 2 PURPLE_OR_YELLOW us_states("New York")
CARD 2 - Property Rights for Women
@@ -101,7 +104,7 @@ CARD 18 - National Woman’s Rights Convention
CARD 19 - National American Woman Suffrage Association
# Add 1 :purple_campaigner in the Atlantic & Appalachia region. Receive 3 :button.
- add_campaigner 1 PURPLE ATLANTIC_APPALACHIA
+ add_campaigner PURPLE ATLANTIC_APPALACHIA
receive_buttons 3
CARD 20 - Jeannette Rankin
@@ -189,7 +192,7 @@ CARD 35 - Southern Strategy
CARD 36 - Women’s Trade Union League
# Add 1 :yellow_campaigner in the Atlantic & Appalachia region. Add 1 :congressional_marker in Congress and receive 2 :button.
- add_cubes_in_each_of 1 YELLOW region_us_states(ATLANTIC_APPALACHIA)
+ add_campaigner YELLOW ATLANTIC_APPALACHIA
add_congress 1
receive_buttons 2
@@ -277,7 +280,7 @@ CARD 52 - Miss Febb Wins the Last Vote
CARD 53 - The Patriarchy
# Add 1 :red_campaigner in the South region. Receive 4 :button. Add 1 :red_cube in each state in the Northeast region, the Atlantic & Appalachia region, the South region and the Midwest region.
- add_campaigner 1 RED SOUTH
+ add_campaigner RED SOUTH
receive_buttons 4
add_cubes_in_each_of 1 RED region_us_states(NORTHEAST, ATLANTIC_APPALACHIA, SOUTH, MIDWEST)
@@ -373,7 +376,7 @@ CARD 70 - Old Dixie
CARD 71 - NAOWS Forms
# Add 1 :red_campaigner in the Northeast region. Receive 2 :button.
- add_campaigner 1 NORTHEAST
+ add_campaigner NORTHEAST
receive_buttons 2
CARD 72 - Woman and the Republic
diff --git a/play.html b/play.html
index 176bb74..4948e79 100644
--- a/play.html
+++ b/play.html
@@ -124,6 +124,12 @@ svg {
position: absolute;
}
+path.state.action {
+ fill: yellow; fill-opacity: 0.8;
+ stroke: white;
+ stroke-width: 20;
+}
+
path.state:hover {
fill: white;
}
@@ -139,6 +145,11 @@ div.state {
height: 64px;
}
+div.state.action {
+ background-color: rgba(251, 186, 0, 0.5);
+ border-color: white;
+}
+
div.state:hover {
background-color: #fff8;
}
@@ -154,6 +165,11 @@ div.region {
height: 65px;
}
+div.region.action {
+ background-color: rgba(251, 186, 0, 0.5);
+ border-color: white;
+}
+
div.region:hover {
background-color: #fff8;
}
diff --git a/play.js b/play.js
index 69a7669..eb8d8f2 100644
--- a/play.js
+++ b/play.js
@@ -301,7 +301,7 @@ function build_user_interface() {
for (let s = 1; s <= us_states_count; ++s) {
let us_state_css = US_STATES[s].code
- elt = ui.regions[s] = document.querySelector(`#map #${us_state_css}`)
+ elt = ui.us_states[s] = document.querySelector(`#map #${us_state_css}`)
elt.my_us_state = s
elt.addEventListener("mousedown", on_click_us_state)
elt.addEventListener("mouseenter", on_focus_us_state)
@@ -427,16 +427,26 @@ function on_update() { // eslint-disable-line no-unused-vars
}
for (let i = 1; i < ui.cards.length; ++i) {
- // ui.cards[i].classList.toggle("action", is_card_action('card', i))
ui.cards[i].classList.toggle("action", is_card_enabled(i))
}
+ for (let i = 1; i <= region_count; ++i) {
+ ui.regions[i].classList.toggle("action", is_region_action(i))
+ }
+
+ for (let i = 1; i <= us_states_count; ++i) {
+ ui.us_states[i].classList.toggle("action", is_us_state_action(i))
+ }
+
action_button("commit_1_button", "+1 Button")
action_button("defer", "Defer")
action_button("match", "Match")
action_button("supersede", "Supersede")
action_button("draw", "Draw")
+ action_button("next", "Next")
+ action_button("purple", "Purple")
+ action_button("yellow", "Yellow")
action_button("end_event", "End Event")
action_button("skip", "Skip")
diff --git a/rules.js b/rules.js
index 182a5a9..ceb072f 100644
--- a/rules.js
+++ b/rules.js
@@ -50,6 +50,15 @@ const D4 = 4
const D6 = 6
const D8 = 8
+const COLOR_CODE = {
+ [PURPLE]: "P",
+ [YELLOW]: "Y",
+ [PURPLE_OR_YELLOW]: "PY",
+ [RED]: "R",
+ [GREEN_CHECK]: "GV",
+ [RED_X]: "RX",
+}
+
const { CARDS } = require("./cards.js")
const { US_STATES } = require("./data.js")
@@ -147,6 +156,31 @@ function region_us_states_except(region, excluded) {
return region_us_states(region).filter( x => !to_remove.has(x) )
}
+function find_campaigners(campaigner) {
+ if (campaigner === PURPLE) {
+ return game.purple_campaigner
+ } else if (campaigner === YELLOW) {
+ return game.yellow_campaigner
+ } else {
+ return game.opposition_campaigner
+ }
+}
+
+function add_campaigner(campaigner, region) {
+ const campaigners = find_campaigners(campaigner)
+ const index = campaigners.indexOf(0)
+ if (index !== -1) {
+ campaigners[index] = region
+ } else {
+ throw Error("No free campaigners")
+ }
+ log(`Placed ${COLOR_CODE[campaigner]}R in R${region}`)
+}
+
+function add_cube(cube, us_state) {
+ log(`Added ${COLOR_CODE[cube]}C in S${us_state}`)
+}
+
// #endregion
// #region PUBLIC FUNCTIONS
@@ -164,6 +198,14 @@ function gen_action(action, argument) {
}
}
+function gen_action_region(r) {
+ gen_action("region", r)
+}
+
+function gen_action_us_state(s) {
+ gen_action("us_state", s)
+}
+
exports.action = function (state, player, action, arg) {
game = state
if (states[game.state] && action in states[game.state]) {
@@ -555,7 +597,6 @@ function can_play_event(c) {
return true
}
-
function count_player_active_campaigners() {
if (game.active === SUF) {
return game.purple_campaigner.filter(value => value !== 0).length + game.yellow_campaigner.filter(value => value !== 0).length
@@ -614,7 +655,6 @@ states.operations_phase = {
if (!game.has_played_claimed) {
// only one claimed can be played per turn
for (let c of player_claimed()) {
- // TODO is this the right type of event?
gen_action("card_event", c)
}
}
@@ -885,21 +925,21 @@ function vm_case() {
// #region EVENTS VfW DSL
function vm_add_campaigner() {
- game.vm.count = vm_operand(1)
- game.vm.campaigner = vm_operand(2)
- game.vm.region = vm_operand(3)
- goto_vm_add_campaigner()
+ game.vm.campaigner = vm_operand(1)
+ game.vm.region = vm_operand(2)
+ game.state = "vm_add_campaigner"
}
function vm_receive_buttons() {
game.vm.count = vm_operand(1)
- goto_vm_receive_buttons()
+ game.state = "vm_receive_buttons"
}
function vm_spend_buttons() {
- // TODO assert
game.vm.count = vm_operand(1)
- goto_vm_spend_buttons()
+ game.state = "vm_spend_buttons"
+ if (player_buttons() < game.vm.count)
+ throw Error("ASSERT: Insufficient buttons")
}
function vm_opponent_loses_buttons() {
@@ -1211,6 +1251,91 @@ states.vm_switch = {
},
}
+states.vm_add_campaigner = {
+ inactive: "add a campaigner",
+ prompt() {
+ event_prompt()
+ gen_action_region(game.vm.region)
+ },
+ region(r) {
+ push_undo()
+ add_campaigner(game.vm.campaigner, r)
+ vm_next()
+ }
+}
+
+states.vm_receive_buttons = {
+ inactive: "receive buttons",
+ prompt() {
+ event_prompt()
+ gen_action("next")
+ },
+ next() {
+ push_undo()
+ log(`+${pluralize(game.vm.count, 'button')}.`)
+ if (game.active === SUF) {
+ game.support_buttons += game.vm.count
+ } else {
+ game.opponent_buttons += game.vm.count
+ }
+ vm_next()
+ }
+}
+
+states.vm_spend_buttons = {
+ inactive: "spend buttons",
+ prompt() {
+ event_prompt()
+ gen_action("next")
+ },
+ next() {
+ push_undo()
+ log(`-${pluralize(game.vm.count, 'button')}.`)
+ if (game.active === SUF) {
+ game.support_buttons -= game.vm.count
+ } else {
+ game.opponent_buttons -= game.vm.count
+ }
+ vm_next()
+ }
+}
+
+function goto_vm_add_cubes() {
+ game.state = "vm_add_cubes"
+ if (game.vm.cubes === PURPLE_OR_YELLOW) {
+ game.vm.cube_color = 0
+ } else {
+ game.vm.cube_color = game.vm.cubes
+ }
+}
+
+states.vm_add_cubes = {
+ inactive: "add a cube",
+ prompt() {
+ event_prompt()
+ if (game.vm.cubes === PURPLE_OR_YELLOW) {
+ gen_action("purple")
+ gen_action("yellow")
+ }
+ if (game.vm.cube_color) {
+ for (let s of game.vm.us_states)
+ gen_action_us_state(s)
+ }
+ },
+ purple() {
+ game.vm.cube_color = PURPLE
+ },
+ yellow() {
+ game.vm.cube_color = YELLOW
+ },
+ us_state(s) {
+ push_undo()
+ add_cube(game.vm.cube_color, s)
+ if (--game.vm.count === 0)
+ vm_next()
+ }
+}
+
function can_vm_place() {
for (let s of game.vm.spaces)
if (can_place_cube(s, game.vm.removed))
@@ -1614,15 +1739,187 @@ function array_remove(array, index) {
array.length = n - 1
}
+
+// insert item at index (faster than splice)
+function array_insert(array, index, item) {
+ for (let i = array.length; i > index; --i)
+ array[i] = array[i - 1]
+ array[index] = item
+ return array
+}
+
+function array_remove_pair(array, index) {
+ let n = array.length
+ for (let i = index + 2; i < n; ++i)
+ array[i - 2] = array[i]
+ array.length = n - 2
+}
+
+function array_insert_pair(array, index, key, value) {
+ for (let i = array.length; i > index; i -= 2) {
+ array[i] = array[i-2]
+ array[i+1] = array[i-1]
+ }
+ array[index] = key
+ array[index+1] = value
+}
+
+function set_clear(set) {
+ set.length = 0
+}
+
+function set_has(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return true
+ }
+ return false
+}
+
+function set_add(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return set
+ }
+ return array_insert(set, a, item)
+}
+
+function set_delete(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return array_remove(set, m)
+ }
+ return set
+}
+
+function set_toggle(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return array_remove(set, m)
+ }
+ return array_insert(set, a, item)
+}
+
+function map_clear(map) {
+ map.length = 0
+}
+
+function map_has(map, key) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return true
+ }
+ return false
+}
+
+function map_get(map, key, missing) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return map[(m<<1)+1]
+ }
+ return missing
+}
+
+function map_set(map, key, value) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else {
+ map[(m<<1)+1] = value
+ return
+ }
+ }
+ array_insert_pair(map, a<<1, key, value)
+}
+
+function map_delete(map, item) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else {
+ array_remove_pair(map, m<<1)
+ return
+ }
+ }
+}
+
+function map_for_each(map, f) {
+ for (let i = 0; i < map.length; i += 2)
+ f(map[i], map[i+1])
+}
+
// #endregion
// #region GENERATED EVENT CODE
const CODE = []
CODE[1] = [ // Seneca Falls Convention
- [ vm_add_campaigner, 1, PURPLE, NORTHEAST ],
- [ vm_add_campaigner, 1, YELLOW, NORTHEAST ],
+ [ vm_prompt, "Add 1 :purple_campaigner and 1 :yellow_campaigner in the Northeast region." ],
+ [ vm_add_campaigner, PURPLE, NORTHEAST ],
+ [ vm_add_campaigner, YELLOW, NORTHEAST ],
+ [ vm_prompt, "Receive 2 :button." ],
[ vm_receive_buttons, 2 ],
+ [ vm_prompt, "Add 2 :purple_or_yellow_cube in New York." ],
[ vm_add_cubes, 2, PURPLE_OR_YELLOW, us_states("New York") ],
[ vm_return ],
]
@@ -1736,7 +2033,7 @@ CODE[18] = [ // National Woman’s Rights Convention
]
CODE[19] = [ // National American Woman Suffrage Association
- [ vm_add_campaigner, 1, PURPLE, ATLANTIC_APPALACHIA ],
+ [ vm_add_campaigner, PURPLE, ATLANTIC_APPALACHIA ],
[ vm_receive_buttons, 3 ],
[ vm_return ],
]
@@ -1841,7 +2138,7 @@ CODE[35] = [ // Southern Strategy
]
CODE[36] = [ // Women’s Trade Union League
- [ vm_add_cubes_in_each_of, 1, YELLOW, region_us_states(ATLANTIC_APPALACHIA) ],
+ [ vm_add_campaigner, YELLOW, ATLANTIC_APPALACHIA ],
[ vm_add_congress, 1 ],
[ vm_receive_buttons, 2 ],
[ vm_return ],
@@ -1944,7 +2241,7 @@ CODE[52] = [ // Miss Febb Wins the Last Vote
]
CODE[53] = [ // The Patriarchy
- [ vm_add_campaigner, 1, RED, SOUTH ],
+ [ vm_add_campaigner, RED, SOUTH ],
[ vm_receive_buttons, 4 ],
[ vm_add_cubes_in_each_of, 1, RED, region_us_states(NORTHEAST, ATLANTIC_APPALACHIA, SOUTH, MIDWEST) ],
[ vm_return ],
@@ -2058,7 +2355,7 @@ CODE[70] = [ // Old Dixie
]
CODE[71] = [ // NAOWS Forms
- [ vm_add_campaigner, 1, NORTHEAST ],
+ [ vm_add_campaigner, NORTHEAST ],
[ vm_receive_buttons, 2 ],
[ vm_return ],
]