Tag Archives: games

Fregl: an introduction to FRP

I’ve been mentioning quite a bit about my latest FRP implementation. First things first: You can find it here. The implementation is called “Fregl”, for “Functional Reactive Game Library”, roughly. But I thought I would take a moment to describe it and some of the directions I plan on taking it. The first section introduces FRP at a high level, and my intent is to write it so that someone unfamiliar with Haskell can at least get an idea of what it is about. The second section is much more technical, and goes into some of the implementation details. (Hmm, don’t have time right now to write the second section. It’s a post for another day.)

The Surface: Signals and Events

There are two major types of objects that make up the core of Fregl: Signals and Events. People familiar with FRP will feel right at home with these. A Signal is a value that varies over time, like any ordinary variable in a typical imperative language (they are defined and used very differently, though). An Event is just something that happens at some time, and then returns a value when it does happen. Both Signal and Event are type constructors, kind of like templates in C++; they carry with them an additional type. For example: Signal Int is a value of type Int that varies over time; Event Vec2 is an event that, when it happens, returns a 2D vector.

There are some core events, for example: waitClickPos, the position of the next mouse click; waitTimestep, occurs when a simulation timestep happens and returns the amount of time since the last one. There are a handful of others, but for simplicity we’ll only use mouseClick which we’ll define like this:

  mouseClick :: Event Vec2                        -- type signature (optional)
  mouseClick = waitClickPos ButtonLeft MouseDown  -- implementation

I should stress that Events are first-class objects just like any other (unlike events in C#!). There is nothing stopping a function from taking some arguments and returning an Event. In fact, waitClickPos does exactly that! It takes a button and a state and returns an Event representing when that mouse button enters that state.

It turns out that most of the logic in an FRP program comes in the form of custom events. Events are composable: you make big, complex events out of smaller ones. Here are a few examples. Non-Haskell programmers, I encourage you to try to understand this code too, it is pretty easy (and I’ve intentionally written it in a more imperative style).

  -- wait for two mouse clicks and return the position of the second one
  secondClick = mouseClick >> mouseClick

  -- wait for two mouse clicks and return the vector from the first to the second
  clickVector = do {
      pos1 <- mouseClick;
      pos2 <- mouseClick;
      return (pos2 ^-^ pos1);  -- ^-^ is vector subtraction
  }

  -- wait for a given amount of time
  waitTime time = do {
    if time <= 0 then
        return ()
    else do {
        dt <- waitTimestep;
        waitTime (time - dt);
    }
  }

  -- if there's a mouse click in the next 10 seconds, return its position,
  -- otherwise return (0,0)    (oh, how unhaskellish)
  clickInTenSeconds = eitherEvent waitTenSeconds mouseClick
      where
      waitTenSeconds = waitTime 10 >> return (0,0)

I hope by the last example you can start to see the power of such composability.

So far we have seen how to define your own Events, but Events don’t do anything. They just define what it means for something to happen, not what to do when they actually do happen. So we have to introduce an “event handler”, right?

Wrong. We need only two primitives, neither of which I would consider an event handler:

  -- return an event which happens instantly, returning the current value in the signal
  readSig :: Signal a -> Event a

  -- The returned signal takes on the value of the first signal until the event happens
  -- (and returns a signal), and takes on the value of the second signal from that point
  -- on.
  untilEvent :: Signal a -> Event (Signal a) -> Event (Signal a)

Examples of using these are coming soon. First, and this the essential difference from classical game programming, note that there is no “signal assignment”. To determine what the value of a signal at a certain time should be, you look at the signal’s definition, and that tells you everything. The only things which can affect its value are the things it depends on, not the things that depend on it. This is one of the sorts of “referential transparency” that Fregl obeys. There will be another–read on.

Okay, so how do you actually use these things? Here is one example to get the feel for it. Again, non-Haskellers should be able to understand this code given a little thought. Oh, I should mention the backquote syntax: If I write foo `baz` bar, that just turns the function baz into an infix operator; i.e. it is equivalent to calling baz with the two arguments: baz foo bar.

  -- Takes an 'initial value' and returns an event which occurs instantly, returning
  -- a signal which counts the amount of time since the event occurred plus the
  -- initial value.
  time :: Double -> Event (Signal Double)
  time init = pure init `untilEvent` do {  -- "pure" constructs a constant signal
      dt <- waitTimestep;
      time (init + dt);
  }

Let’s take a moment to study that code. It says that the returned signal takes on the constant value ‘init’ [“pure init”] until [“untilEvent”] the next timestep [“waitTimestep”], at which point it behaves like time (init + dt). It is a recursive definition. (Nit for the leet: the last line should be time $! init + dt lest we should make a huge addition thunk.)

It returns the signal inside an Event which occurs instantly. This is very common of signals. You can think of Events not just as things that happen, but things that have a perception of time. That is, our time function here needs to know what the “current time” is for its definition, which is why it must be returned inside an Event. Don’t worry if this part doesn’t make sense yet.

Now we get to step way outside the realm of conventional programming and define some really powerful stuff. It turns out that it is possible to define the following function:

  -- Returns an event which happens instantly, and returns a signal which represents
  -- the integral of the given signal over time, starting from the time the event
  -- was fired.
  integral :: Signal Vec2 -> Event (Signal Vec2)

(The actual implementation works on more general types than just Vec2)

Using this, we can define the following program (very similar to examples/follow):

  -- we use the following predefined signal:
  mousePos :: Signal Vec2

  -- defines the position of a ball that follows the mouse around
  follower = mdo {
      let acceleration = mousePos ^-^ position ;
      velocity <- integral acceleration ;
      position <- integral velocity ;
      return position ;
  }

If nothing in the article has given you chills yet, this should. In the definition of follower, first we define the acceleration to be the target position (the mouse) minus the current position. What do you mean the current position, where is that defined? Look two lines down, there it is, defined as the integral of velocity! This is a circular definition of position, essentially asking the library to solve the equation position = ∫∫ (mousePos – position).

Then, using this definition, we can easily turn this into a program which draws a ball at that position using the (very limited so far) drawing primitives:

  main = runGameSDL $ do {
    ballPos <- follower
    return (Draw.translate <$> ballPos <*> pure Draw.circle)
  }

And there’s the whole program.

This is just the beginning, the bare bones of FRP. It’s all embedded inside idiomatic Haskell, so we can use Haskell’s top-notch abstraction abilities to write out programs. To give you a flavor, here’s the signature of a neat function:

  -- Takes an event as an argument.  When this event fires, it should return a
  -- a signal (representing perhaps the state of an actor) and another event
  -- (representing the death condition for this actor).  So the returned signal
  -- will be in the output list between the time the "creation event" fires
  -- and the time the "destruction event" fires.
  actorList :: Event (Signal a, Event ()) -> Event (Signal [a])

This function implements the idea of a list of active actors, something I’ve written over and over in C++, whose implementation is always spread out across my program (iterate through it once in the draw() routine, once in the step() routine, once in the events() routine). A less general variation of it appears in examples/shmup, and it only takes about 9 lines to implement, once and for all.

That’s it for the layman’s introduction. One of my major programming-evangelistic goals is to convince people that OO is not the best way to solve every problem. I hope that this introduction has shown you that there are some non-OO techniques which can be immensely powerful that the game community has not even begun to explore.

Here’s a teaser for next time. It turns out, not by any conscious plan of my own, just by coincidence, that Fregl’s implementation of these semantics admits a very nice parallel implementation. In theory, it scales linearly with the number of processors automatically (i.e. the game programmer need not put in any extra work), which is a big deal if I do say so myself. I’ll be performing a practical test on one of CU’s 8-processor machines in a few days.

Sleepless Night

It’s one of those nights again. A night I am tired enough to sleep, but I just don’t want to for a reason that evades me. Instead, I’m staying up watching bad movies and wasting time. One way, I thought, to waste time would be to write some nonsense in my blog.

My life is pretty busy right now, in a way that would be judged by someone else to be completely the opposite. When I’m not staring at my computer, I’m playing the piano. But inside I know that the aforementioned someone else doesn’t know what he is talking about. Here’s some of the interesting stuff I’m working on:

I have a very powerful incarnation of FRP with well-defined (but occasionally spooky) semantics. The world is broken up into signals (values that vary over time) and events (somewhat spooky). It has a nice referential transparency-like property which I painstakingly maintained in my design (which was not entirely easy since Event is isomorphic to IO (or rather, a transformer thereof)). It was very tempting to allow things like writing files and allocating names for objects inside events. But I thought it through, and the property I want to maintain disallows those things. Anyway, I programmed a little shoot-em-up in the FRP library I wrote, and it’s quite encouraging. I still am not sure quite how to think in FRP, but the abstraction abilities are amazing (as expected). The only problem is that it is quite slow at the moment, but there are abundant opportunities for optimization in the library, which I just haven’t had the inspiration to implement.

I’m also working on several games. The first is the linguistic magic game that I’ve been talking about here on and off for several years. I have the simulation, and even a rough spec for the language (which is reminiscent of the aborted child of Esperanto and Finnish). I can’t say much about it without going into a lot of detail, so I’ll just put that off until later.

The other game I’m working on is a music and rhythm game, which has hopes of transcending the sight-reading trend. I have tried to design an improvisation game before, and it was never too promising. But this one is promising, and I have it basically fully specced out in my head. I’m going back the other direction towards sightreading, but not all the way. It’s a hybrid of sightreading and improvisation, where the game is serving as the conductor (remember my founding idea for SNW?) and you, the player, are serving as the musician. As an example flow, the computer would give you a drum beat and might start you off with a Guitar Hero style sightreading thing as a bassline; i.e. “play this line verbatim”. You repeat that 6 times, and then the computer takes over: the bassline continues, but your fingers do not. Then maybe it gives you a line to play, but it just tells you the notes and the order, not the rhythm. You are in charge of inventing the rhythm for that line. And so on. There are soloesque line sections where it gives you a set of notes, and you just have to play all the notes in the set, but the order and rhythm is up to you. There are invent-your-own-bassline sections, where you play any bassline you like, but then you’ve got to repeat it (and keep coming back to it throughout the song). The key, tempo, drum part, and song structure are dictated by configuration files, but the exact incarnation of the song is up to the player.

I’m also learning Hungarian Rhapsody no. 2 by Liszt on the piano, which is the second most rediculously difficult song I’ve ever attempted (the first being—*snicker*—Rachmaninoff’s 3rd Piano Concerto, which, needless to say, I did not get very far into).

FRP: What’s the big deal?

I really have to get to bed, but I just did a little test and am so excited I need to say something:

AFRP sucks. The incredible amount of trouble I had to go through just to implement extremely simple physics with a dynamic number of balls within FRP (none of that cheating by factoring the physics elsewhere; while that may be a good thing to do, it’s a point for the power of FRP if you can do it directly in FRP) indicates that AFRP is absolutely not suitable for games. The short reason is that is chokes when faced with dynamic behavior.

On the other hand, classical comonadic FRP is great; it supports such dynamism without a sweat. That is, if it weren’t for the spacetime leak that results when you have value recursion like:

  e = integral 1 e

Which is horrible because that is the form of every differential simulation (read: games).

Because of that leak, I tried three different approaches with arrows, with varying flexibility trade-offs, but they were all bad for making games. I wanted to go back to comonadic FRP so badly, but the spacetime leak loomed in the darkness, condemning my programs to progressively slow down (and eat up more and more memory) as they ran.

As refresher, the data structure for comonadic FRP is:

  type DTime = Double
  data Signal a = Signal a (DTime -> Signal a)

And today something hit me, something so simple that it made me reconsider my sanity:

  -- 'runSignal step sig' produces the infinite list of
  -- values every 'step' seconds from 'sig'
  runSignal :: Double -> Signal a -> [a]
  runSignal = ...

  -- listSignal is the inverse of runSignal, constructing
  -- a signal from a list
  listSignal :: Double -> [a] -> Signal a
  listSignal = ...

  buffer :: Double -> Signal a -> Signal a
  buffer step = listSignal step . runSignal step

The buffer function just samples a signal at regular intervals, caching the results internally in a list. The implementation of these three functions combined is 13 simple lines; the concepts are easy too. Again, foreheadslap! Why? This is why:

  e = buffer 0.05 $ integral 1 e

No more spacetime leak! The nth timestep of e is found in linear time and constant space. To generalize the technique, just put a buffer between any value recursion to fix the leak. No, it’s not a perfect solution, but it’s a good compromise. You still get perfect granularity in your event handling (to me, an essential property), and you get to use comonadic FRP.

I’m so excited!

Revolution Revised

We playtested Revolution at GameDev tonight. Despite the very vague rules, and the GMs mostly making it up as we go along, the playtest went pretty well and showed the game definitely had potential.

After the playtest, I rewrote the rules incorporating a lot of the stuff we settled on (and some new stuff).

It was amazing how little people broke away from the “standard game”, just focusing on pure resource gathering and weapon production. Eric was the best at drawing outside the box: he formed a new religion (using some deceptive persuasion skills he learned through a Red Light District) and non-violently converted two farm lands into his control (the second after a “no military invasion of farms allowed” law was passed). Rob did a pretty good job too, though he went home before he really had a chance to use it. Ben made a massively good deal with the government early on, essentially protecting him from any invasion. I don’t think he won though.

One thing I noticed was how hard it was for the government to maintain unity. After the first two turns, the revolutionaries’ interests conflicted, and no laws were introduced without being vetoed. That kept the lawmaking game at a standstill, unfortunately. My revision addresses that by not giving anybody any goals until after the first round, and a proposed rule which allows the people to award the government points for treating them well (see discussion page on rewrite for a precise description). I’m not sure how well either of those would work.

According to Jude’s description of his experience, the game captured one of the dynamics I was going for very well: the trade-off between human values and economics. You have to make decisions which are unpopular, or even which hurt the well-being of the people in general, in order to grow the nation’s economy. Stalin, for example, made that trade fully focusing on the economy and none on the people :-/.

But it looked like everyone was having a good time modulo the complaining about us “making it up as we go along” (which we were… which is why we’re impartial game masters). Having two game masters was a good idea, though with more structure (as in my rewrite) it might suffice to have one… maybe. Another would be nice to give rule clarifications, since they cannot be avoided. But people were acting like they were treated fairly despite the open-ended rules.

I’m excited to play this again. Or play it at all. Or observe it as a GM again. I just want to see where it goes.

Revolution

Here is a design sketch (or maybe even a complete design) for a live role playing game which vaguely resembles Werewolf and Diplomacy.

I call it Revolution, because the game begins just after a culture has a violent uprising. There’s a game master, and all the non-game-master players represent people in this culture. The game revolves around victory points; play to 10 or something (maybe 4 would be more realistic).

The game master resides in a private lair for most of the game. One of the only hard rules of the game is that you may not eavesdrop on the game master’s conversations with players. At the beginning of the game, each player meets with the game master to recieve his role and his first goal. A goal is just something which must happen in the game world, and when it does, the player who owned that goal recieves a victory point (and a new goal). For instance, “accumulate $1,000,000″, or “kill Hagan”. Your goal is hidden information.

If your goal can never be satisfied, such as when your character dies (or for some other reason), you lose a victory point and recieve a new goal. If you die, you basically respawn as another character entirely, with a new role too. It’s a role playing game, so if your previous character posessed some knowledge when he died, you should do your best to forget that knowledge ;-).

The idea of a role and the whole concept of the gameplay of this game are intertwined. A role essentially defines your character. You could be a successful businessman in some industry, a mob boss, a peasant (not that fun a role to play perhaps, so it might be left out), a police officer, etc. Roles are chosen by the game master to make an interesting game. Gameplay progresses in rounds; during each round people exchange in free conversation and trade, and come to the game master whenever they want to do something nontrivial in the world. What you’re allowed to do depends on your role: if you’re a successful businessman, you can come to the game master and ask for a bunch of money. If you’re a mob boss, you can steal things (or rather have your imaginary cronies do it) and murder people and whatnot. If you have accomplished a goal, you tell the game master, and he gives you a point and a new goal.

At the end of each round, which ends when the game master feels like it (maybe timed), everybody gathers in a public place and the game master announces notable things that have happened during the round, and then announces the score (or keeps track of it on a board). Then the next round begins.

There is one special role which gets assigned to three(ish) people: revolutionary. These are the people who were at the right place at the right time for the revolution and decide to start the provisional government. Over the next few rounds, they meet and decide on laws and policies, and announce them at the end of each round. They are also in charge of enforcing those laws, which they can do using imaginary entities (such as a police force) through the game master.

People can meet the game master in groups to do something like an uprising (which would essentially assign three new revolutionaries). But they all have to decide to enter as a group, which means they need some organization. And the government is allowed to observe said organization and try to thwart it. Etc. etc.

In summary it is a very loosely defined game which is very much up to the game master to make interesting. That’s the epitome of a role-playing game though, isn’t it?

Dreams of FRP

Here is a post about how I see programming a game in Functional Reactive Programming. It’s oriented toward people who already get the basics of FRP. It is based on the original paper, rather than the newer AFRP paper. The “circuitry” model doesn’t seem to fit into my head as well as behaviors and events do, but maybe I’ll see how arrows play into it once I explore the subject a bit more.

This is a dreamy post; I have not actually done any FRP yet (partly because I can’t get the AFRP library to build), but I have read and understood enough to do it in my head. I’m going to write code in the way I would like to be able to write it, and then sometimes correct it to how I would actually have to write it given lifting and all that bullcrap.

A little refresher: an Event is a just a value that “occurs” at some time (possibly in the “future”). Event is a monad, with its join operation defined by the the occurrence of the value (another event) that the event returns. a Behavior is a value that depends on time, for example the current position of the mouse or the action that draws the current frame. Behavior is a comonad, with its cojoin defined by projecting the time into its argument. I think Event and Behavior are nicely dual, but I haven’t really explored it.

The paper gives an example of a bouncing ball, which actually disgusted me for a minute. The “modular” 1-D bounce function’s workings were not obvious or clear, and it wasn’t quite so modular as they claimed. For example, it incorporated gravity. What the heck does gravity have to do with bouncing?

Upon further thought, I discovered that that is no limitation of FRP. Instead it was just a poor implementation of bouncing balls. Let’s try again.

What is the essence of bouncing? Impulses… which are strangely absent from their implementation. In a traditional model I would implement an impluse simple as a force divided by the delta time. But FRP explicitly abstracts over time deltas, so that won’t work. What is an impluse then? I’d encode it using an event containing a momentum delta vector.

In order to have events affect behavior, we’ll define a new type, an event stream:

  newtype EventStream a = EventStream (Event (a, EventStream a))

It’s just an event which returns a value and a new event stream, containing all subsequent events. Then we can model the sequence of wall-bounces using an EventStream Double (remember we’re in 1-D) or some such.

To turn event streams back into behaviors, we want a function analogous to scanl for lists:

  scanES :: (a -> Time -> b -> a) -> a -> EventStream b -> Behavior a
  scanES f init (EventStream e) =
                   lift0 init `untilB` e +=> \ t (x,es) ->
                                                 scanES f (f init t x) es

It takes on the value of init until the first event happens, when it passes the value of the event and the current state to the folding function and takes on the result, etc. I have an inkling that this is not quite as general as it could be, but it’ll do for now.

Given this format, we can have the bounce function return a stream of impulses:

  bounce :: (Double,Double)     -- boundaries
         -> Double              -- radius
         -> Behavior Double     -- position
         -> Behavior Double     -- velocity
         -> Time                -- initial time
         -> EventStream Double  -- return impulses
  bounce (minBound,maxBound) radius pos vel t0 =
          stream t0
      where
      -- just a helper function so we don't have to repeat all those args
      stream :: Time -> EventStream Double
      stream t = EventStream (nextImpluse +=> \t' imp -> (imp,stream t'))

      collideRight, collideLeft, collide :: Event ()
      collideRight = predicate (pos + radius >= maxBound) t0
      collideLeft  = predicate (pos - radius <= minBound) t0
      collide      = collideRight .|. collideLeft

      nextImpulse :: Event Double
      nextImpulse = snapshot collide vel ==> \((),v) -> -2*v

Which I find quite a bit nicer than their version. To get to the bouncing balls:

  integrateES :: (Num a) => EventStream a -> Behavior a
  integrateES = scanES (\cur t v -> cur + v) 0

  ballPos :: Behavior Vec2
  ballPos = pos
    where
    pos = integrate vel
    vel = (1,1) + integrateES imp + integrate accel
    accel = (0,-0.5)  -- gravity
    imp = (impx, impy)
    impx = bounce (-10,10) 1 (fst pos) (fst vel) 0
    impy = bounce (-10,10) 1 (snd pos) (snd vel) 0

And this is really where FRP is beautiful. This felt incredibly declarative to write: the position is just the integral of velocity, the velocity is just (1,1) + the integral of all impulses + the integral of acceleration, etc.

Sadly, this is not valid Haskell. I left out all the necessary lifting in both of these snippets. I’m hoping that the arrow notation will be able to alleviate some of the tireless lifting. For comparison, here’s a correct version of ballPos:

  ballPos :: Behavior Vec2
  ballPos = pos
    where
    pos = integrate vel
    vel = liftW2 (\imp' accel' -> (1,1) + imp' + accel')
                (integrateES imp) (integrate accel)
    accel = lift0 (0,-0.5)
    imp = liftW2 (,) impx impy
    impx = bounce (-10,10) 1 (liftW fst pos) (liftW fst vel) 0
    impy = bounce (-10,10) 1 (liftW snd pos) (liftW snd vel) 0

Which is quite a bit muckier. Still, the concepts are clean and elegant. And I didn’t pull very much at all out of thin air, everything I used was firmly grounded in the paper.

More posts about FRP coming soon!

Screenplay

Here’s a sketch of a short screenplay I’d like to write.

Depict a stereotypical “successful businessman” finishing a day’s work (closing a deal or something), driving home in his nice car, sitting in front of his top-notch TV set and beginning to play a video game. Repeat a few times, with some, but not too much, variety. Playing somewhat, again not too much so, digital-sounding music.

Pan out to find that this depiction is in fact on a top-notch home theater, a video game being played by an identical stereotype, but a different actor. He expresses boredom or frustration somehow, that he wants his character in the game to do something different. Frustrated, he turns off the console and walks outside.

Depict him climbing trees, hopping across a river on stones, other fun things in organic environments. Playing fluid, organic music. Close with him jumping on a goomba.
image of goomba

Suggestions?

Boulder Buy’em Poker

The boulder gamedev club had a card game jam this week. My group made a poker variant. It’s pretty good (it received the high praise from Namaste, “I’m not sure if it’s better than no limit Texas Hold’em”). The game has been dubbed “Boulder Buy’em” by Paul Steinbrecker. Here are the rules.

Each player, as usual, starts with some chips somehow. There’s a dealer button on one of the players, and it rotates clockwise each round.

Something to note while reading this: there is no “dealing”, and players do not receive a new hand each round. Instead they build their hand over the course of multiple rounds.

The round proceeds in several phases:

  1. Ante
  2. Auction
  3. Claims
  4. Discards

The Ante phase is just an ante. Each player puts in a fixed ante.

The Auction phase is quite unlike any other poker game. Cards equal to the number of players are placed on the table, 2 of them face up1, the rest face down. It’s an auction for first choice of cards to put into your hand. The player on the dealer button makes a fixed blind bid (double the Ante in our playtests). Then there is a free auction without ordering (just calling out numbers with the dealer acting as the auctioneer); for cases without a dedicated dealer, it’s possible to use a turn-based auction style. There is no minimum increment for bidding, except as restricted by the chip values (it is perfectly reasonable for the blind to be 10, someone to bid 100, and then someone else bid 105). The winner of the auction pays the amount he bid, everyone else pays nothing. The winner then takes a card from the table of his choice, face up or face down, and the rest of the players take cards from the table in clockwise order.

The Claims phase is much more like a traditional poker hand. Most rounds there will be no claims, but the dealer should make the request for claims each round. The first person to say “claim” after the request initiates a claim. He chooses any number of cards from his hand and places them on the table face down in front of him, optionally in addition to some chips (as an opening bid). Then, proceeding clockwise around the table, each player has the standard options (raise, call, fold). When a player raises or calls, he chooses cards from his hand to put on the table. If the number of cards the player plays exceeds the maximum number of cards anyone has on the table, then it “counts” as a raise in terms of actions: everyone else gets another chance to act. It also counts as a raise if it was a monetary raise, of course. Whenever a player acts, he gets a chance to put more cards on the table face down in front of him, but not to remove any cards.

When the bidding completes, everyone is either folded or has the same amount of money and some cards (not necessarily the same number) on the table (modulo all ins). There is then a showdown. Starting with the last person to bid or raise, proceeding clockwise, a player can show his cards or muck. The best hand takes the whole pot, including the pot built up over the past few rounds from the auction phases. All the cards which were played on the table are reshuffled into the deck, including those of folded players. Players get to keep cards which they never played on the table.

On the Discard phase, all players who have more than seven cards in their hand choose cards to discard down to seven, and the dealer reshuffles those into the deck.

In tournaments, if a player does not have enough for the ante, he pays whatever he can into the ante. No special splitting is necessary in this case (think about it). It is strongly advised to claim that round (because otherwise the player is definitely out).

If the player on the dealer button does not have as much as the blind bid, then the blind bid is equal to the player’s stack and starts from there. That is, if the blind is 50, but the player only has 10, then the blind is considered 10 and it is perfectly reasonable for another player to bid 15.

If a player wishes to sit out, he must sit out until the round after the next claim, so his next ante will be into an empty pot. Harsh and variable, I know. This is necessary to keep player from sitting on a good hand not paying ante until the pot is huge.

1During heads up, only one of the two cards is face up. All the other rules remain the same.

Making Haskell nicer for game programming

Last week I tried to create a board game programming architecture in Haskell. The idea was to base the architecture around specifying an abstract state machine for the game. As we discussed in GameDev this week, abstract state machines aren’t exactly appropriate for games, but they’re close enough that you can make a few modifications to the idea and get something cool (the biggest modification being that your set of rules is part of your state).

Haskell was a joy to work with in this sense. I made a monad which handled the transactional nature of ASMs; I differentiated between rules and actions in order to enforce the if condition then action structure which makes reasoning about ASMs easy. It was cool stuff, and it took about 100 lines of code.

Then I set out to write my first game with it. Just a simple bidding game I found somewhere; I don’t remember what it was called. And it hit me: games are stateful, definitely abstract state machines are stateful, and Haskell sucks when it comes to content programming for stateful systems. I was trying to show how easy it would be to specify a game with dynamically changing rules, and all I could think about was how to refactor the horribly ugly code that ensued.

For the first time ever, I used C macros in a Haskell program. There are a lot of good reasons not to do this. But it did make working with stateful data much easier. Here’s the idea:

First, let’s make our game state object:

data GameState
    = GameState { _p1bid :: Int
                , _p2bid :: Int
                , _score :: Int
                }

Because very few Haskellers read this blog, I’ll explain. That essentially declares a new class with three member variables, whose names you should be able to extract.

Now we make the monad in which we will perform game computations:

type Game a = StateT GameState IO a

When we perform a computation inside the Game monad, there is a “global” GameState at our disposal. But we also need to interact with the user (the computation is not “pure” in that sense), so we glob on the IO monad.

That was all fairly straightforward. Here’s the new stuff. Define an “Accessor” class, which abstracts over the ability of data inside the state to be read and written:

data Accessor a
    = Accessor { readVal :: Game a
               , writeVal :: a -> Game ()
               }

Again, it’s just a class—actually a template class abstracted over the type a—with two members, readVal and writeVal. Except this time the members have more complex data types. readVal performs a computation given no input (namely, to return the value), and writeVal performs a computation given an a as input (namely, to store the value back into the game state). We will define an Accessor object for each data member in our state, each with different implementations of readVal and writeVal.

Here’s where the macros come in. The implementations are different, but they are regularly different, but not abstractable due to limitations which ultimately boil down to Haskell’s type system (no partial records). We define a macro to define an accessor for us:

#define ACCESSOR(NAME) \
NAME = Accessor { readVal = fmap _ ## NAME get \
                , writeVal = \n -> get >>= \s -> put $ s { _ ## NAME = n } \
                }

Wow, that’s ugly. Fortunately it’s the last of the ugly we will see. For non Haskellers… I’m not going to explain that in detail. Suffice to say that it defines an Accessor object called NAME which does the right thing. It assumes that the element in our state being referenced is called NAME with an underscore prepended.

Now we define a few accessors:

ACCESSOR(p1bid)
ACCESSOR(p2bid)
ACCESSOR(score)

And now we can start defining some familiar procedural operations, like := (which we must spell =: because operators that start with a colon have a special meaning) and +=.

a =: x  =  writeVal a x

a += x  = do
    a_ <- readVal a   -- I would have called it a', but the C preprocessor doesn't like that
    a =: (a_ + x)

a -= x  =  a += (-x)

-- etc. etc.

If we were making this into a library, we would probably define the precedences to be saner, so we wouldn’t have to, for example, parenthesize (a_ + x) above.

And then you can go on defining your game:

main :: IO ()
main = flip evalStateT (GameState 0 0 0) $ loop $ do
    liftIO $ putStr "Player 1, bid: "
    bid <- liftIO readLn
    p1bid =: bid
    -- ...
    cmp <- liftM2 compare (readVal p1bid) (readVal p2bid)
    case cmp of
        LT -> score -= 1
        EQ -> return ()
        GT -> score += 1

Which feels an awful lot nicer. For comparison, score -= 1 would otherwise have been written:

get >>= (s -> put $ s { _score = _score s - 1 })

It still ain’t perfect. I don’t like that I have to read values from the state into temporary variables (well, I don’t have to, but I do if I want anything to be near readable). There’s really no way around that, except for more preprocessing!… which I’m not going to do.