Flush Internals

State management in Flush (and in games in general)

Most games need to manage the current state of a game, be it chess positions or number of cards played or the size of the pot. One could always use an global variable like turn and then set the variable to the next player., However, another approach could be to use functional programing idioms and let the state flow from one player to the next without having to create any such variable.

Suppose there is a list of players, then we could recursively work on the list and get to the next player.

For example:
(define (play players)
(if  (null? players) ‘end
    (begin
(do-sth (car players))
(play (cdr players))))

Here we recurse on the list players and call do-sth on the first player in the list.

Here we have completely removed the use for a turn variable. However, in this simplistic example there is no  state management. In the game of flush, there are a couple of variables we need to manage, viz. the current size of the pot, the current minimum allowable bet amount and the amount of money each player has and info on whether a player has passed or not.

Lets add the first two variable into our example. Also we change do-sth to play? which looks at the cards of the current player and decides whether it wants to play or not.

(define (play players pot minbet)
(if (null? players) ‘end
   (if (play? (car players)
       (play (cdr players) (+ pot minibet) minibet)
       (play (cdr players) pot minibet)

Now , when a player plays,   the size of the pot increases and this information is passed on to the next player .( Note that we don’t have the functionality right now to increase the minibet yet.)

But a coulple of information are missing like the amount of money player1 has and the pass state of a player. If a player has already passed, it will simply pass all the information to the next player.

(define (play players pot minibet ms ps)
(if (null? players) ‘end
   (if (and (car ps) (play? (car players) minibet pot (car ms))
                               (play (cdr players) (+ pot minibet) minibet (cdr ms)  (cdr ps))
                               (play (cdr players) pot minibet (cdr ms) (cdr ps)))))

Ok, now we’ve made a couple of changes. First we added the list ms (money ) and ps (pass status) for each player. The (car ps) is set to true if a player is still playing, so we’ve also added that in the if statement. Also we’ve added more parameters to the play? function since you need the information on how big the pot is, how much money you have and what the minimum bet is to make your decision.

Still a couple of things are missing here. First when you run out of players, it just stops. We’ll worry about that later. Another thing that’s missing is the new state of money and the pass state. While we have information on the amount of money you have right now, we have no way to record the amount of money you have after you decide to play, Also, if you decide not to play this turn, there is no way to record that info.

Lets digress here to talk about some of the idioms of functional programming. Here’s a common way to recursively calculate length of a list.

(define (length lst)
(if (null? lst) 0 (+ 1 (length (cdr lst))))

The problem with this is that scheme has to keep track of the recursion and what is left to do. For eg. if you calculate length of a list (1 2 3) it recurs three times, and comes back up three times adding 1 for each recursive call. This problem is usually solved using accumulators.

(define (length-helper lst value)
(if (null? lst)

Some updates

Some updates on the callbreak and satori applications. I have finally gotten around to setting up my ec2 server and now callbreak (Seaside version ) and the Satori (github.com/alokthapa/satori) are both available online. 

 

Link to callbreak : bit.ly/playcallbreak

 

Link to satori: http://bit.ly/f5BIrk (although this seems to be broken right now… 😦 )

 

Also, I’ve been working on a scheme implementation for flush (or sth like that), which is played using 3 cards. It’s available here at github.com/alokthapa/flush so download it and check it out. You will need Racket 5.1 to play the game. 

 

Enjoy.

A web-based teaching application

I was inspired by the way “The Little Schemer” was used to teach scheme, with question on the left and answers on the right. I wondered how hard it would be to build a web app that could teach you in such an interactive way. Not so hard as I later found out, it needed less than 70 lines of code to build a prototype. Not only is the code small, but all you need to do is create a “nodes” datatype to create your own custom book! 

The application first starts with a list of nodes. Each node contains a question to ask and possible responses. Each response can either do nothing (i.e. you move on to the next node in the list), jump you to another named node or have their own child nodes that only they can visit. Each node may or may not have a label, so we can only use them when we need to jump. 

Here’s a small example that tries to teach you French.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 
#lang racket
(require web-server/servlet)
(require web-server/servlet-env)


; a teaching web thingy where you can create your own custom teaching libraries.
;
;
; let's call an ask-response an askonce
; askonse contains ask and response
;
; ask can contain text, pics or combinations of either.
;
; response can contain text, and choices.
;
;
; each askonse can have a label so that you can get back to it later.
;
; each response leads to another askonse.
;
; How would it be structured?
;
; 1. you should be able to ask questions and save them to variables.
;
; for eg. you could ask a persons name and reuse it to address the person later on.
;
; askonce -> list of nodes
; ask/responsetext -> some html markup thingy
; car of node -> ask
; cdr of node -> list of possible responses
; last of node (optional) -> label for node
; car of response -> responsetext
; cdr of response (optional) if atom -> go to label
; cdr of response (optional) if list -> a node
;
;
; if no cdr of a response exists, then it moves to the next askonce
;
;
;
;
;


(define nodes
  '(("how do you do?" (("not bad! how about you?")) home)
    ("I'm fine thank you!!"
     (("I don't really care!!" home)
      ("you're welcome")))
    ("Bonjour" (("Bonjour! Is that French?")) bonjour)
    ("Oui! Bonjour means 'good morning' in French"
     (("Ahh! Je comprend!")))
    ("What do you think 'bon' in bonjour means?"
     (("umm I don't know..." ("it means 'good'" (("ahh.."))))
      ("I guess it means good" ("awesome" (("thanks"))))) complicatednode)
    ("Ok now what might 'jour' mean?"
     (("night" ("not quite" (("sorry.."))))
      ("day! it means day!" ("awesome" (("thanks!"))))))
    ("too complicated"
     (("yes!" bonjour)
      ("not really")))))

(define (start request)
  (show-nodes nodes request))
  
(define atom?
   (lambda (x)
     (cond
       ((null? x) #f)
       ((pair? x) #f)
       (else #t))))

(define (response-text r) (car r))

(define (find-node lbl)
    (local [(define (find-lbl n)
              (if (null? n) '()
                  (let ((lblname (last (car n))))
                    (cond
                      ((and
                        (atom? lblname)
                        (eq? lblname lbl)) n)
                      (else (find-lbl (cdr n)))))))]
      (find-lbl nodes)))
             

(define (node-ask n) (first n))
 
(define (response-action r)
  (if (pair? (cdr r))
      (cadr r)
      '()))
 
(define (node-responses n)
  (second n))

(define (node-label n)
  (let ((lbl (last n)))
    (if (atom? lbl)
        lbl
        'empty-label)))

(define (has-label? n)
  (eq? 'emtpy-label (node-label n)))
      
(define (show-nodes n request)
  (local [(define (current-node) (car n))
          (define (response-generator embed/url)
            `(html (head (title "Graph Traversal example"))
                   (body
                    (p ,(node-ask (current-node)))
                    ,@(map (lambda (r)
                             `(p(a ((href ,(embed/url (new-node-location r)))) ,(response-text r))))
                           (node-responses (current-node))))))
          (define (new-node-location resp)
            (let ((action (response-action resp)))
              (cond
                ((null? action) (lambda (req) (display 'is-null) (show-nodes (cdr n) req)))
                ((atom? action) (lambda (req) (display 'is-atom) (show-nodes (find-node action) req)))
                ((pair? action) (lambda (req) (display 'is-pair) (show-nodes (cons action (cdr n)) req))))))]
    (send/suspend/dispatch response-generator)))

(serve/servlet start #:quit? #t
               #:listen-ip #f
               #:servlet-path ""
               #:servlet-regexp #rx""
               #:port 8000)

Output:

This is the first page after you run the application. It shows the question of the first node. Since its response does not contain any action, it simply creates a link to the next node. 

[[posterous-content:pid___0]] 

This page for the second node. There are two possible responses, either you say “I don’t care” which takes you back to the “home” node while clicking on “you’re welcome” takes you to the next node. 

 

[[posterous-content:pid___1]]

 

Let’s skip the next node as it only has one response. Now the fourth node contains two responses each of which sends you to a different node.

[[posterous-content:pid___2]]

If you click on “umm I don’t know…” , you get to this page.

[[posterous-content:pid___3]]

 

and if you click on “I guess it means good” link, you get to this page. 

[[posterous-content:pid___4]]

 

Since, none of the responses above do anything more clicking any of the two link above takes you to the page for the next node. 

 

Enjoy.

 

ASP.NET Wrapper Panel

This is a useful control that works like a masterpage but is more lightweight. You can use this control as a wrapper for commonly used html snippets in your code.

 

This is the code file for the control.

 

You would use it as follows:

The result would be:

Now you can focus on what’s important and not worry about the wrapping html code.

Also using the TemplateInstance.Single attribute, you can access controls within your wrapper just as you would without it. If you didn’t use it, you willl have to access them using the FindControl function on wrapper control.