Monte Carlo Simulation for the Wingspan Automa: Part 2

This is the second post of a short series describing my work estimating the score of the Wingspan Automa, and interesting things I learned along the way. As usual, the code for this project is on Github.

Charts and Graphs!

I’m not going to bore you with the details of learning matplotlib, the Python library for rendering sophisticated charts and graphs, but it turned out to be as cumbersome to use, but also easy enough to get most of what I wanted out of it. Mostly, but good enough to render results for all of you.

Interpreting Each Graph

For each graph below, the x axis represents the possible score in one of the simulations, and the y axis represents the number of times that score appeared. This is why each graph is a bell curve; the scores are predictable along a mean. The lines-and-triangle pair shows the mean and standard deviation of each graph.

Each minor axis line along the x axis represents a difference of two points for the Automa.

Most of the news won’t be that interesting in this article except that it verifies a few things:

  1. No surprise: the more points the Automa scores for each Draw action, the higher the score. About eight points per level, it seems – you see the difference between each curve’s mean by looking at the x-coordinate of each triangle. Although I don’t understand why higher-points per Draw action results in a curve of a different height. Each plot line represents 1/3 of all 1,800,000 simulated games. Is it really possible that 600,000 simulations wasn’t enough?It’s interesting that Eagle-eyed Eagle has the largest standard distribution of values, which is why its graph is shorter, more variance. I assume that’s because it depends on the frequency that Draw a Bird and Play a Bird actions come up.bylevel
    plot mean stdev
    [Eaglet] 80.39430833 7.717951275
    [Eagle] 88.548995 7.791237642
    [Eagle-eyed Eagle] 96.69753167 8.288301338
  2. There’s about a two point difference in the Automa’s score whether you use the base game or European Expansion, or both.bydeck
    plot mean stdev
    deck[ee] 89.587765 10.54851503
    deck[both] 88.28183833 10.24598541
  3. There’s not much difference whether the Automa uses the Rasp Life Fellow or Autwitcher game-end card, though there’s an interesting deviation between the two.bygoal
    plot mean stdev
    goal[RaspbLifeFellow] 88.59058889 10.37572037
    goal[Autwitcher] 88.50330111 10.34003917
  4. Of course the Automa is going to store more points with the Autumbon Society card as opposed to without it, about seven on average, it seems. Autombon Society also increases the standard deviation of scores, which isn’t a surprise, I guess — there’s more cards to draw from each round.byautumbon
    plot mean stdev
    autumbon[False] 84.98969444 9.2331507
    autumbon[True] 92.10419556 10.19885435

Coming Next

Why? What if? (When I dig in, and then write it.. :D)

Monte Carlo Simulation for the Wingspan Automa: Part 1

This is the first post of three describing my work estimating the score of the Wingspan Automa, and interesting things I learned along the way.

Introduction

I wasn’t very satisfied with the Wingspan Automa post I wrote last week, though it basically showed me how reliable the variance was  for end-of-round goals. But I wondered what it would take to write a full-on simulator for the Wingpan Automa. So I did it.

A simulation couldn’t really simulate a proper game, because it wouldn’t represent me as an opponent. So while I can’t predict whether an Automa will win, I can predict its range of scores. With a number of assumptions, of course.

In this post I’ll discuss the first part, about running simulations, the many variations of ways the Automa can be played, and approximations and compromises I had to along the way. This results in storing a bunch of data to be parsed later.

This post assumes you’re familiar with how the Automa works. I spent time making the last post readable to non-players, but it didn’t quite work out. Lesson learned.

Whereas my last coding effort focused around all the possible permutations of cards, I couldn’t really do that this time, so I went instead of the Monte Carlo simulation. But I ran approximately 1.8 million simulations, and that takes about five minutes to run.

Iterations

I wasn’t specifically looking for 1.8 million simulations as a good number. But what I did was look at the different ways the Automa game can vary and went through all those combinations. They included:

  • The chosen difficulty level, which scores a different number of points for each Draw Cards action. The three levels are called Eaglet, Eagle, and Eagle-Eyed Eagle.
  • Whether the Autombon Society card is included in the card deck. The two options are included and excluded.
  • Which decks of bird cards are used in the game. The three options are base, European Expansion, and both.
  • Which end-of-game goal card the Automa uses. The two options are the European Expansion cards Autwitcher and Raspb Life Fellow. (Although there are 31 other end-of-game goal cards, those are the two made just for the Automa. I wasn’t interested in trying out any of the other cards, for good reason.)

Anyway, I ran through each possible combination of these options. I normally cringe at four for-loops one after the other, but this isn’t professional work – this is hobby time.

levels = [3,4,5] # representing Eaglet, Eagle and Eagle-Eyed Eagle
autombons = [True, False]
decks = ['base', 'ee', 'both']
goals = ['Autwitcher', 'RaspbLifeFellow']
for level in levels:
 for autombon in autombons:
   for deck in decks:
     for goal in goals:
       params = { 'level': level, 'autombon': autombon, 
                  'deck': deck, 'goal': goal}
       run_simulation(params, writer)

Those options can be combined in 36 different ways. Each combination is run through 50,000 sample games. And that’s how we get to 36 * 50,000 = 1,800,000.

Decisions

In order for this to work, I had to make some estimates and decisions. I’ll cover them now:

Dealing from the Automa deck. This was pretty easy to simulate accurately. Each action the Automa takes is represented by dealing a card from the deck. Shuffling and dealing from a small deck is pretty simple, and with 1.8M simulations, while I don’t know jack about statistical significance, I’m happy enough for now.

End-of-game goals. I limited end-of-game goals to two cards as mentioned above: Autwitcher and Raspb Life Fellow. These are the only two end-of-game goal cards made just for the Automa. I don’t use other cards, and it turns out, it made other things easier, as you’re about to read.

Deck of birds. Since I wanted to know whether there was a meaningful difference for the Automa playing with the base cards, EE or both together, I needed to track relevant data of all 250 birds. Maybe I’d need a data structure representing each bird. Let’s see, I’m going to need point values for the end-of-game goal action and … huh … that’s about it. So I only need two pieces of data about each bird: its score and which set it belongs to. This became a dead-simple data structure where each deck is a mapping from point value to the number of birds with that point value in the deck:

bird_cards = [
  { 0:6, 1:12, 2:20, 3:33, 4:33, 5:34, 6:12, 7:8, 8:8, 9:5 }, # base
  { 0:3, 1:7, 2:8, 3:18, 4:24, 5:8, 6:6, 7:4, 8:2, 9:0 } # ee
]

Except I made a small error. The base deck has 180 cards, and the entries above add up to 181. What did I get wrong? I honestly don’t think it would meaningfully matter. But I’ll fix it soon enough. Perhaps.

Bird cards in the display. Once a deck is prepared with the appropriate cards, it’s shuffled, and the simulation actually deals out cards in the display. It chooses cards to be available to purchase. The cards in the display only change under these circumstances:

  • The Automa resets the display through the Draw Cards action.
  • The Automa chooses cards for the end-of-game bonuses for the Play a Bird action.
  • The display is reset at the end of the game.
  • The human opponent takes a Draw Cards action.

This last one has the only non-deterministic behavior. I felt it was important emulate this in order to keep the display fresh for the Automa’s Play a Bird action, so I used the following naive heuristic: 20% of the time, the human player will draw one card from the display, and 20% of the time the human player will draw two cards from the display. (This winds up drawing a wide variety of cards, averaging around 19. But I tried a smaller percentages, averaging around 13 cards, and it did not seem to make a meaningful change in scores. You can look at that branch of the repo if you like.)

End of Round Goals. While the prior post was all about analyzing end-of-round goals, this is a different problem, because while that post was about counting cubes, I now needed to translate that to points. And here I made up another heuristic: when the Automa ends its turn with 0 cubes, the human wins the end-of-round goal. When the Automa ends its turn with 1 cube, they tie. If the Automa ends its turn with two or more cubes, it wins. This probably unfairly gives the Automa an advantage, particularly in later rounds, to the tune of 7 or so points, but if someone has a better proposal, I’m happy to rerun the simulations.

Other Actions. Lay Egg actions are easy to track. Gain Food and Activate Pink Powers have almost nothing to do with the Automa, and help the human opponent, and are ignored.

The Code, The Data

You can see the code at on Github, where you should be able to run the Monte Carlo simulations to generate the intermediate CSV data. Patches welcome!

Coming Next

Turning CSV data into charts and graphs!

Analyzing the End of Round Goals in the Wingspan Automa

3d-wingspan-1024x1002Note: this post uses images for tables visual clarity. It’s hard to embed that kind of css-formatted table in free WordPress, so if you have trouble viewing the images, you can read the post on Google Docs.

I’ve been playing with the Wingspan Automa lately. It’s a vastly simplified opponent people can use to play Wingspan as a solo game. The Automa’s behavior is controlled by a deck of cards, each with a fairly simple action meant to compete against you for points, and also the one area where opponents have the most direct competition: end of round goals. Each of the game’s four rounds includes a custom condition to compete against for bonus points: having the most eggs in a certain kind of nest, for example, or the number of food tokens in your supply. At the end of the round, the player with the highest value for the condition gains the most points for the round, and so on down to the player with the lowest value for the round.

The Automa participates in this competition by simulating an effect of achieving the goal. Rather than complicate the Automa by tracking eggs on each kind of nest, for instance, the Automa tracks progress toward these goals with a pool of tokens. Each Automa card played either adds a token to this pool, removes a token to this pool, or neither. At the end of the round, the cubes gained by the Automa (plus a modifier which is beyond the scope of this article) represents their units for that goal.

scan

Here’s an example card on the right. First, it’s only used for the first three rounds, and is discarded before Round Four. The blue cubes indicate adding a token to the end-of-round pool and the cube with the red X indicates removing a token instead.

After having played a couple of games with the Automa, which regularly beats me in end-of-round goals, I wondered just how many units the Automa regularly gains in each round. So I read the cards and mapped out their effects in the table below, so let’s talk about that table, since it probably doesn’t make any sense yet. (The card above is represented below as #3.)

zeroth

Some of you know that there’s an eleventh card which represents the optional Autombon Society. It makes the game harder for the opponent, and also confuses this analysis, so I’ll get to it later.

There are two other important things you need to know:

  • In every round, both the player and the Automa will take one fewer action than before. In Round One you take 8 actions, Round Two you take 7, and so on.
  • At the end of every round you permanently remove one of the Automa cards from the game. Specifically, card #1 is discarded after Round One, card #2 is discarded after Round Two, and so on.

Said another way:

  • During Round One you and the Automa get 8 actions, and the Automa deck has 10 cards.
  • During Round Two you and the Automa get 7 actions, and the Automa deck has 9 cards.
  • During Round Three you and the Automa get 6 actions, and the Automa deck has 8 cards.
  • During Round Four you and the Automa get 5 actions, and the Automa deck has 7 cards.

So, I’m going to rearrange the data on those cards to make the pattern on them easier to see:

firstYep, each round has 3 +1s and 3 -1s, and a decreasing number of zeroes. I’m going to assume this means I’ll expect more variance as the rounds go on.

OK, so back to my big question: how many cubes is the Automa likely to end up with at the end of each round? Well, let’s start with a simplified way to look at it.

Naive Approach

Let’s start simple: if all cards are played each round, you can add the +1s and -1s, and the net result is zero. But we also know that each round, all cards but two will be played, which means outcomes can waver based on which are omitted. If the two cards not played have -1, then the net result is two. But if the two cards not played are +1, then the net result is … -2?

That doesn’t make any sense. Anyone who’s played this knows that there’s no way to have a negative number of cubes in the pool at any time. Which means we have to start looking at permutations. And not combinations, because order matters.

So Much For the Naive Approach

Gah. I really hate statistics. I got out of that class by the skin of my teeth. The first version of this document talked about calculating permutations, simplifying those calculations, and was wrong in so many ways. Which is why it’s long deleted. I’m good at programming computers, so I replaced all of it with some dead-simple Python which you can read here. Thank goodness Python has fabulous support for my use case with the permutations function and a super-fun use of the reduce function, which I’ve never had need to use until today. Who cares? Let’s look at the results.

second

How is it that the odds of 2 and 3 are always the same? I’m pretty sure my code is correct, but tell me if I’m wrong.

OK, that was fun. Let’s add back the Autombon Society card mentioned at the beginning of this article. It’s a simple card, actually, for every round it adds +1, regardless.

Here, I’ll give you a visual:

third

Like that.

The result from the Python code are commingled with the original table of results below

fourth

And now put into a pretty chart.

chart

OK, so does this change the average or standard deviation much?

avg and stdev

fifth

 

Huh! So after all that, there’s very little variance between rounds. Which is not what I expected at all. But there’s still a standard deviation of between .8 and 1.0 tokens, which can make the difference between first place and second place. 

As you saw on the sample card, there’s more to the Automa than end-of-round goals. If the fancy strikes me, I’ll dig into those facets, too.

Scanning Thick Tiles

Playing Wingspan the other night, my friend pointed out that she was missing one of the end-of-round tokens from her box, so I offered to make her one. It’s easy enough to do: scan the tile on both sides, laser print it and affix to 1mm thick board.

I was generally pleased. I can’t round those corners, but more noticeable, and this might be hard to see in the image below, is that the tile I manufactured is much more gray. The original tile is on the left, and has some brown and red in it.

IMG_20200405_190441 (1).jpg

Was it my laser printer, or my scanner, which sapped the color?

Here’s what the scanner produced:

They’re pretty gray. They also  have that dark black line, visible along the top. That line is probably a shadow generated by the scanner. That shadow gave me a thought: perhaps the problem is the tile is thick, and light isn’t reflecting back correctly.

So I fashioned a frame with the same thickness as the original tile to see if that would help.IMG_20200405_193343.jpg

Again, this may be hard to tell, but there’s a little more brown in these new scans. Here’s a side-by-side. The first scan is on the left. The revised scan is on the right.sidebyside.jpg

It’s not so much color as to make a meaningful difference, but there’s a little.

I guess this is what you get for an entry-level scanner. I might try some other settings, but I don’t think much will change.

Board Gaming with Social Isolation, Part 2

In my prior post I tested out using a camera mount to play a board game remotely. Today I used it to play an actual game of Flash Point: Fire Rescue. Flash Point is a cooperative game with no hidden information. Very much like the more popular game Pandemic. We just like Flash Point more.

The other reason Flash Point makes a good test case is because all the information’s on the board. The players don’t have private hands of cards, something I wasn’t terribly interested in trying out. They could examine the board, and report how they wanted their player to move. There wasn’t much I could hand them in terms of control, but the game includes some dice rolling, so they were responsible for that.

We used Google Hangouts for the videochat. I mounted my cell phone on the mount, and used a tablet both to interact, and also as a way to view what’s on the phone, displaying the board.

2020-03-15

Initial rotations were peculiar: I had to futz with my phone’s rotation settings before my friends could see the full board, remotely, but eventually they were able to see the full board.

Screenshot_20200315-150450_Hangouts

They found that for the most part, they could play by watching TV.

Screenshot_20200315-152309_Hangouts

While the board was mostly clear and visible, we found a few problems, most notably:

Screenshot_20200315-170901_Hangouts

  1. Upload bandwidth meant that the display was sometimes pixelated at lower resolution, or suffered from lag time. This wasn’t a pleasant experience.
  2. The play board itself, shown in the image above, had too much contrast for one of the remote players. If we played again, I would make a facsimile of the board with much lower contrast, black and white.
  3. Near the end of the game I realized that while moving game pieces, I needed to be very deliberate, showing my teammates what I was doing.
  4. The arm worked well enough, for the most part, but we found that over time it sagged, moving the board out of view. Nobody noticed it until I realized it was something I had to look out for. There are bits of gear that are much more expensive that probably address this, but for now I’m content.

None of these things got in the way of us having a good time, or executing on the game, so basically I declare this a qualified success, I hope to try with another game sometime soon.

Board Gaming with Social Isolation

Something I’ve been wanting to try for some time, is playing physical board games with friends not near me. Of course, there are mobile apps. I’ve played dozens of games of Ticket to Ride on the mobile app, the key being that we have a simultaneous videochat. You know, for the friendly banter.

It’s the friendly banter that matters to me. Even more now, that we’re forced to be socially isolated. Board gaming is just too close, you can’t stay two meters away from the board while someone else is playing.

There’s a Kickstarter project called Vorpal Board which actually addresses this by providing an interesting solution: a camera mounting arm, and a card scanner, which combined with a mobile app, allows players to see and control their own hands and decks. I didn’t back the project, adopting a wait-and-see attitude. But I still wanted to try something! This mounting arm was $21 on Amazon, a price point worth trying.41TzETh3bdL.jpgI tested out different board sizes to see if they’d be reasonably visible.

20200314_123641

Flash point fits in the camera easy-peasy.

20200314_123650

A Ticket to Ride Board is larger than typical boards (~21″x31″), and a good test of what will work.

20200314_123848

Of course, Ticket to Ride in this manner can be difficult, especially, you know, without a card scanner, but this is just for sizing, and also, even those things are surmountable.

Screenshot_20200314-123924.png

If you’re going to try this, change a couple of your camera settings, for instance, disabling what your volume key does, but more importantly, disabling video stabilization, which automatically zooms the camera to 2x when recording video.

(This might not actually be necessary when using a video chat app, but keep it in mind.)

Some ad-hoc testing suggests that the boards are visible using Google Hangouts. So, next step is to, you know, play something.

Getting Started in Board Game Crafting

Last updated: January 15

PnP board game crafting is a hobby where you learn most of it with practice and your brain, so the simplest thing to do is find technique videos that achieve what you want, and think / practice your way through the fine details.

But I do have a very clear recommendation on getting started.: it’s the Dining Table Print and Play Youtube Channel, followed by the rest of Jake’s videos. The two to watch first are Tip: Use a Steel Ruler! and Tip: How to Use a Rotary Cutter. These two form the basis of everything I have done. I recommend printing a few sheets of paper with horizontal and vertical lines for you to practice your cuts from those two videos alone, and from there, you can look at his channels for things like making cards, boxes, or even double-layer recessed boards.

The DIY forum on BoardGameGeek is very helpful and supportive. And they have a post with All the DIY Links You Never Knew You Needed. It’s a great resource if YouTube or Google don’t come through.

Materials

I have a lot I can say about materials, and absolutely will not be comprehensive. (Edited to add: looks like I was somewhat comprehensive.)

Rotary Cutter: Get the Fiskars. Get spare blades. They’re pricey but you don’t want to deal with dull blades.

Steel Ruler: You saw above. Get a steel ruler with a cork backing. Once in a while an 18” ruler helps out when cutting large pieces of poster board, but it is otherwise unwieldy.

Self-Healing Mat: Another must. They’re great. Michaels has an OLFA brand one that is great for measuring.

Hobby Knife: Soon you’ll move from rotary cutter to X-Acto knives. You can get an X-Acto-branded knife, but check out this video which talks about ways to upgrade your knives. I 100% agree with the concerns, and bought the Excel knife (and also a 100-pack of blades.) No regrets.

Circle Cutters: I can’t find a good one. I think the Fiskars circle cutter kind of sucks, but the presenter in the hobby knife video kind of liked it. I’ve relied on a couple of circle punches for things like tokens, eg but nothing for circles larger than 1” in diameter.

Rounding Corners: OK, so you can get corner rounders to protect playing card edges. The cheap ones you get at Michaels will not work well if your asset has any thickness. They’re great for paper and that’s about it. I invested in a heavy-duty one. It was $60, but I don’t regret it for the value it provided. (I round everything I can, all the time!)

Adhesives: I use a few. Because I live in an apartment with standard air ventilation I can’t use a spray adhesive. I rely heavily on Elmer’s Washable Purple School Glue. It’s nearly perfect, though the one problem is that you often have to do minor repairs the following hour or day. Always double-check, and learn to apply the glue with a small knife in corners.

Plain double-sided scotch tape is great under some circumstances. For something nicer, I use double-sided sticker tape. I don’t use it often, but for example, it worked great with the double-layered Century Spice Road boards. (Those boards are also made with sticker paper, discussed below.)

I haven’t yet mastered spray adhesives and can’t do it anyway what with the limited ventilation in my apartment building. But even when I was in a house, I couldn’t trust that a spray wouldn’t show a wet blotch through the other side. Eh.

Paper and Cardstock: Obviously I use standard 20lb laser printer paper for most of my work. If I could get cardstock to go into my color laser printer I’d do it, but I can’t.

Poster Board: I use four different kinds: First, I reuse my cereal boxes and other chipboard. They work just great. I’ve never had real issues with gluing to the glossy side. There other are two poster board thicknesses you can use, the normal poster board you can get at any pharmacy (or craft or office supply store,) which has a little weight to it. I often use those for playing cards. That’s not the best way to make cards, but it works and I am satisfied. A thinner poster board can be used as an easy way to make bands to keep cards together. If you don’t know what I mean, don’t worry about it. My favorite is this 1.3mm-thick board which seems to be available at art shops. It’s strong. It takes glue very well. My dice tower is made from it, and I’ve used it for other things. The only down-side is that one side of the board has a watermark on it, ugh, go away watermark.

Oh, right – I’ve used a fifth kind for large game boards, the important thing is to find something thick. And use new blades.

Foam Core: Great for inserts. Don’t use it for making boards. Paper doesn’t stick to it easily. Stay with thick cardboard.

Sticker Paper: This is a great way to get artwork on top of cards and solves the adhesive problem, but two things: first, change your printer settings to print to sticker media. You literally have to choose the sticker paper media type for your printer when printing. It changes the printer’s fuser’s temperature so the color adheres to the paper (ref.) Second, you’ll probably want to use a fixative on these to help preserve the color.

Fixatives: They’re great. I wish I could use them in my apartment. Then I’d print on sticker paper more, especially when I want something nice looking. Like adhesives, it’s easy to over-spray, but it’s worth practicing.

Other Tips

  • I bought some +1.25 glasses from the pharmacy which basically act like a magnifying glass on my face. Great for being more confident about precise cutting.
  • Every once in a while, but rarely, I rely on cheap calipers to measure thickness. I needed that to design the dice tower, for example.

Expanding a game isn’t as easy as having an idea

In my last post I talked (mostly) about the work behind two expansions for a game I have been enjoying. Something was nagging me about the placement cards (which I listed as expansion 1) which was really about whether there was a fair distribution of spaces of (what is known in the game as) treasures.

screen-shot-2019-06-02-at-11.34.07-pm

This card has treasures on 15 of the 25 water spaces.

Given that I had designed and laid out those cards in Python, I resolved to use that same code to transfer the data to a spreadsheet, and to visualize how frequently each of the 25 water spaces appeared in all 24 cards.

If you read the Python from my prior post, you’ll know that each card was represented as a string of characters, each character representing one of the 25 cells (a for 0,0, b for 0,1, and so on.) Since I wanted to render these results in a spreadsheet, I created a new Google Sheet rewrote the Python as Javascript. The result is in the code sample at the bottom. It’s not efficient. It isn’t meant to be. But by publishing the Apps Script Project as a Sheets Add-On …

Screen Shot 2019-06-05 at 9.13.24 PM

it can be used as functions right in the spreadsheet (a new thing for me!)

Screen Shot 2019-06-05 at 9.14.30 PM

So, what were the results?

Screen Shot 2019-06-05 at 9.10.31 PM

What is this saying? The 25 cells represent the cells of a card. The number represents how many cards out of 24 have a treasure in that water space.

So the most common place to find a treasure is right in the center. 20 out of 24 cards have a treasure right in the center.

Just like my sample card, above, and repeated below.

screen-shot-2019-06-02-at-11.34.07-pm

For clarity, I added Conditional Formatting on the range, turning it into a poor-person’s heatmap.

Screen Shot 2019-06-05 at 9.15.38 PM

Which came out like this:

Screen Shot 2019-06-05 at 9.15.30 PM

This colorization shows something interesting:

Screen Shot 2019-06-05 at 10.34.02 AM

One thing is obvious: there are only 7 out of 24 chances for treasures to appear in the four cells orthogonally adjacent to the center of the board, at spots (1,2), (2,1), (2,3), and (3,2).

Compare that to this heatmap which shows the distribution of the original six cards.

Screen Shot 2019-06-05 at 9.16.01 PM

There, treasures are only found twice out of six times, at (1,1), (1,3), (3,1), and (3,3), but are found five times out of six at (0,2), (2,0), (2,4), and (4,2).

So, is this meaningful?

Let’s see. Now, my statistics and probability is rusty, but I think I can pull this out with help from The Internet.

Let’s start by choosing, for instance, one of the (2,1) spaces where treasures occur only 7 times in the deck of 24.  What are the chances that when drawing four cards, none of them have a treasure on that space?

Drawing 4 cards out of 24, there are 24C4, or 10,626 combinations. I gave each card a number and the computed all the permutations with the help of this permutations calculator. With that, and more spreadsheet magic, here’s the chances.

Occurrences Count %
0 2380 22%
1 4760 45%
2 2856 27%
3 595 6%
4 35 0.3%

In other words, almost a quarter of the time a treasure won’t appear in that water space for the whole game.

Now let’s compare that to the odds when drawing from the 6-card deck. There, the spaces with the fewest treasures are one space diagonally from the center, and those spaces only have treasures in two out of six cards.

Drawing 4 cards out of 6, as you do in a game, there are 6C4, or 15 combinations. Thanks to the same permutations calculator and spreadsheet magic, here are the odds of those low-frequency spaces being drawn in a game.

Occurrences Count %
0 1 7%
1 8 53%
2 6 40%
3 0 0%
4 0 0%

It shouldn’t be a surprise that if a treasures appears on a water space only twice out of six cards, there’s a 0% chance of drawing three cards with treasures on that space.

Let’s compare these side-by-side.

Screen Shot 2019-06-05 at 10.49.46 PM

With a deck of six cards, there’s only a 7% chance those specific low-frequency water spaces will remain unpopulated the whole game, while with the deck of 24 cards, those sparsely-populated spaces will be less likely to be populated.

While I’ve never discussed the rules to the game on this post, you can imagine this means someone will make very different decisions about where to spend my time on the board.

So, what value would work?

Thanks to all that prework, it took much less effort to find out the odds drawing cards when they appear 8 out of 24 times, or 9 or 10.

Screen Shot 2019-06-05 at 11.00.12 PM

So I were to build a deck of 24 cards, I might endeavor to have the spaces least likely to contain treasures to at least appear in the deck 10 times.

And this is just focusing on four cells out of all 25.

The Moral

  1. Designing an expansion can just be about whimsy and fun.
  2. And if you do that, you might find unexpected results.
  3. Math can be whimsical and fun.
  4. And if you do that, you might find unexpected results.

The Code

function parse(counts, str, invert) {
  for (var i = 0; i < str.length; i++) {
    var a = str.charCodeAt(i) - 97
    var row = parseInt(a / 5)
    var col = parseInt(a % 5)
    if (counts[row][col]) {
      counts[row][col]++;
    } else {
      counts[row][col] = 1;
    }
  }
}

function dibsimple(x, y) {
  return dibb(x, y, false);
}

function dib(x, y) {
  return dibb(x, y, true);
}

function dibb(x, y, all) {
  var counts = [];
  for (var i = 0; i < 5; i++) {
    counts[i] = [];
  }
  if (!all) {
    parse(counts, "abdefjmptuvxy")
    parse(counts, "bdfgijmpqstvx")
    parse(counts, "bdgiklmnoqsvx")
    parse(counts, "bdgiklmnoqsvx", true)
    parse(counts, "cfgijmpqstw")
    parse(counts, "cfgijmpqstw", true)
    parse(counts, "cfghijmpqrstw")
    parse(counts, "cfghijmpqrstw", true)
    parse(counts, "bcdgikmoqsvwx")
    parse(counts, "bcdgikmoqsvwx", true)
    parse(counts, "aefgijmpqstuy")
    parse(counts, "aefgijmpqstuy", true)
    parse(counts, "aegiklmnoqsuy")
    parse(counts, "aegiklmnoqsuy", true)
    parse(counts, "aceghikmoqrsuwy")
    parse(counts, "aceghikmoqrsuwy", true)
    parse(counts, "abdefgjpstuvxy")
    parse(counts, "abdefijpqtuvxy")
  }

  parse(counts, "abcdeklmnouvwxy")
  parse(counts, "cghiklnoqrsw")
  parse(counts, "acefhjkmoprtuwy")
  parse(counts, "bcdfjkmoptvwx")
  parse(counts, "acegikmoqsuwy")
  parse(counts, "bdfhjlnprtvx");
  return counts[x][y];
}

 

Making Custom Board Game Cards for Waters of Nereus

My most recent game obsession is this enjoyable small-print game called Waters of Nereus. I won’t go into details about the game, but I enjoyed it enough to write my first game review. The thing I’ve most enjoyed about the game is that it’s tapped my creativity in two ways such that I’ve spent maybe sixty hours on two expansion projects.

Before going any further, note that this work is all based on other people’s hard copyrighted work. I have no problem scanning and reusing their images for personal use, and I’m happy to show you photos and rough screenshots, but I have no plans to make these cards generally available. (The expansion rules, not reusing copyrighted artwork, will be, and already is, available.)

pic3925234.jpg

Expansion 1

The first, and far simpler expansion, merely provides extra cards for indicating spots on a 5×5 grid. The game itself comes with six cards, each with a different pattern in each of the 25 cells, which is either on, or off. It doesn’t seem particularly advantageous to have more cards with more patterns, but whatever, I want it.

Look at the cards below. The four on the left are my prototypes, and the one on the right is an original. So, either my printer or scanner is losing color. That one doesn’t really bother me.

IMG_20190602_225915

The patterns from the top two cards come from the original set, the bottom two are new ones I laid out.  These four are part of a set of 24.)

I did all of this work in Gimp. As I said, the top two cards are in the original set. If you look at them, between the two of them all 25 water squares are filled. So within Gimp, I put those two images on two layers, and cut holes out of the top one where the lower icons are, and presto! I had a single image with all 25 spots filled.

And I can do the same thing with the negative spaces. Between the two cards, I can also compose a single image that was all background.

From there it was a matter of cutting out the patterns, 24 times. Or, not. Turns out Gimp has scripting! With Python! So, that was another four hours, just learning the ins and outs of the Gimp scripting API. The Python code is at the bottom of this post, because I am a huge nerd.

It wasn’t always easy. Sometimes I forgot to include the base image.

Screen Shot 2019-06-02 at 11.32.26 PM

But persistence paid off and soon I had 24 computer-generated images

Screen Shot 2019-06-02 at 11.34.07 PM.png

If you go back and look at the photo of the printed cards, you might get an idea how tricky the actual printing process can be. Those white borders on the edges. The wrinkling paper. The corners. Did you notice the corners? The original card has rounded corners. Scanning those images, I had to draw a reasonable looking corner to continue the image. I’m no professional, but I just wanted something … decent. So, that was another hour.

Even though I’ll probably get my hands on a corner cutter, it’s good to feel good about one’s effort.

Expansion 2

The second expansion I wanted was a decent solo automaton. Inspired by the automata for Scythe and Patchwork, I came up with a mechanism for defining actions through a deck of cards. I’ve never done anything like that before, and it took well over 20 hours of thinking, sketching, writing and play testing. I’ve still only play tested 3 times over those 20 hours of thinking and writing.

IMG_20190602_234847

These card above were my original testing cards. They represent a set of rules that I abandoned part-way through for something I like much more. Rather than draw new cards every times the rules changed, I used the numbers in the bottom-right corner to look up actions in the rules document. It still needs more play testing, but rather than complete it, my mind wandered toward card design. I sketched ideas until finally setting on something like what you see on the right, below.

IMG_20190602_235049 (1)    IMG_20190602_235055

Rather than draw icons for everything, I scanned the game board, shown below. Almost every icon you see can be traced to that board.

IMG_20190602_234855

And after hours, and hours, and hours of printing, testing, sizing, and learning features of Gimp I never knew existed, (Alpha To Selection is why you see the border around the 2 and 3, below,) I present my first four (not embarrassing) prototypes.

IMG_20190602_225947

The post-artwork layout is done in Google Slides, which provide far more features than I expected. Still, Inkscape or Illustrator may not be far from my future.

The Card Backs

IMG_20190602_225804

Like everything else, I scanned a card back to make my own backs. A reference card is on the left, my Automaton cards are in the middle, and extra pattern cards on the right.

More Sizing

Go back and look at the card backs on the right. They, like the pattern cards up at the top, have some extra white border. And that’s because I was relying too much on perfectly-sized artwork. (I also hadn’t yet filled in the corners, like you can see in the Automaton cards.)

To accommodate this, I added .03″ on all for edges. And that meant having to fill it in. Which I did.

IMG_20190602_230145

Look at the two cards, above. The one on top is the original, with a rounded corner, and the one on the bottom is a printout with the expanded geography, which you can see along the bottom and sides. I even extended the chain links. And like before, those will probably disappear when I cut them, and nobody will ever notice, but, I’ll notice.

Finally

What a long slog. It’s not even done! I’ve still got plenty of construction ahead of me, and then I need to get down to decent printing and cutting. I’m relying on this great video web series called Dining Table Print & Play, and specifically this time, How to Make Playing Cards. I’ve purchased sticker sheets and a corner cutter, and have carefully laid out a template complete with cutting guides and folding guides. Looking at the image below, I already see a problem with the layout that’ll cost me at least an hour to fix.

Screen Shot 2019-06-03 at 12.08.21 AM.png

Python!

from itertools import izip

xts = [128, 391, 645, 926, 1200]
xbs = [332, 591, 854, 1126, 1390]
yts = [155, 500, 825, 1196, 1549]
ybs = [384, 730, 1105, 1430, 1789]

def sel(img, x, y, mode = 2):
  xc = xts[x-1]
  yc = yts[y-1]
  w = xbs[x-1] - xc
  h = ybs[y-1] - yc
  pdb.gimp_image_select_rectangle(img, mode, xc, yc, w, h)

def go(idx, l):
  if len(gimp.image_list()) > 1:
    raise "oof"
  filename = "/tmp/images/img_%d.png" % idx
  img = gimp.image_list()[0]
  #
  layer = pdb.gimp_image_get_layer_by_name(img, 'template')
  copy = layer.copy()
  img.add_layer(copy, 0)
  img.active_layer = copy
  #
  drw = pdb.gimp_image_active_drawable(img)
  it = iter(l)
  pdb.gimp_selection_none(img)
  for entry in izip(it, it):
  sel(img, entry[0], entry[1], 0)
  pdb.gimp_edit_cut(drw)
  pdb.gimp_selection_clear(img)
  #
  new_image = pdb.gimp_image_duplicate(img)
  layer = pdb.gimp_image_merge_visible_layers(new_image, CLIP_TO_IMAGE)
  pdb.gimp_file_save(new_image, layer, filename, filename)
  pdb.gimp_image_delete(new_image)
  #
  pdb.gimp_image_remove_layer(img,copy)

def parse(s, invert = None):
  r = []
  for c in s:
    a = ord(c) - 97
    row = (a / 5) + 1
    col = (a % 5) + 1
    if invert:
      r.append(col)
    r.append(row)
    if not invert:
      r.append(col)
  return r


cards=[]
cards.append(parse("abdefjmptuvxy"))
cards.append(parse("bdfgijmpqstvx"))
cards.append(parse("bdgiklmnoqsvx"))
cards.append(parse("bdgiklmnoqsvx", True))
cards.append(parse("cfgijmpqstw"))
cards.append(parse("cfgijmpqstw", True))
cards.append(parse("cfghijmpqrstw"))
cards.append(parse("cfghijmpqrstw", True))
cards.append(parse("bcdgikmoqsvwx"))
cards.append(parse("bcdgikmoqsvwx", True))
cards.append(parse("aefgijmpqstuy"))
cards.append(parse("aefgijmpqstuy", True))
cards.append(parse("aegiklmnoqsuy"))
cards.append(parse("aegiklmnoqsuy", True))
cards.append(parse("aceghikmoqrsuwy"))
cards.append(parse("aceghikmoqrsuwy", True))
cards.append(parse("abdefgjpstuvxy"))
cards.append(parse("abdefijpqtuvxy"))

cards.append(parse("abcdeklmnouvwxy"))
cards.append(parse("cghiklnoqrsw"))
cards.append(parse("acefhjkmoprtuwy"))
cards.append(parse("bcdfjkmoptvwx"))
cards.append(parse("acegikmoqsuwy"))
cards.append(parse("bdfhjlnprtvx"))

for x in range(len(cards)):
  go(x, cards[x])

A Casual Look at the Clank! In! Space! Modules

Cross-posted to boardgamegeek.

I never really paid close attention to what makes each Clank! In! Space! module distinct until today when I spent some time fixing the frayed edges. So it seemed like a nice opportunity to write up what I noticed about them.

The rule book starts by recommending Hydroponics on top, with Doomsday Cannon and Med Lab below. When a module is on top, it’s rotated 180 degrees. Does that have an impact on how you navigate it? Perhaps.

Let’s start with the modules, by the numbers. It already tells you a couple of things:

Module
(opp.)

Hydr.
(Eng.)

Eng.
(Hydr.)

D.C.
(Arena)

Arena
(D.C.)

Med Lab
(Prom.)

Prom.
(Med Lab)

Rooms

12

15

12

14

15

13

Major Secrets

2

2

2

1

2

2

Minor Secrets

3

3

3

3

3

3

Total Terminals

6

6

5

6

5

6

Clank Terminals

2

1

2

2

1

2

Medical Bays

0

0

0

1

4

0

Shops

2

1

1

1

1

3

  • All the modules have 3 minor secrets, and except for Arena, they have 2 major secrets.
  • Almost none of the modules have medical bays, but Med Lab sure has a lot of them.
  • Promenade is full of shops.

I’ve also realized something else about the modules in general: The tops of the modules are always closest to the corridor and so, easiest to get to. This is true whether the module is sitting on the bottom or the top (in which case the module is rotated half-way round) And this is why you’ll find clank-heavy terminals near the top. If you want a better reward you’ll have to travel deeper into the module. It’s a nice design, I admire it.

Hydroponics

I never noticed Hydroponics’s color and style. Cute, right? Two market spaces within easy access, though if this module sits near the cargo bay, at best they’re a way to grab a last contraband before running off.

The terminals in the center make this a nice board for two or three players: 5 credits or double-life, with a minor secret to boot. You’ll be hard pressed to find something better. (Only Engineering has something comparable with a 5-credit terminal, and still no double-life terminal.)

You might even be lucky enough to grab a major and minor secret on the same turn, if you can deal with a lock and a checkpoint.

If this is the top module, as recommended for your first game, then the crystal and teleporter rooms will sit right by the top of the Command Module, giving you some valuable help before your big move or after starting your escape.

What would it take to get from one end of the module to the other? Naturally there are four entryways, so left to right isn’t the only option, but that’s what I’m measuring.

If you have swords and boots, you can take the lower route to get out from left to right in five steps, and if not, you’ll need seven steps. Regardless, you’ll have a checkpoint in your way.

Engineering

The other side of Hydroponics is Engineering. It seems like a complicated set of pathways because of the checkpoint arcs, but I think that’s just visual trickery. Though, those checkpoints will surely slow you down.

Of all the modules this has the best reward-terminal to clank-terminal ratio (6 terminals, only one delivers clank) so you have to be really desperate to hit that one up. The 5-money terminal isn’t that difficult to get to (8 steps from left to right with some enemies for good measure) with both major secrets up for grabs. But those outside edges can be tough to get to – the payoff is nice.

Doomsday Cannon

Doomsday Cannon. If you didn’t see it, the cannon itself is on the bottom of the module.

Who needs to go shopping? Apparently just a few people because you’ll find one market space on this board. You can skim across the top of this board and get from left to right in six steps (with a checkpoint in your way.) There are plenty of options for money terminals, which I guess you’ll need at the Doomsday Cannon Market.

If you want to work your way into the center you’ll have some options for the valuable terminals, secrets and a Crystal. If you want that crystal though you might need to spend a few boots to get in and out.

There’s not much else there, and nothing thematically doomsday about it.

Arena

Oh, Arena, I love you. Only one major secret, and that center structure! You can hack a terminal to grab an extra sword, reveal a secret and then combat two enemies to hit the other side and grab the other secret, maybe ending your move at a medical checkpoint (and then stop at the market to buy contraband. Or a G0B-L1N t-shirt.)

But if you had to go from left to right, those one-way paths mean you’ve got fewer options through., though there’s a pretty safe path along the bottom in 7 steps, and another one on top in 7 with a checkpoint.

Arena is also the only board with one major secret, and like I said, if you happen to be going toward the left, that’s great.

Med Lab

There’s a reason the Med Lab is on the lower right of the default set-up. By the time you’ve hit that corner of the board you’ve generated plenty of clank and damage. It’s also a decent way to grab a little money and hack a terminal all at once. The lower path is the most attractive with the major secret and 3 credit terminal, and it makes the two enemy icons less daunting: even without swords you can get a major secret hack a three credit terminal for just one life. (It takes seven steps to go left to right through the lower terminal, versus six for the other two.)

If this were the lower left module, it might be a good spot to heal up before making your final escape.

But also, this is one of the weaker modules, only harder to navigate than Promenade, which sits on the other side.

Promenade

Thieving is hard. Let’s go shopping! And like a good shopping district, it’s easy to navigate – you can go all the way from left to right in six steps, no enemies, no two-boot pathways, no checkpoints. This is why I call it the weakest board. You can just run through it. To be fair, the cleanest path has two terminals and each of the cost you two clank, so if you have easy ways to remove clank those might be perfectly fine terminals to hack.

There’s a nice terminal up at the top that gives 3 credits. If you have the swords and a key that’s a nice major-minor combination. It’s not bad, even without the swords.

I wish Promenade had some arrows forcing shoppers — I mean, thieves — to spend more time in the mall. Does this place have a food court? I just can’t get over disliking it.

Finally

Clank! In! Space! Has four new modules in the Clank! In! Space! Apocalypse! Expansion: Mainframe, Viral Lab, Hangar, and Portal Chamber.

There’s some fun themes and ideas in there — I mean — what is going on with that Mainframe module? And how desperate for credits do you need to be to hack that terminal in the center launch bay?

Look, Clank! In! Space! doesn’t change drastically with each module: there’s always a teleport pad and a market, a fair number of accessible terminals, and plenty of secrets, but there’s enough variety in each module to set the tone of your game. And the effort to differentiate the modules, and understand their behavior can give you an edge when you need to compose your escape plan.

If you could assemble your own modules, what would they be like?