~subsetpark/whist

ref: 18a5446a58efa8d6444719443d57c93ffa5bcaa9 whist/game/bid.janet -rw-r--r-- 3.4 KiB
18a5446a — Zach Smith Incorporate lit through discard 7 months ago
                                                                                
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
# game/bid.janet
(import players)
(import bids)
(import events)

# New Meta
(defn- new-meta
  [{:meta meta} {:value last-bid :player last-bidder}]
  (let [{:bid previous-high-bid :player previous-high-bidder} (meta :high_bid)
        # Record the high bid (whether it's a new bid or the existing high bid).
        [high-bid high-bidder] (case last-bid
                                 "pass" [previous-high-bid previous-high-bidder]
                                 [last-bid last-bidder])]
    @{:high_bid @{:player high-bidder :bid high-bid}}))

# Initial Bidding Events
(defn- initial-events
  [{:meta {:high_bid {:bid previous-high-bid :player previous-high-bidder}}}
   {:value last-bid :player last-bidder}
   current-high-bid]
  (case last-bid
    "pass" @[(events/add-decoration last-bidder "bid_action" "passed")]
    (array/concat 
     (case previous-high-bidder
       nil @[]
       @[(events/clear-decoration previous-high-bidder "bid_action")])
     (events/add-decoration last-bidder "bid_action" "declarer")
     (events/add-decoration last-bidder "bid" (bids/to-text current-high-bid)))))

# Update Not Passed
(defn- update-not-passed
  [{:meta {:not_passed not-passed}} {:value last-bid :player last-bidder}]
  (case last-bid
    # Handle a new pass. Mark the player as passed by removing them from the set.
    "pass" (put not-passed (keyword last-bidder) nil))
    not-passed)

# Main Bid Function
(defn bid-phase
  ```
  The players bid in an auction to name trump. 

  The highest bid is a number of tricks to take above six with a named
  suit or no-trumps.
  
  Requires:
  - `high_bid`
  - `not_passed`: The players that haven't yet passed.
  ```
  [state players action]
  (if (= action :null) (error {:error "action required"}))
  # Handle the Bid Action
  (let  [new-meta (new-meta state action)
         {:high_bid {:player high-bidder :bid high-bid}} new-meta
         events (initial-events state action high-bid)
         not-passed (update-not-passed state action)]
    # The set of players still in the auction is now up to date. We'll
    # use it to determine whether the action is over.
    (if (and (not (nil? high-bidder)) (= 1 (length not-passed)))
      # If someone has bid and all but one have passed, the auction is over.
      # End the Auction
      [(merge state {:meta new-meta
                     # State: Bid -> Discard
                     :phase "discard"})
       # Bidder selects suit in a trumps bid or direction in a no-trumps bid.
       (array/push events (events/pick1 "bid" high-bidder (bids/second-bid high-bid)))]

      # Otherwise, continue the bidding.
      # Continue the Auction
      (let [{:player last-bidder} action
            next-bidder (players/next-player last-bidder players not-passed)]
        (array/push events (events/add-decoration next-bidder "bid_action" "bidding"))
        # The auction isn't over; include the set of players still bidding in the metadata.
        [(merge state {:meta (put new-meta :not_passed not-passed)
                       # State: Bid -> Bid
                       :phase "bid"})
         (if (= 1 (length not-passed))
           # If no one has bid and all but one have passed, the dealer has to bid.
           (array/push events (events/pick1 "bid" next-bidder (bids/force-bid)))
           # Otherwise, move to the next bidder.
           (array/push events (events/pick1 "bid" next-bidder
                                             (bids/available-bids high-bid))))])

  ))

)