0f94eea4ffffb5b5c9fd9bc4102a6f0a9c8598e1
[sdk] / samples / games / cards / poker / poker.ec
1 /****************************************************************************
2    POKER Game Interface
3
4    Copyright (c) 2001 Jerome Jacovella-St-Louis
5    All Rights Reserved.
6
7    poker.ec - Poker Main Window
8 ****************************************************************************/
9 import "ecere"
10 import "player.ec"
11 import "widow.ec"
12 import "bet.ec"
13
14 static String cardsNames[] =
15 {
16    ":ac.png", ":ad.png", ":ah.png", ":as.png",    ":2c.png", ":2d.png", ":2h.png", ":2s.png",    ":3c.png", ":3d.png", ":3h.png", ":3s.png",
17    ":4c.png", ":4d.png", ":4h.png", ":4s.png",    ":5c.png", ":5d.png", ":5h.png", ":5s.png",    ":6c.png", ":6d.png", ":6h.png", ":6s.png",
18    ":7c.png", ":7d.png", ":7h.png", ":7s.png",    ":8c.png", ":8d.png", ":8h.png", ":8s.png",    ":9c.png", ":9d.png", ":9h.png", ":9s.png",
19    ":10c.png", ":10d.png", ":10h.png", ":10s.png",":jc.png", ":jd.png", ":jh.png", ":js.png",    ":qc.png", ":qd.png", ":qh.png", ":qs.png",
20    ":kc.png", ":kd.png", ":kh.png", ":ks.png",    ":rb.png", ":rr.png"
21 };
22
23 static define CARD_WIDTH = 111;
24 static define CARD_HEIGHT = 150;
25
26 enum PokerHand { nothing, onePair, twoPair, threeOfAKind, straight, flush, fullHouse, fourOfAKind, straightFlush, royalFlush };
27
28 /*
29 ROYAL FLUSH        0.0002 %
30 STRAIGHT FLUSH     0.0012 %
31 FOUR OF A KIND     0.0240 %
32 FULL HOUSE         0.1441 %
33 FLUSH              0.1967 %
34 STRAIGHT           0.3532 %
35 THREE OF A KIND    2.1128 %
36 TWO PAIR           4.7539 %
37 ONE PAIR          42.2569 %
38 NOTHING           50.1570 %
39 */
40
41 enum Facing { faceDown, faceUp };
42
43 static int lowHand[5] = { 4*0 + 1, 4*1, 4*2, 4*3, 4*5 };
44 static Player players[6];
45 static int deck[52], deckIndex;
46
47 static int numPlayers;
48 static int numPlayersLeft;
49 static char playerNames[6][20] =
50 {
51    "Jerome",
52    "Adam",
53    "Jason",
54    "Bruce",
55    "Pete",
56    "Daniel"
57 };
58 static Pointf positions[5][6] =
59 {
60    {{ .50f, .82f }, { .50f, .18f }},
61    {{ .50f, .82f }, { .18f, .18f },  { .82f, .18f}},
62    {{ .50f, .82f }, { .18f, .50f },  { .50f, .18f},  { .82f, .50f}},
63    {{ .50f, .82f }, { .18f, .50f },  { .50f, .18f},  { .82f, .50f}, { .82f, .50f}},
64    {{ .25f, .82f }, { .18f, .50f },  { .25f, .18f},  { .75f, .18f}, { .82f, .50f}, { .75f, .82f}}
65 };
66
67 // --- Data Used by Child Window Classes ---
68 int currentBet;
69 int potMoney;
70 int widowNum = 0;
71 int widow[52];
72 bool gameOver = true;
73
74 define ANTE = 1;
75
76 class Poker : Window
77 {
78    background = teal;
79    hasMinimize = true, hasMaximize = true, hasClose = true;
80    borderStyle = sizable;
81    text = "ECERE Poker";
82    size = Size { 986, 740 };
83
84    Bitmap bitmapCards[52];
85    Bitmap cardBack {};
86
87    Widow widowWindow { this, opacity = 0, text = "Widow", borderStyle = sizable, anchor = Anchor { left = 0.375, top = 0.34, right = 0.375, bottom = 0.34 } };
88
89    void DrawCard(Surface surface, int x, int y, int card)
90    {
91       Bitmap bitmap;
92       if(card != -1)
93          bitmap = bitmapCards[card];
94       else
95          bitmap = cardBack;
96       surface.Blit(bitmap, x, y, 0,0, bitmap.width,bitmap.height);
97    }
98
99    // --- Poker Game Flow ---
100
101    void CreatePlayers(int num)
102    {
103       int c;
104
105       numPlayers = num;
106       for (c = 0; c<numPlayers; c++)
107       {
108          char string[256];
109          Pointf pos = positions[numPlayers - 2][c];
110
111          sprintf(string, "%s (%d)", playerNames[c], c + 1);
112          players[c] = Player { this, opacity = 0, text = string, anchor = Anchor { left = pos.x - 0.175, top = pos.y - 0.16, right = 1-(pos.x + 0.175), bottom = 1-(pos.y + 0.16) } };
113          players[c].Create();
114       }
115       players[0].human = true;
116    }
117
118    void Shuffle()
119    {
120       int c;
121
122       POKER_ShuffleDeck(deck);
123       deckIndex = 0;
124       numPlayersLeft = numPlayers;
125       for(c = 0; c<numPlayers; c++)
126       {
127          players[c].numDown = players[c].numUp = 0;
128          players[c].folded = false;
129          players[c].winner = false;
130       }
131       widowNum = 0;
132       gameOver = false;
133    }
134
135    void Deal(Facing up, int howMany)
136    {
137       int c;
138       int p;
139
140       for(c = 0; c<howMany; c++)
141          for(p = 0; p<numPlayers; p++)
142          {
143             Player player = players[p];
144             if(!player.folded)
145             {
146                if(up)
147                {
148                   player.up[player.numUp++] = deck[deckIndex++];
149                   POKER_SortCards(player.up, player.numUp);
150                }
151                else
152                {
153                   player.down[player.numDown++] = deck[deckIndex++];
154                   POKER_SortCards(player.down, player.numDown);
155                }
156             }
157          }
158       Update(null);
159    }
160
161    void DealWidow(int howMany)
162    {
163       int c;
164       for(c = 0; c<howMany; c++)
165          widow[widowNum++] = deck[deckIndex++];
166       POKER_SortCards(widow, widowNum);
167       Update(null);
168    }
169
170    void Ante()
171    {
172       int c;
173       for(c = 0; c<numPlayers; c++)
174       {
175          if(players[c].money >= ANTE)
176          {
177             players[c].money -= ANTE;
178             potMoney += ANTE;
179          }
180          else
181             players[c].folded = true;
182       }
183       Update(null);
184    }
185
186    void BettingRound(int firstBet)
187    {
188       int p;
189       int numBets = 0;
190
191       if(!created) return;
192
193       if(numPlayersLeft >= 2)
194       {
195          currentBet = 0;
196          for(p = 0; p<numPlayers; p++)
197             players[p].thisBet = 0;
198
199          for(p = firstBet;; p++)
200          {
201             Player player;
202             char string[64];
203             Bet bet;
204
205             if(p == numPlayers) p = 0;
206             player = players[p];
207             if(player.folded) continue;
208
209             if(currentBet && player.thisBet == currentBet) break;
210
211             sprintf(string, "Your bet, %s?", playerNames[p]);
212             bet = Bet { parent = this, thisBet = &player.thisBet, text = string };
213             bet.Create();
214             eInstance_IncRef(bet);
215             while(bet.created)
216             {
217                app.UpdateDisplay();
218                if(!app.ProcessInput(true))
219                   app.Wait();
220             }
221             eInstance_DecRef(bet);
222
223             if(!created) return;
224
225             //player.thisBet = 0;
226
227             if(player.thisBet < currentBet)
228             {
229                player.folded = true;
230                numPlayersLeft--;
231                if(numPlayersLeft < 2)
232                   break;
233                numBets = 0;
234             }
235             else if(player.thisBet > currentBet)
236             {
237                currentBet = player.thisBet;
238                numBets = 0;
239             }
240             else
241                numBets++;
242             potMoney += player.thisBet;
243             player.money -= player.thisBet;
244             Update(null);
245
246             if(!currentBet && numBets >= numPlayersLeft)
247                break;
248          }
249       }
250    }
251
252    void WinMoney(int numHand, int numWidow)
253    {
254       int p;
255       int numWinners = 0;
256       int bestHand[5] = { lowHand[0], lowHand[1], lowHand[2], lowHand[3], lowHand[4] };
257
258       if(!created) return;
259
260       for(p=0; p<numPlayers; p++)
261       {
262          int cards[16];
263          int c;
264          Player player = players[p];
265
266          if(player.folded) continue;
267
268          for(c = 0;; c++)
269          {
270             if(c < player.numDown)
271                cards[c] = player.down[c];
272             else if(c - player.numDown < player.numUp)
273                cards[c] = player.up[c - player.numDown];
274             else
275                break;
276          }
277          CopyBytesBy4(player.bestHand, lowHand, 5);
278          POKER_BestHand(cards, widow, c, widowNum, numHand, numWidow, player.bestHand);
279          player.handType = POKER_HandType(player.bestHand);
280       }
281
282       for(p=0; p<numPlayers; p++)
283       {
284          int c;
285          Player player = players[p];
286          if(player.folded) continue;
287
288          switch(POKER_Compare(bestHand, player.bestHand))
289          {
290             case 0:
291                numWinners ++;
292                player.winner = true;
293                break;
294             case 1:
295                for(c=0; c<numPlayers; c++)
296                   players[c].winner = false;
297                numWinners = 1;
298                CopyBytesBy4(bestHand, player.bestHand, 5);
299                player.winner = true;
300                break;
301          }
302       }
303       for(p=0; p<numPlayers; p++)
304       {
305          Player player = players[p];
306          if(player.folded) continue;
307          if(POKER_Compare(player.bestHand, bestHand) == 0)
308             player.money += potMoney / numWinners;
309       }
310       if(numWinners)
311       {
312          potMoney -= (potMoney / numWinners) * numWinners;
313       }
314       gameOver = true;
315       Update(null);
316    }
317
318    // --- Poker Games Definitions ---
319
320    /*
321    TEXAS HOLDEM - The most popular poker game in Blackhawk. A variation of 7-Card
322    Stud where every player gets dealt 2 cards face down and there is a community
323    board of 5 cards. Players Ise the 2 cards in their hand plus the 5 community
324    cards to make the best possible 5 card hand. A dealers button moves around the
325    table each hand. The player to the left of the dealer button is dealt the
326    first card. Also the person to the left of the button has to post a blind.
327    There is a betting round after the players receive their first 2 cards. Then the
328    dealer places 3 cards on the board (the flop) and there is a betting round. Then
329    the dealer places another card on the board (the turn) and there is another
330    betting round. Then the dealer places the final card (the river) on the board
331    and there is a final betting round. Games may have 1 blind or 2 blinds. Games
332    vary from $2-5 betting to straight $5 betting.
333    */
334    void TexasHoldem()
335    {
336       Shuffle();
337       Ante();
338       Deal(faceDown, 2);
339       BettingRound(0);
340       DealWidow(3);
341       BettingRound(0);
342       DealWidow(1);
343       BettingRound(0);
344       DealWidow(1);
345       BettingRound(0);
346       WinMoney(2, 5);
347    }
348
349    /*
350    OMAHA - A games similar to Texas Holdem except the players are dealt 4 cards
351    face down. There is a board of 5 community cards and you must Ise 2 cards out
352    of your hand to make the best possible hand. The game may be played straight
353    high or high/lowHand. There is a dealer button that moves around the table each
354    hand and the player that has the dealers button may choose to play the game
355    straight high or high/lowHand. The player to the left of the dealer button has
356    to post a small blind of $1 and the person to his/her left has to post the
357    large blind of $2. To qualify for a lowHand hand, the player must have 5 cards
358    that are 8 or lowHander. There is a betting round after the players receive their
359    4 cards. Then the dealer places 3 cards on the board (the flop). After the
360    betting round, the dealer places another card on the board (the turn) and there
361    is another betting round. Then the dealer places the last card (the river) on
362    the board and there is a final betting round. The betting limits are Isually
363    $2-$5.
364    */
365    void OmahaHoldem()
366    {
367       Shuffle();
368       Ante();
369       Deal(faceDown, 4);
370       BettingRound(0);
371       DealWidow(3);
372       BettingRound(0);
373       DealWidow(1);
374       BettingRound(0);
375       DealWidow(1);
376       BettingRound(0);
377       WinMoney(2, 3);
378    }
379
380    void SevenCardStud()
381    {
382       Shuffle();
383       Ante();
384       Deal(faceDown, 2);
385       Deal(faceUp, 1);
386       BettingRound(0);
387       Deal(faceUp, 1);
388       BettingRound(0);
389       Deal(faceUp, 1);
390       BettingRound(0);
391       Deal(faceUp, 1);
392       BettingRound(0);
393       Deal(faceDown, 1);
394       BettingRound(0);
395       WinMoney(5, 0);
396    }
397
398    // --- Poker Window Class ---
399    bool OnLoadGraphics()
400    {
401       int i;
402       cardBack.LoadT(":back.png",null,displaySystem);
403       for(i = 0; i < 52; i++)
404       {
405          bitmapCards[i] = Bitmap {};
406          bitmapCards[i].LoadT(cardsNames[i], null, displaySystem);
407       }
408       return true;
409    }
410
411    void OnUnloadGraphics()
412    {
413       int i;
414       for(i=0;i<52;i++)
415          delete bitmapCards[i];
416       cardBack.Free();
417    }
418
419    bool OnPostCreate()
420    {
421       potMoney = 0;
422       CreatePlayers(6);
423       return true;
424    }
425
426    bool OnClose(bool parentClosing)
427    {
428       if(MessageBox { type = yesNo, text = "Exit", contents = "Quit?" }.Modal() == yes)
429          return true;
430       return false;
431    }
432
433    bool OnKeyHit(Key key, unichar ch)
434    {
435       if(!gameOver) return false;
436       switch(key)
437       {
438          case f1: TexasHoldem(); break;
439          case f2: OmahaHoldem(); break;
440          case f3: SevenCardStud();   break;
441       }
442       return true;
443    }
444 }
445
446 PokerApp app;
447
448 class PokerApp : GuiApplication
449 {
450    Poker { };
451    appName = "Poker Master";
452
453    bool Init()
454    {
455       int c;
456       // Initialize Card Deck
457       RandomSeed((int)(GetTime() * 1000));
458       for(c = 0; c<52; c++)
459          deck[c] = c;
460
461       app = this;
462       return true;
463    }
464 }