~subsetpark/whist

8fc382a6dce31cc91d6440c69bd07e137b29b63c — Zach Smith 6 months ago b0f715a literate master
Format all
9 files changed, 200 insertions(+), 223 deletions(-)

M bids.janet
M cards.janet
M events.janet
M game/play.janet
M init.janet
M lit/events.lit
M main.janet
M players.janet
M whist.lit
M bids.janet => bids.janet +8 -8
@@ 20,12 20,12 @@

## Second Bids
(def- direction [[{:direction "up"} "Uptown"]
		[{:direction "down"} "Downtown"]])
                [{:direction "down"} "Downtown"]])

(def- suit [[{:suit "hearts"} "Hearts"]
	   [{:suit "spades"} "Spades"]
	   [{:suit "diamonds"} "Diamonds"]
	   [{:suit "clubs"} "Clubs"]])
           [{:suit "spades"} "Spades"]
           [{:suit "diamonds"} "Diamonds"]
           [{:suit "clubs"} "Clubs"]])

(def second-bids (array/concat @[] direction suit))



@@ 41,7 41,7 @@
  [bid &opt source]
  (default source bids)
  (if-let [ind (find-row-index (freeze bid) source)
	   row (source ind)]
           row (source ind)]
    (row 1)
    (error (string "Not found: " (string/format "%q" bid) " in " (string/format "%q" source)))))
## Available Bids


@@ 52,9 52,9 @@
  (case high-bid
    nil (array ;bids ["pass" "Pass"])
    (if-let [minimum-bid (if (no-trumps? high-bid)
		 	   {:count (inc (high-bid :count)) :direction "up"} 
			   {:count (high-bid :count) :suit "no_trumps"})
	     minimum-bid-ind (find-row-index minimum-bid bids)]
                           {:count (inc (high-bid :count)) :direction "up"} 
                           {:count (high-bid :count) :suit "no_trumps"})
             minimum-bid-ind (find-row-index minimum-bid bids)]
      (array/push (array/slice bids minimum-bid-ind) ["pass" "Pass"])
      @[["pass" "Pass"]])))


M cards.janet => cards.janet +63 -63
@@ 3,23 3,23 @@
(defn to-text [{:suit suit :rank rank}]
  (case suit
    "joker" (case rank
	      2 "Big Joker"
	      1 "Little Joker")
              2 "Big Joker"
              1 "Little Joker")
    (let [suits {"diamonds" "♦" "spades" "♠" "clubs" "♣" "hearts" "♥"}
	  ranks {1 "Ace"
		 2 "2"
		 3 "3"
		 4 "4"
		 5 "5"
		 6 "6"
		 7 "7"
		 8 "8"
		 9 "9"
		 10 "10"
		 11 "J"
		 12 "Q"
		 13 "K"}]
	(string (suits suit) (ranks rank)))))
          ranks {1 "Ace"
                 2 "2"
                 3 "3"
                 4 "4"
                 5 "5"
                 6 "6"
                 7 "7"
                 8 "8"
                 9 "9"
                 10 "10"
                 11 "J"
                 12 "Q"
                 13 "K"}]
        (string (suits suit) (ranks rank)))))

## Of Suit or Off
(defn- of-suit


@@ 32,18 32,18 @@
  "Return any cards in stack that match the led suit, or are jokers."
  [led-suit stack]
  (let [with-jokers |(or (= led-suit ($0 :suit))
			 (= "joker" ($0 :suit)))]
                         (= "joker" ($0 :suit)))]
    (filter with-jokers stack)))

(defn of-suit-or-off
  "Return any cards in stack that match the led suit, otherwise return all cards."
  [led-suit current-bid stack]
  (let [on-suit (if (= led-suit (current-bid :suit))
		  # If the led suit is trumps, then look for all cards
		  # of that suit or jokers.
		  (of-suit-or-jokers led-suit stack)
		  # Otherwise, look just for cards of that suit.
		  (of-suit led-suit stack))]
                  # If the led suit is trumps, then look for all cards
                  # of that suit or jokers.
                  (of-suit-or-jokers led-suit stack)
                  # Otherwise, look just for cards of that suit.
                  (of-suit led-suit stack))]
    (if (> (length on-suit) 0) on-suit stack)))

## Enable Card Comparison


@@ 63,48 63,48 @@

(defn- uptown-card [trumps]
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] 1
		 @[_ "joker"] -1
		 @[trumps trumps] (uptown (self :rank) (other :rank))
		 @[trumps _] 1
		 @[_ trumps] -1 
		 @[_ _] (uptown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] 1
                 @[_ "joker"] -1
                 @[trumps trumps] (uptown (self :rank) (other :rank))
                 @[trumps _] 1
                 @[_ trumps] -1 
                 @[_ _] (uptown (self :rank) (other :rank))))})

(defn- downtown-card [trumps]
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] 1
		 @[_ "joker"] -1
		 @[trumps trumps] (downtown (self :rank) (other :rank))
		 @[trumps _] 1
		 @[_ trumps] -1 
		 @[_ _] (downtown (self :rank) (other :rank))) )})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] 1
                 @[_ "joker"] -1
                 @[trumps trumps] (downtown (self :rank) (other :rank))
                 @[trumps _] 1
                 @[_ trumps] -1 
                 @[_ _] (downtown (self :rank) (other :rank))) )})

(def- notrumps-card
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] -1
		 @[_ "joker"] 1
		 @[_ _] (uptown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] -1
                 @[_ "joker"] 1
                 @[_ _] (uptown (self :rank) (other :rank))))})

(def- notrumps-downtown-card
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] -1
		 @[_ "joker"] 1
		 @[_ _] (downtown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] -1
                 @[_ "joker"] 1
                 @[_ _] (downtown (self :rank) (other :rank))))})

(defn- make-compare-enable-fn [current-bid]
  (let [proto (match [(current-bid :suit) (current-bid :direction)]
		@["notrumps" "up"] notrumps-card
		@["notrumps" "down"] notrumps-downtown-card
		@[trumps "up"] (uptown-card trumps)
		@[trumps "down"] (downtown-card trumps))]
                @["notrumps" "up"] notrumps-card
                @["notrumps" "down"] notrumps-downtown-card
                @[trumps "up"] (uptown-card trumps)
                @[trumps "down"] (downtown-card trumps))]
    (fn [card]
      (table/setproto card proto))))



@@ 113,9 113,9 @@
  "Return any cards in stack that match the led suit, or are trumps."
  [led-suit trumps stack]
  (let [with-jokers-and-trumps
	|(or (= led-suit ($0 :suit))
	     (= trumps ($0 :suit))
	     (= "joker" ($0 :suit)))]
        |(or (= led-suit ($0 :suit))
             (= trumps ($0 :suit))
             (= "joker" ($0 :suit)))]
    (filter with-jokers-and-trumps stack)))

(defn high-card


@@ 123,13 123,13 @@
  [stack led-suit bid]
  (let [f (make-compare-enable-fn bid)]
    (->> stack
	 # Get a version of the current-trick where
	 # each card has a `:compare` method that's
	 # aware of the current bid.
	 (map f)
	 (of-suit-or-trumps led-suit (bid :suit))
	 # Get the highest card according to each
	 # one's `:compare`.
	 (extreme compare>))))
         # Get a version of the current-trick where
         # each card has a `:compare` method that's
         # aware of the current bid.
         (map f)
         (of-suit-or-trumps led-suit (bid :suit))
         # Get the highest card according to each
         # one's `:compare`.
         (extreme compare>))))



M events.janet => events.janet +2 -2
@@ 9,9 9,9 @@
(defn end-game
  [players team1 score1 team2 score2]
  (let [players1 (players/of-team players (string team1))
	players2 (players/of-team players (string team2))]
        players2 (players/of-team players (string team2))]
    {:event "end_game" :scores (zipcoll (array/concat players1 players2)
					[score1 score1 score2 score2])}))
                                        [score1 score1 score2 score2])}))

# Decorations
## Events: Add Decoration

M game/play.janet => game/play.janet +4 -4
@@ 39,9 39,9 @@
  [players bid info]
  (let [bidding-team (bidding-team players bid)] 
    (->> (players/of-team players bidding-team)
	 (map |(keyword $0 "_tricks"))
	 (map |(info $0))
	 (sum))))
         (map |(keyword $0 "_tricks"))
         (map |(info $0))
         (sum))))

## Bid Values
(defn- adjustment-for-bid


@@ 120,7 120,7 @@
        bidders-score (if (made-bid? total-tricks current-bid)
                        (+ bidders-score (-> total-tricks (tricks-value) (score-multiplier)))
                        (- bidders-score (-> current-bid (in :count)
			(score-multiplier) )))
                        (score-multiplier) )))
        opponent-team-keyword (-> players (non-bidding-team current-bid) (keyword))
        opponents-score (in info opponent-team-keyword)]
            

M init.janet => init.janet +8 -8
@@ 6,12 6,12 @@
  {:deck "52JJ"
   :player_count 4
   :stacks [{:id "trick"
	     :label "trick"
	     :orientation :up
	     :max-size 4
	     :alignment :stagger}]
             :label "trick"
             :orientation :up
             :max-size 4
             :alignment :stagger}]
   :info [{:id "north_south" :label "North/South" :value 0}
	  {:id "east_west" :label "East/West" :value 0}]})
          {:id "east_west" :label "East/West" :value 0}]})

## Init
(defn-


@@ 23,9 23,9 @@
  "Create an initial game state."
  [fst snd thd fth]
  {:players [(make-player fst "north_south")
	     (make-player snd "east_west")
	     (make-player thd "north_south")
	     (make-player fth "east_west")]
             (make-player snd "east_west")
             (make-player thd "north_south")
             (make-player fth "east_west")]
   :state {:phase "deal" :info {:north_south 0 :east_west 0}}})



M lit/events.lit => lit/events.lit +80 -80
@@ 46,12 46,12 @@ suit. For no-trumps bids, the declarer calls the direction.

--- Second Bids
(def- direction [[{:direction "up"} "Uptown"]
		[{:direction "down"} "Downtown"]])
                [{:direction "down"} "Downtown"]])

(def- suit [[{:suit "hearts"} "Hearts"]
	   [{:suit "spades"} "Spades"]
	   [{:suit "diamonds"} "Diamonds"]
	   [{:suit "clubs"} "Clubs"]])
           [{:suit "spades"} "Spades"]
           [{:suit "diamonds"} "Diamonds"]
           [{:suit "clubs"} "Clubs"]])

(def second-bids (array/concat @[] direction suit))



@@ 85,9 85,9 @@ Finally, if three out of four players pass, then the fourth player
  (case high-bid
    nil (array ;bids ["pass" "Pass"])
    (if-let [minimum-bid (if (no-trumps? high-bid)
		 	   {:count (inc (high-bid :count)) :direction "up"} 
			   {:count (high-bid :count) :suit "no_trumps"})
	     minimum-bid-ind (find-row-index minimum-bid bids)]
                           {:count (inc (high-bid :count)) :direction "up"} 
                           {:count (high-bid :count) :suit "no_trumps"})
             minimum-bid-ind (find-row-index minimum-bid bids)]
      (array/push (array/slice bids minimum-bid-ind) ["pass" "Pass"])
      @[["pass" "Pass"]])))



@@ 108,7 108,7 @@ Finally, if three out of four players pass, then the fourth player
  [bid &opt source]
  (default source bids)
  (if-let [ind (find-row-index (freeze bid) source)
	   row (source ind)]
           row (source ind)]
    (row 1)
    (error (string "Not found: " (string/format "%q" bid) " in " (string/format "%q" source)))))
@{Available Bids}


@@ 139,23 139,23 @@ represented with 1 up to Kings at 13.
(defn to-text [{:suit suit :rank rank}]
  (case suit
    "joker" (case rank
	      2 "Big Joker"
	      1 "Little Joker")
              2 "Big Joker"
              1 "Little Joker")
    (let [suits {"diamonds" "♦" "spades" "♠" "clubs" "♣" "hearts" "♥"}
	  ranks {1 "Ace"
		 2 "2"
		 3 "3"
		 4 "4"
		 5 "5"
		 6 "6"
		 7 "7"
		 8 "8"
		 9 "9"
		 10 "10"
		 11 "J"
		 12 "Q"
		 13 "K"}]
	(string (suits suit) (ranks rank)))))
          ranks {1 "Ace"
                 2 "2"
                 3 "3"
                 4 "4"
                 5 "5"
                 6 "6"
                 7 "7"
                 8 "8"
                 9 "9"
                 10 "10"
                 11 "J"
                 12 "Q"
                 13 "K"}]
        (string (suits suit) (ranks rank)))))
---

@s Determining What Can Be Played


@@ 181,18 181,18 @@ are members of their own suit.
  "Return any cards in stack that match the led suit, or are jokers."
  [led-suit stack]
  (let [with-jokers |(or (= led-suit ($0 :suit))
			 (= "joker" ($0 :suit)))]
                         (= "joker" ($0 :suit)))]
    (filter with-jokers stack)))

(defn of-suit-or-off
  "Return any cards in stack that match the led suit, otherwise return all cards."
  [led-suit current-bid stack]
  (let [on-suit (if (= led-suit (current-bid :suit))
		  # If the led suit is trumps, then look for all cards
		  # of that suit or jokers.
		  (of-suit-or-jokers led-suit stack)
		  # Otherwise, look just for cards of that suit.
		  (of-suit led-suit stack))]
                  # If the led suit is trumps, then look for all cards
                  # of that suit or jokers.
                  (of-suit-or-jokers led-suit stack)
                  # Otherwise, look just for cards of that suit.
                  (of-suit led-suit stack))]
    (if (> (length on-suit) 0) on-suit stack)))
---



@@ 213,9 213,9 @@ the play we can pull the winning player off of it.
  "Return any cards in stack that match the led suit, or are trumps."
  [led-suit trumps stack]
  (let [with-jokers-and-trumps
	|(or (= led-suit ($0 :suit))
	     (= trumps ($0 :suit))
	     (= "joker" ($0 :suit)))]
        |(or (= led-suit ($0 :suit))
             (= trumps ($0 :suit))
             (= "joker" ($0 :suit)))]
    (filter with-jokers-and-trumps stack)))

(defn high-card


@@ 223,14 223,14 @@ the play we can pull the winning player off of it.
  [stack led-suit bid]
  (let [f (make-compare-enable-fn bid)]
    (->> stack
	 # Get a version of the current-trick where
	 # each card has a `:compare` method that's
	 # aware of the current bid.
	 (map f)
	 (of-suit-or-trumps led-suit (bid :suit))
	 # Get the highest card according to each
	 # one's `:compare`.
	 (extreme compare>))))
         # Get a version of the current-trick where
         # each card has a `:compare` method that's
         # aware of the current bid.
         (map f)
         (of-suit-or-trumps led-suit (bid :suit))
         # Get the highest card according to each
         # one's `:compare`.
         (extreme compare>))))
---

@s Compare-Enabled Cards


@@ 263,48 263,48 @@ system, so feel free to skip it if it's not of particular interest.

(defn- uptown-card [trumps]
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] 1
		 @[_ "joker"] -1
		 @[trumps trumps] (uptown (self :rank) (other :rank))
		 @[trumps _] 1
		 @[_ trumps] -1 
		 @[_ _] (uptown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] 1
                 @[_ "joker"] -1
                 @[trumps trumps] (uptown (self :rank) (other :rank))
                 @[trumps _] 1
                 @[_ trumps] -1 
                 @[_ _] (uptown (self :rank) (other :rank))))})

(defn- downtown-card [trumps]
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] 1
		 @[_ "joker"] -1
		 @[trumps trumps] (downtown (self :rank) (other :rank))
		 @[trumps _] 1
		 @[_ trumps] -1 
		 @[_ _] (downtown (self :rank) (other :rank))) )})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] 1
                 @[_ "joker"] -1
                 @[trumps trumps] (downtown (self :rank) (other :rank))
                 @[trumps _] 1
                 @[_ trumps] -1 
                 @[_ _] (downtown (self :rank) (other :rank))) )})

(def- notrumps-card
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] -1
		 @[_ "joker"] 1
		 @[_ _] (uptown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] -1
                 @[_ "joker"] 1
                 @[_ _] (uptown (self :rank) (other :rank))))})

(def- notrumps-downtown-card
  @{:compare (fn [self other]
	       (match [(self :suit) (other :suit)]
		 @["joker" "joker"] (compare (self :rank) (other :rank))
		 @["joker" _] -1
		 @[_ "joker"] 1
		 @[_ _] (downtown (self :rank) (other :rank))))})
               (match [(self :suit) (other :suit)]
                 @["joker" "joker"] (compare (self :rank) (other :rank))
                 @["joker" _] -1
                 @[_ "joker"] 1
                 @[_ _] (downtown (self :rank) (other :rank))))})

(defn- make-compare-enable-fn [current-bid]
  (let [proto (match [(current-bid :suit) (current-bid :direction)]
		@["notrumps" "up"] notrumps-card
		@["notrumps" "down"] notrumps-downtown-card
		@[trumps "up"] (uptown-card trumps)
		@[trumps "down"] (downtown-card trumps))]
                @["notrumps" "up"] notrumps-card
                @["notrumps" "down"] notrumps-downtown-card
                @[trumps "up"] (uptown-card trumps)
                @[trumps "down"] (downtown-card trumps))]
    (fn [card]
      (table/setproto card proto))))
---


@@ 336,21 336,21 @@ In Janet we can do this using fibers.
  
  (var ind (find-index |(and (= ($0 :id) id)) players))
  (let [f (fiber/new (fn []
		       (while true
			 (do
			   (set ind (mod (inc ind) (length players)))
			   (yield ind)))))]
                       (while true
                         (do
                           (set ind (mod (inc ind) (length players)))
                           (yield ind)))))]
    (var found nil)
    (while (not found)
      (let [new-ind (resume f)
	    new-id ((players new-ind) :id)]
	(if (or (nil? out-of) (in out-of (keyword new-id)))
	  (set found new-id))))
            new-id ((players new-ind) :id)]
        (if (or (nil? out-of) (in out-of (keyword new-id)))
          (set found new-id))))
    found))

(defn of-team [players team] (->> players
				  (filter |(= ($0 :team) team))
				  (map |($0 :id))))
                                  (filter |(= ($0 :team) team))
                                  (map |($0 :id))))
---

# Appendix IIII

M main.janet => main.janet +5 -5
@@ 17,8 17,8 @@
## Init Handler
(defn init [request]
  (let [players (get-in request [:query-string :players])
	[p1 p2 p3 p4] (string/split "," players)
	resp (init/init p1 p2 p3 p4)]
        [p1 p2 p3 p4] (string/split "," players)
        resp (init/init p1 p2 p3 p4)]
  
    (application/json resp)))



@@ 30,11 30,11 @@

(defn next [request]
  (def handler (fiber/new (fn [req]
			    (whist/next (params req))) :e))
                            (whist/next (params req))) :e))
  (match (resume handler request)
    {:error error-msg} @{:status 422
			 :body (json/encode {:error error-msg})
			 :headers @{"Content-Type" "application/json"}}
                         :body (json/encode {:error error-msg})
                         :headers @{"Content-Type" "application/json"}}
    [state events]
    (application/json {:state state :events events})))


M players.janet => players.janet +9 -9
@@ 4,19 4,19 @@
  
  (var ind (find-index |(and (= ($0 :id) id)) players))
  (let [f (fiber/new (fn []
		       (while true
			 (do
			   (set ind (mod (inc ind) (length players)))
			   (yield ind)))))]
                       (while true
                         (do
                           (set ind (mod (inc ind) (length players)))
                           (yield ind)))))]
    (var found nil)
    (while (not found)
      (let [new-ind (resume f)
	    new-id ((players new-ind) :id)]
	(if (or (nil? out-of) (in out-of (keyword new-id)))
	  (set found new-id))))
            new-id ((players new-ind) :id)]
        (if (or (nil? out-of) (in out-of (keyword new-id)))
          (set found new-id))))
    found))

(defn of-team [players team] (->> players
				  (filter |(= ($0 :team) team))
				  (map |($0 :id))))
                                  (filter |(= ($0 :team) team))
                                  (map |($0 :id))))


M whist.lit => whist.lit +21 -44
@@ 21,7 21,8 @@ Tamerlane's API contract.

This code is written using the [Literate][literate] program, which takes a
literate source document and renders the document you are reading, as
well as the source files needed to compile the program.
well as the source files needed to compile the program. The source
files are available at [sourcehut](https://git.sr.ht/~subsetpark/whist).

[literate]: http://literate.zbyedidia.webfactional.com/



@@ 75,53 76,29 @@ The rules of the game, therefore, are realized in the **next state** step.

--- Sequence Diagram
+---------+             +---------+              +-------------+

| Player  |             | Server  |              | RulesEngine |

+---------+             +---------+              +-------------+

     |                       |                          |

     | start game            |                          |

     |---------------------->|                          |

     |                       |                          |

     |                       | get initial state        |

     |                       |------------------------->|

     |                       |                          |

     | player action         |                          |

     |---------------------->|                          |

     |                       |                          |

     |                       | current state            |

     |                       |------------------------->|

     |                       |                          | ----------------------\

     |                       |                          |-| (whist/next params) |

     |                       |                          | |---------------------|

     |                       |                          |

     |                       |               next state |

     |                       |<-------------------------|

     |                       |                          |

     |      prompt for input |                          |

     |<----------------------|                          |

     |                       |                          |
---



@@ 1012,9 989,9 @@ those players' tricks taken, and add them together.
  [players bid info]
  (let [bidding-team (bidding-team players bid)] 
    (->> (players/of-team players bidding-team)
	 (map |(keyword $0 "_tricks"))
	 (map |(info $0))
	 (sum))))
         (map |(keyword $0 "_tricks"))
         (map |(info $0))
         (sum))))
---

@s Getting the Score Multiplier


@@ 1083,7 1060,7 @@ info in order to populate the new state with it.
        bidders-score (if (made-bid? total-tricks current-bid)
                        (+ bidders-score (-> total-tricks (tricks-value) (score-multiplier)))
                        (- bidders-score (-> current-bid (in :count)
			(score-multiplier) )))
                        (score-multiplier) )))
        opponent-team-keyword (-> players (non-bidding-team current-bid) (keyword))
        opponents-score (in info opponent-team-keyword)]
            


@@ 1125,9 1102,9 @@ player ID to their final score.
(defn end-game
  [players team1 score1 team2 score2]
  (let [players1 (players/of-team players (string team1))
	players2 (players/of-team players (string team2))]
        players2 (players/of-team players (string team2))]
    {:event "end_game" :scores (zipcoll (array/concat players1 players2)
					[score1 score1 score2 score2])}))
                                        [score1 score1 score2 score2])}))
---

@s 


@@ 1181,12 1158,12 @@ particular, that includes:
  {:deck "52JJ"
   :player_count 4
   :stacks [{:id "trick"
	     :label "trick"
	     :orientation :up
	     :max-size 4
	     :alignment :stagger}]
             :label "trick"
             :orientation :up
             :max-size 4
             :alignment :stagger}]
   :info [{:id "north_south" :label "North/South" :value 0}
	  {:id "east_west" :label "East/West" :value 0}]})
          {:id "east_west" :label "East/West" :value 0}]})
---

@s /init


@@ 1206,9 1183,9 @@ player IDs in the game and returns an object with `players` and
  "Create an initial game state."
  [fst snd thd fth]
  {:players [(make-player fst "north_south")
	     (make-player snd "east_west")
	     (make-player thd "north_south")
	     (make-player fth "east_west")]
             (make-player snd "east_west")
             (make-player thd "north_south")
             (make-player fth "east_west")]
   :state {:phase "deal" :info {:north_south 0 :east_west 0}}})
---



@@ 1282,8 1259,8 @@ We can handle it simply by splitting on the commas.
--- Init Handler
(defn init [request]
  (let [players (get-in request [:query-string :players])
	[p1 p2 p3 p4] (string/split "," players)
	resp (init/init p1 p2 p3 p4)]
        [p1 p2 p3 p4] (string/split "," players)
        resp (init/init p1 p2 p3 p4)]
  
    (application/json resp)))
---


@@ 1311,11 1288,11 @@ the response that the Tamerlane server expects.

(defn next [request]
  (def handler (fiber/new (fn [req]
			    (whist/next (params req))) :e))
                            (whist/next (params req))) :e))
  (match (resume handler request)
    {:error error-msg} @{:status 422
			 :body (json/encode {:error error-msg})
			 :headers @{"Content-Type" "application/json"}}
                         :body (json/encode {:error error-msg})
                         :headers @{"Content-Type" "application/json"}}
    [state events]
    (application/json {:state state :events events})))
---