Cavacamicia - analisys of an Italian card game with scheme

Published:

When I was a child, I used to play lots of various card games with my grandmother and cousins. One of these games is a northern-italian game called Cavacamicia, with simple rules and based solely on luck (no strategy involved at all). It was a good game to pass time since it can become quite long.

Exactly the fact that the game can become quite long, made me wonder how much a game can last.

Since I was bored yesterday evening, I decided it was time to sharpen my scheme programming and I wrote a script that plays cavacamicia by itself and keeps track of how long (in number of turns) a game can last.

The point of this post is not the experiment result itself. I just wanted to make a couple of comments on how scheme programming feels for a mainly-java guy.

Rules of the game

The game is played by two opponents with fourty italian cards (here in Veneto we use to play with the Trevigiane variety for a lot of games). I'm pretty sure there are variants with more players, but for the sake of this post let's keep up with just two players.

The deck is shuffled and each player is given a deck of 20 cards, covered.

Now, let's say we have two players, A and B. A starts and flips a card from the top of his deck and puts it on the table. If that card is a 1, a 2 or a 3, B must pay 1, 2 or 3 cards. So, one at a time, B flips and puts on the table 1, 2 or 3 cards. If one of those cards is a 1, a 2 or a 3, B stops flipping cards and now it's for A to flip n cards, and so on. If, in the process, the player flipped 1, 2 or 3 cards and nothing happened, the opponents won the hand, takes the cards on the table and puts them at the bottom of his deck. Then another hand starts.

Let's make an example:

  • A flips a 4
  • B flips a 7
  • A flips a 3. Now B has to "pay"
  • B flips a 5
  • B flips a 4
  • B flips a 9. B lost the hand.
  • A takes the cards from the table and puts them at the bottom of his deck.

  • A flips a 2. B has to pay

  • B flips a 5
  • B flips a 3. Now A has to pay
  • A flips a 1. Now B has to pay
  • B flips a 8. B lost the hand.

And so on... until one of the players has no more cards on his decks. In which case, the opponent wins.

As I said, since at the end of each hand the cards on the table get placed at the bottom of the winner's deck, they'll respawn, so the game can become quite long.

For the sake of this post a player's turn ends when the opponent flips a card.

The script

The script (actually a bunch of function to load from a scheme interpreter and then call) is on a github repo.

It was written for chicken scheme but I'm pretty sure it can be quickly adapted to run on other schemes.

So once you load it with

csi cavacamiciaanalyzer.scm

You can call the play-game function with no arguments to let it play a single game and return the number of turns it took.

Or you can call the play-games function passing as an argument the number of turns to play, which prints on stdout the results of n calls to play-game.

The results

Launching the game 1,000 times, gave widely varying results. You can see the results here.

Please note that this is not a full-blown statistic analysis. Just a list of results on a rather small sample set.

How scheme felt

Those who know me, knows that I write java code for a living (and some javascript at times). So coding in scheme is still a bit alien to me.

Scheme is a completely different beast from java. A mainly functional beast, for that matter. So I had to learn to think in a recursive way. So no loops. Just recursion.

I also completely avoided changing variables values.

The play-hand function has been re-written three times before I got it right. At first I forgot to account for the fact that I had to keep track of the ongoing turns count. Then I didn't know how to tell the recursive calls know that the opponent drew a 1, 2 or 3 and act accordingly. So I simply decided that the first parameter was the current player's deck instead of the "player 1" deck. These are not hard problems by themselves. The real problem was that, since the code wasn't imperative, it took me a while to figure out how to change the function.

A thing that at first was a bit daunting but became easier typing the program, was the use of paredit. It took a while to get used to structured editing.

Conclusions

Ok, scheme is really different from java. But I like it. Also, some things from javascript seem to be concepts borrowed from functional languages like scheme.

I haven't even started to scratch the surface (I still have to try macros and continuations). Given the plethora of libraries available for chicken I think I could write something more real-world-like to go a bit deeper. I'll also try to write something with Kawa to harness the breadth of libraries available from java.

Permalink