├── README.md
└── texasholdem
├── doc
├── Client_server.txt
├── DESIGN.txt
├── HISTORY.txt
├── LICENSE.txt
├── README.txt
├── TODO.txt
└── Winnings.txt
├── launchers
├── texasholdem (GUI).launch
└── texasholdem (JUnit).launch
├── pom.xml
└── src
├── main
├── java
│ └── org
│ │ └── ozsoft
│ │ └── texasholdem
│ │ ├── Card.java
│ │ ├── Client.java
│ │ ├── Deck.java
│ │ ├── Hand.java
│ │ ├── HandEvaluator.java
│ │ ├── HandValue.java
│ │ ├── HandValueType.java
│ │ ├── Player.java
│ │ ├── Pot.java
│ │ ├── Table.java
│ │ ├── TableType.java
│ │ ├── actions
│ │ ├── Action.java
│ │ ├── AllInAction.java
│ │ ├── BetAction.java
│ │ ├── BigBlindAction.java
│ │ ├── CallAction.java
│ │ ├── CheckAction.java
│ │ ├── ContinueAction.java
│ │ ├── FoldAction.java
│ │ ├── RaiseAction.java
│ │ └── SmallBlindAction.java
│ │ ├── bots
│ │ ├── BasicBot.java
│ │ ├── Bot.java
│ │ └── DummyBot.java
│ │ ├── gui
│ │ ├── AmountPanel.java
│ │ ├── BoardPanel.java
│ │ ├── ControlPanel.java
│ │ ├── Main.java
│ │ ├── PlayerPanel.java
│ │ ├── ResourceManager.java
│ │ └── UIConstants.java
│ │ └── util
│ │ └── PokerUtils.java
└── resources
│ └── images
│ ├── button_absent.png
│ ├── button_present.png
│ ├── card_00.png
│ ├── card_01.png
│ ├── card_02.png
│ ├── card_03.png
│ ├── card_04.png
│ ├── card_05.png
│ ├── card_06.png
│ ├── card_07.png
│ ├── card_08.png
│ ├── card_09.png
│ ├── card_10.png
│ ├── card_11.png
│ ├── card_12.png
│ ├── card_13.png
│ ├── card_14.png
│ ├── card_15.png
│ ├── card_16.png
│ ├── card_17.png
│ ├── card_18.png
│ ├── card_19.png
│ ├── card_20.png
│ ├── card_21.png
│ ├── card_22.png
│ ├── card_23.png
│ ├── card_24.png
│ ├── card_25.png
│ ├── card_26.png
│ ├── card_27.png
│ ├── card_28.png
│ ├── card_29.png
│ ├── card_30.png
│ ├── card_31.png
│ ├── card_32.png
│ ├── card_33.png
│ ├── card_34.png
│ ├── card_35.png
│ ├── card_36.png
│ ├── card_37.png
│ ├── card_38.png
│ ├── card_39.png
│ ├── card_40.png
│ ├── card_41.png
│ ├── card_42.png
│ ├── card_43.png
│ ├── card_44.png
│ ├── card_45.png
│ ├── card_46.png
│ ├── card_47.png
│ ├── card_48.png
│ ├── card_49.png
│ ├── card_50.png
│ ├── card_51.png
│ ├── card_back.png
│ ├── card_joker_black.png
│ ├── card_joker_red.png
│ └── card_placeholder.png
└── test
└── java
└── org
└── ozsoft
└── texasholdem
├── BasicBotTest.java
├── CardTest.java
├── HandEvaluatorTest.java
├── HandTest.java
└── util
└── PokerUtilsTest.java
/README.md:
--------------------------------------------------------------------------------
1 | # Texas Hold'em poker (texasholdem-java)
2 |
3 | ## Introduction
4 |
5 | This project has been created as a platform to experiment with a Texas Hold'em poker game in Java.
6 |
7 | Its primary goal is to offer a clean, open source Texas Hold'em poker engine in Java. The game engine strives to follow the famous Robert's Rules of Poker as closely as possible. In order to test the game engine, the project also offers a Swing GUI and bots.
8 |
9 | This project is provided under the Apache License 2.0.
10 |
11 | ## Status
12 |
13 | The current implementation support the Fixed-Limit and No-Limit variants of the game with a Swing GUI, with the human player playing against 3 bots.
14 |
15 | ## Building and running
16 |
17 | This Java project has a Maven structure. Build the project with "mvn clean install" and find the binary in the 'target' directory. Run the game with "java -jar texasholdem.jar".
18 |
19 | ## Contact
20 |
21 | If you like this project or have any questions please mail me (oscar.stigter@gmail.com). For bug reports or feature requests please create an issue using this GitHub project site Your input is highly appreciated!
22 |
23 | ## Disclaimer
24 |
25 | This project is created only because of my love for Java and my interest in the game of poker. As a Christian, I strongly oppose to any form of gambling, as I believe it eventually leads to a path of greed, destruction and suffering.
26 |
--------------------------------------------------------------------------------
/texasholdem/doc/Client_server.txt:
--------------------------------------------------------------------------------
1 | Client/Server design
2 | ====================
3 |
4 |
5 | Request table info
6 | -----------------
7 |
8 | Request (client):
9 |
10 |
11 |
12 |
13 |
14 | Response (server):
15 |
16 |
17 |
18 | 2
19 |
20 |
21 | Joe
22 | 99
23 | 1
24 |
25 |
26 |
27 |
28 |
29 | Mike
30 | 98
31 | 2
32 |
33 |
34 |
35 |
36 |
37 | Eddie
38 | 98
39 | 2
40 |
41 |
42 |
43 |
44 | 7h
45 | As
46 | Qd
47 |
48 | Eddie
49 | Eddie
50 |
51 |
52 |
53 |
54 | Table update
55 | ------------
56 |
57 | Message (client):
58 |
59 |
60 |
61 | Joe
62 |
63 |
64 |
65 |
66 |
67 | Message types
68 | -------------
69 |
70 | requestTableInfo
71 | tableInfo
72 | tableUpdate
73 | join
74 | leave
75 | requestAction
76 | playerAction
77 |
78 |
79 | Actions
80 | -------
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/texasholdem/doc/DESIGN.txt:
--------------------------------------------------------------------------------
1 | Design
2 | ======
3 |
4 | Fixed Limit Texas Hold'em poker
5 |
6 | Big blind: Any even size
7 | Small blind: Half of big blind
8 |
9 | Fixed bets/raises:
10 | - Pre-Flop and Flop: 1x big blind
11 | - Turn/River: 2x big blind
12 |
13 | Phases:
14 | - Pre-Flop: Hole cards (2 per player), betting round
15 | - Flop: 3 cards on the board, betting round
16 | - Turn: 1 extra card on the board, betting round
17 | - River: 1 extra card on the board, betting round
18 | - Showdown
19 |
20 | Actions:
21 | - bet == 0: Check, Bet, Fold
22 | - bet > 0: Call, Raise, Fold
23 | - all-in: Call
24 |
25 | Bet/Raise: All other players must act again (Call, Raise, Fold), bet/raised player has the final option (Call, Raise, Fold)
26 |
27 | Max. raises per betting round: 4, except when only 2 players left (Heads-up mode)
28 |
29 | All-in:
30 | - If a player uses all of his remaining cash to call (partially or full), he goes all-in.
31 | - All-in player must stay in hand until showdown, without acting.
32 | - At the showdown, each active player is processed, in order of the best hand to worst:
33 | if he is NOT all-in, he wins the pot (done), otherwise (all-in) he wins his pot share (next player).
34 |
35 |
36 | Hand phases
37 | -----------
38 |
39 | - Rotate the dealer position
40 | - Post the Small Blind and Big Blind
41 | - Deal the 2 Hole cards per player
42 | - Pre-Flop betting round
43 | - Deal the 3 Flop cards on the board
44 | - Flop betting round
45 | - Deal the Turn card on the board
46 | - Turn betting round
47 | - Deal the River card on the board
48 | - River betting round
49 | - Showdown
50 |
51 |
52 | Action types
53 | ------------
54 |
55 | enum Action {
56 | CHECK
57 | CALL
58 | BET
59 | RAISE
60 | FOLD
61 | }
62 |
63 |
64 | Classes
65 | -------
66 |
67 | class Deck {
68 | -cards : Card[]
69 | +shuffle()
70 | +deal() : Card
71 | +deal(int noOfCards) : Card[]
72 | +deal(int rank, int suit) : Card
73 | +reset()
74 | }
75 |
76 | class Card {
77 | -rank : int
78 | -suit : int
79 | +Card(int rank, int suit)
80 | +Card(String s)
81 | +getRank() : int
82 | +getSuit() : int
83 | }
84 |
85 | class Hand {
86 | -cards : Card[]
87 | -noOfCards : int
88 | +Hand()
89 | +getNoOfCards() : int
90 | +addCard(card : Card)
91 | +addCards(cards : Card[])
92 | +addCards(cards : Collection)
93 | +clear()
94 | }
95 |
96 | class Server {
97 | -tables : List
98 | +Server(noOfTables : int)
99 | +start()
100 | +stop()
101 | +createAccount(String username, String password)
102 | +login(String username, String password)
103 | +logout(String username)
104 | +buyChips(String username, int amount)
105 | +joinTable(String username, int tableNumber)
106 | +leaveTable(String username)
107 | }
108 |
109 | class Account {
110 | -username : String
111 | -password : String
112 | -chips : int
113 | }
114 |
115 | class Table {
116 | -bigBlind : int
117 | -players : Map
118 | -activePlayers : Map
119 | -deck : Deck
120 | -board : List
121 | -bet : int
122 | -pot : int
123 | +Table(bigBlind : int)
124 | +start()
125 | +stop()
126 | +addPlayer(Player player)
127 | +removePlayer(Player player)
128 | }
129 |
130 | class Player {
131 | -name : String
132 | -position : int
133 | -cash : int
134 | -client : Client
135 | -isDealer : boolean
136 | -isActor : boolean
137 | -cards : Card[] // Confidential, only set when appropriate!
138 | -bet : int
139 | -action : Action
140 | -raises : int
141 | +Player(String name, int cash, Client client)
142 | }
143 |
144 | interface Client {
145 | +joinedTable(int tableNumber, int bigBlind, List players, int position)
146 | +leftTable()
147 | +playerJoined(Player player)
148 | +playerLeft(Player player)
149 | +dealerRotated(Player dealer)
150 | +actorRotated(Player actor)
151 | +dealPocketCards(Card[] cards)
152 | +boardUpdated(List cards)
153 | +playerActed(Player player)
154 | +act(Set allowedActions) : Action
155 | }
156 |
157 |
158 | Bot algorithm
159 | -------------
160 |
161 | Factors:
162 | - hole cards (Chen formula)
163 | - community cards
164 | - potential duplicates (more than One Pair)
165 | - potential straight
166 | - potential flush
167 | - number of players
168 | - table position
169 | - bet
170 | - pot
171 | - cash
172 | - chance to win
173 | - actions from earlier table positions
174 | - bluffing
175 | - opponent behavior
176 | - bet
177 | - cash
178 | - tightness (loose/tight)
179 | - aggression (passive/aggressive)
180 | - bluffing
181 |
--------------------------------------------------------------------------------
/texasholdem/doc/HISTORY.txt:
--------------------------------------------------------------------------------
1 | HISTORY
2 | =======
3 |
4 | Release Date Description
5 | ---------------------------------------------------------------------------------------------------
6 |
7 | 0.6a ? - Bugfixes by Ivo Wijnker
8 | - Updated to Java 7
9 |
10 | 0.5a 16-May-2013 - Added No-Limit game engine
11 | - Updated GUI with No-Limit game engine
12 | - Implemented basic bot AI
13 | - General code cleanup
14 | - Added README.txt file
15 |
16 | 0.4a 17-Apr-2013 - Implemented pot splitting
17 | - Implemented all-in and broke players
18 | - Finished GUI game engine (Fixed Limit poker)
19 | - Improved poker engine (rule compliancy)
20 | - Implemented Heads Up (head-to-head) mode
21 | - General code cleanup
22 | - Divide odd chips from the pot
23 | - Added HISTORY.txt file
24 |
25 | 0.3a 11-Nov-2011 - Implemented pot division (including side pots)
26 | - Fixed more bugs in hand evaluator
27 | - Fixed bugs in game engine
28 | - Fixed GUI updates
29 | - Added Apache License 2.0 file and headers
30 |
31 | 0.2a 16-Jun-2011 Fixed more bugs in hand evaluator
32 |
33 | 0.1a 02-Jun-2011 - First official alpha release!
34 | - Console game with 1 player against 3 dumb bots
35 | - Swing GUI game variant
36 | - Fixed many bugs in hand evaluator
37 | - Added many unit tests
38 | - Added TODO.txt file
39 |
40 | - 19-Aug-2009 Initial project import from incubator.
41 |
--------------------------------------------------------------------------------
/texasholdem/doc/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/texasholdem/doc/README.txt:
--------------------------------------------------------------------------------
1 | Texas Hold'em poker
2 | ===================
3 |
4 |
5 | Introduction
6 | ------------
7 |
8 | This project has been created as a platform to experiment with a Texas Hold'em poker game in Java.
9 |
10 | Its primary goal is to offer a clean, open source Texas Hold'em poker engine in Java. The game
11 | engine strives to follow the famous Robert's Rules of Poker as close as possible. In order to test
12 | the game engine, the project also offers a Swing GUI and bots.
13 |
14 | This project is provided under the Apache License 2.0.
15 |
16 |
17 | Status
18 | ------
19 |
20 | The current implementation support the Fixed-Limit and No-Limit variants of the game with a Swing
21 | GUI, with the human player playing against 3 bots.
22 |
23 |
24 | Building and running
25 | --------------------
26 |
27 | This Java project has a Maven structure. Build the project with "mvn clean install" and find the
28 | binary in the 'target' directory. Run the game with "java -jar texasholdem.jar".
29 |
30 | Recommended tools for development are Eclipse with the Subversive and m2eclipse plugins.
31 |
32 |
33 | Contact
34 | -------
35 |
36 | If you like this project or have any questions please mail me (oscar.stigter@gmail.com). For bug
37 | reports or feature requests please create an issue using the Google Code project site
38 | (http://texasholdem-java.googlecode.com). Your input is highly appreciated!
39 |
40 |
41 | Disclaimer
42 | ----------
43 |
44 | This project is created only because of my love for Java and my interest in the game of poker. As a
45 | Christian, I strongly oppose to any form of gambling, as I believe it eventually leads to a path of
46 | greed, destruction and suffering.
47 |
--------------------------------------------------------------------------------
/texasholdem/doc/TODO.txt:
--------------------------------------------------------------------------------
1 | TODO
2 | ====
3 |
4 | * Determine the cards that form the best combination
5 | * Improve the hand descriptions
6 | * Heads Up bot arena
7 | * Table log (replayable) with GUI panel
8 | * Network game (client/server)
9 |
--------------------------------------------------------------------------------
/texasholdem/doc/Winnings.txt:
--------------------------------------------------------------------------------
1 | Poker winnings (pot division)
2 | =============================
3 |
4 | Player Cash Action Bet Pot
5 | A 10 SB (5) 10 5: {A} (Total: 5)
6 | B 20 BB (10) 10 5: {A, B}, 5: {B} (Total: 15)
7 | C 40 C (10) 10 5: {A, B, C}, 5: {B, C} (Total: 25)
8 | D 80 C (10) 10 5: {A, B, C, D}, 5: {B, C, D} (Total: 35)
9 | A 5 C (5) * 10 5: {A, B, C, D}, 5: {A, B, C, D} (Total: 40)
10 | B 10 - 10 5: {A, B, C, D}, 5: {A, B, C, D} (Total: 40)
11 | C 30 B 10 10 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {C} (Total: 50)
12 | D 70 R 10 20 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {C, D}, 10: {D} (Total: 70)
13 | A - - 20 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {C, D}, 10: {D} (Total: 70)
14 | B 10 C (10) * 20 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {B, C, D}, 10: {D} (Total: 80)
15 | C 20 C (10) 20 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {B, C, D}, 10: {C, D} (Total: 90)
16 | D 50 - 20 5: {A, B, C, D}, 5: {A, B, C, D}, 10: {B, C, D}, 10: {C, D} (Total: 90)
17 | * Ranking: A, B, C, D:
18 | * A receives 40 (20 + 20)
19 | * B receives 30
20 | * C receives 20
21 | * Ranking: C, A, B, D:
22 | * C receives 90
23 | * Ranking: D, A, B, C
24 | * D receives 90
25 | * Ranking: A/B, C, D
26 | * A receives 20 (20/2 + 20/2)
27 | * B receives 70 (20/2 + 20/2 + 30 + 20)
28 | * Ranking: A/C, B/D
29 | * A receives 20 (20/2 + 20/2)
30 | * C receives 70 (20/2 + 20/2 + 30 + 20)
31 | * Ranking: B/D, A, C
32 | * B receives 35 (20/2 + 20/2 + 30/2)
33 | * D receives 55 (20/2 + 20/2 + 30/2 + 20)
34 |
35 | Player Cash Action Bet Pot
36 | A 10 SB (5) 10 5: {A} (Total: 5)
37 | B 100 BB (10) 10 5: {A, B}, 5: {B} (Total: 15)
38 | C 20 C (10) 10 5: {A, B, C}, 5: {B, C} (Total: 25)
39 | A 5 C (5) * 10 5: {A, B, C}, 5: {A, B, C} (Total: 30)
40 | B 90 B 90 * 90 5: {A, B, C}, 5: {A, B, C}, 90: {B} (Total: 120)
41 | C 10 C (10) * 90 5: {A, B, C}, 5: {A, B, C}, 10: {B, C}, 80: {B} (Total: 130)
42 | * Ranking A, B, C:
43 | * A receives 30 (15 + 15)
44 | * B receives 100 (20 + 80)
45 | * Ranking B, A, C:
46 | * B receives 130 (15 + 15 + 20 + 80)
47 | * Ranking A, C, D:
48 | * A receives 30 (15 + 15)
49 | * C receives 20
50 | * D receives 80
51 | * Ranking C, A, D:
52 | * C receives 50 (15 + 15 + 20)
53 | * D receives 80
54 |
55 | Player Cash Action Bet Pot
56 | A 100 B 100 * 100 100: {A} (Total: 100)
57 | B 10 C (10) * 100 10: {A, B}, 90: {A} (Total: 110)
58 | C 50 C (50) * 100 10: {A, B, C}, 40: {A, C}, 50: {A} (Total: 160)
59 | * Ranking A, B, C:
60 | * A receives 160 (30 + 80 + 50)
61 | * Ranking B, C, A:
62 | * B receives 30
63 | * C receives 80
64 | * A receives 50
65 | * Ranking C, B, A:
66 | * C receives 110 (30 + 80)
67 | * A receives 50
68 | * Ranking A/B, C:
69 | * A receives 145 (30/2 + 80 + 50)
70 | * B receives 15 (30/2)
71 | * Ranking A/C, B:
72 | * A receives 105 (30/2 + 80/2 + 50)
73 | * C receives 55 (30/2 80/2)
74 | * Ranking B/C, A:
75 | * B receives 15 (30/2)
76 | * C receives 145 (30/2 + 80 + 50)
77 | * Ranking A/B/C:
78 | * A receives 100 (30/3 + 80/2 + 50)
79 | * B receives 10 (30/3)
80 | * C receives 50 (30/3 + 80/2)
81 |
--------------------------------------------------------------------------------
/texasholdem/launchers/texasholdem (GUI).launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/texasholdem/launchers/texasholdem (JUnit).launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/texasholdem/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | 4.0.0
5 |
6 | org.ozsoft.texasholdem
7 | TexasHoldEm
8 | 0.6-SNAPSHOT
9 | jar
10 |
11 | TexasHoldEm
12 | Texas Hold'em poker game
13 | 2009
14 |
15 |
16 | Apache License 2.0
17 | manual
18 |
19 |
20 |
21 |
22 | Oscar Stigter
23 | oscar.stigter@gmail.com
24 |
25 |
26 |
27 |
28 | UTF-8
29 | 1.7
30 | 4.11
31 |
32 |
33 |
34 |
35 | junit
36 | junit
37 | ${junit.version}
38 | test
39 |
40 |
41 |
42 |
43 | TexasHoldEm
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-compiler-plugin
48 |
49 | ${java.version}
50 | ${java.version}
51 |
52 |
53 |
54 | org.apache.maven.plugins
55 | maven-jar-plugin
56 |
57 |
58 |
59 | org.ozsoft.texasholdem.gui.Main
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Card.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | /**
21 | * A generic game card in a deck (without jokers).
22 | *
23 | *
24 | * Its value is determined first by rank, then by suit.
25 | *
26 | * @author Oscar Stigter
27 | */
28 | public class Card implements Comparable {
29 |
30 | /** The number of ranks in a deck. */
31 | public static final int NO_OF_RANKS = 13;
32 |
33 | /** The number of suits in a deck. */
34 | public static final int NO_OF_SUITS = 4;
35 |
36 | // The ranks.
37 | public static final int ACE = 12;
38 | public static final int KING = 11;
39 | public static final int QUEEN = 10;
40 | public static final int JACK = 9;
41 | public static final int TEN = 8;
42 | public static final int NINE = 7;
43 | public static final int EIGHT = 6;
44 | public static final int SEVEN = 5;
45 | public static final int SIX = 4;
46 | public static final int FIVE = 3;
47 | public static final int FOUR = 2;
48 | public static final int THREE = 1;
49 | public static final int DEUCE = 0;
50 |
51 | // The suits.
52 | public static final int SPADES = 3;
53 | public static final int HEARTS = 2;
54 | public static final int CLUBS = 1;
55 | public static final int DIAMONDS = 0;
56 |
57 | /** The rank symbols. */
58 | public static final String[] RANK_SYMBOLS = {
59 | "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"
60 | };
61 |
62 | /** The suit symbols. */
63 | public static final char[] SUIT_SYMBOLS = { 'd', 'c', 'h', 's' };
64 |
65 | /** The rank. */
66 | private final int rank;
67 |
68 | /** The suit. */
69 | private final int suit;
70 |
71 | /**
72 | * Constructor based on rank and suit.
73 | *
74 | * @param rank
75 | * The rank.
76 | * @param suit
77 | * The suit.
78 | *
79 | * @throws IllegalArgumentException
80 | * If the rank or suit is invalid.
81 | */
82 | public Card(int rank, int suit) {
83 | if (rank < 0 || rank > NO_OF_RANKS - 1) {
84 | throw new IllegalArgumentException("Invalid rank");
85 | }
86 | if (suit < 0 || suit > NO_OF_SUITS - 1) {
87 | throw new IllegalArgumentException("Invalid suit");
88 | }
89 | this.rank = rank;
90 | this.suit = suit;
91 | }
92 |
93 | /**
94 | * Constructor based on a string representing a card.
95 | *
96 | * The string must consist of a rank character and a suit character, in that
97 | * order.
98 | *
99 | * @param s
100 | * The string representation of the card, e.g. "As", "Td", "7h".
101 | *
102 | * @throws IllegalArgumentException
103 | * If the card string is null or of invalid length, or the rank
104 | * or suit could not be parsed.
105 | */
106 | public Card(String s) {
107 | if (s == null) {
108 | throw new IllegalArgumentException("Null string or of invalid length");
109 | }
110 | s = s.trim();
111 | if (s.length() != 2) {
112 | throw new IllegalArgumentException("Empty string or invalid length");
113 | }
114 |
115 | // Parse the rank character.
116 | String rankSymbol = s.substring(0, 1);
117 | char suitSymbol = s.charAt(1);
118 | int rank = -1;
119 | for (int i = 0; i < Card.NO_OF_RANKS; i++) {
120 | if (rankSymbol.equals(RANK_SYMBOLS[i])) {
121 | rank = i;
122 | break;
123 | }
124 | }
125 | if (rank == -1) {
126 | throw new IllegalArgumentException("Unknown rank: " + rankSymbol);
127 | }
128 | // Parse the suit character.
129 | int suit = -1;
130 | for (int i = 0; i < Card.NO_OF_SUITS; i++) {
131 | if (suitSymbol == SUIT_SYMBOLS[i]) {
132 | suit = i;
133 | break;
134 | }
135 | }
136 | if (suit == -1) {
137 | throw new IllegalArgumentException("Unknown suit: " + suitSymbol);
138 | }
139 | this.rank = rank;
140 | this.suit = suit;
141 | }
142 |
143 | /**
144 | * Returns the suit.
145 | *
146 | * @return The suit.
147 | */
148 | public int getSuit() {
149 | return suit;
150 | }
151 |
152 | /**
153 | * Returns the rank.
154 | *
155 | * @return The rank.
156 | */
157 | public int getRank() {
158 | return rank;
159 | }
160 |
161 | /** {@inheritDoc} */
162 | @Override
163 | public int hashCode() {
164 | return (rank * NO_OF_SUITS + suit);
165 | }
166 |
167 | /** {@inheritDoc} */
168 | @Override
169 | public boolean equals(Object obj) {
170 | if (obj instanceof Card) {
171 | return ((Card) obj).hashCode() == hashCode();
172 | } else {
173 | return false;
174 | }
175 | }
176 |
177 | /** {@inheritDoc} */
178 | @Override
179 | public int compareTo(Card card) {
180 | int thisValue = hashCode();
181 | int otherValue = card.hashCode();
182 | if (thisValue < otherValue) {
183 | return -1;
184 | } else if (thisValue > otherValue) {
185 | return 1;
186 | } else {
187 | return 0;
188 | }
189 | }
190 |
191 | /** {@inheritDoc} */
192 | @Override
193 | public String toString() {
194 | return RANK_SYMBOLS[rank] + SUIT_SYMBOLS[suit];
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Client.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.util.List;
21 | import java.util.Set;
22 |
23 | import org.ozsoft.texasholdem.actions.Action;
24 |
25 | /**
26 | * A player client showing the table information and acting on behalf of the
27 | * player.
28 | *
29 | *
30 | * Must be implemented by any client representing a player, either human or bot.
31 | *
32 | * @author Oscar Stigter
33 | */
34 | public interface Client {
35 |
36 | /**
37 | * Handles a game message.
38 | *
39 | * @param message
40 | * The message.
41 | */
42 | void messageReceived(String message);
43 |
44 | /**
45 | * Handles the player joining a table.
46 | *
47 | * @param type
48 | * The table type (betting structure).
49 | * @param bigBlind
50 | * The table's big blind.
51 | * @param players
52 | * The players at the table (including this player).
53 | */
54 | void joinedTable(TableType type, int bigBlind, List players);
55 |
56 | /**
57 | * Handles the start of a new hand.
58 | *
59 | * @param dealer
60 | * The dealer.
61 | */
62 | void handStarted(Player dealer);
63 |
64 | /**
65 | * Handles the rotation of the actor (the player who's turn it is).
66 | *
67 | * @param actor
68 | * The new actor.
69 | */
70 | void actorRotated(Player actor);
71 |
72 | /**
73 | * Handles an update of this player.
74 | *
75 | * @param player
76 | * The player.
77 | */
78 | void playerUpdated(Player player);
79 |
80 | /**
81 | * Handles an update of the board.
82 | *
83 | * @param cards
84 | * The community cards.
85 | * @param bet
86 | * The current bet.
87 | * @param pot
88 | * The current pot.
89 | */
90 | void boardUpdated(List cards, int bet, int pot);
91 |
92 | /**
93 | * Handles the event of a player acting.
94 | *
95 | * @param player
96 | * The player that has acted.
97 | */
98 | void playerActed(Player player);
99 |
100 | /**
101 | * Requests this player to act, selecting one of the allowed actions.
102 | *
103 | * @param minBet
104 | * The minimum bet.
105 | * @param currentBet
106 | * The current bet.
107 | * @param allowedActions
108 | * The allowed actions.
109 | *
110 | * @return The selected action.
111 | */
112 | Action act(int minBet, int currentBet, Set allowedActions);
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Deck.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.security.SecureRandom;
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Random;
24 |
25 | /**
26 | * A standard, generic deck of game cards without jokers.
27 | *
28 | *
29 | * NOTE: This class is implemented with the focus on performance (instead of clean design).
30 | *
31 | * @author Oscar Stigter
32 | */
33 | public class Deck {
34 |
35 | /** The number of cards in a deck. */
36 | private static final int NO_OF_CARDS = Card.NO_OF_RANKS * Card.NO_OF_SUITS;
37 |
38 | /** The cards in the deck. */
39 | private Card[] cards;
40 |
41 | /** The index of the next card to deal. */
42 | private int nextCardIndex = 0;
43 |
44 | /** Random number generator (crypographical quality). */
45 | private Random random = new SecureRandom();
46 |
47 | /**
48 | * Constructor.
49 | *
50 | * Starts as a full, ordered deck.
51 | */
52 | public Deck() {
53 | cards = new Card[NO_OF_CARDS];
54 | int index = 0;
55 | for (int suit = Card.NO_OF_SUITS - 1; suit >= 0; suit--) {
56 | for (int rank = Card.NO_OF_RANKS - 1; rank >= 0 ; rank--) {
57 | cards[index++] = new Card(rank, suit);
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * Shuffles the deck.
64 | */
65 | public void shuffle() {
66 | for (int oldIndex = 0; oldIndex < NO_OF_CARDS; oldIndex++) {
67 | int newIndex = random.nextInt(NO_OF_CARDS);
68 | Card tempCard = cards[oldIndex];
69 | cards[oldIndex] = cards[newIndex];
70 | cards[newIndex] = tempCard;
71 | }
72 | nextCardIndex = 0;
73 | }
74 |
75 | /**
76 | * Resets the deck.
77 | *
78 | * Does not re-order the cards.
79 | */
80 | public void reset() {
81 | nextCardIndex = 0;
82 | }
83 |
84 | /**
85 | * Deals a single card.
86 | *
87 | * @return the card dealt
88 | */
89 | public Card deal() {
90 | if (nextCardIndex + 1 >= NO_OF_CARDS) {
91 | throw new IllegalStateException("No cards left in deck");
92 | }
93 | return cards[nextCardIndex++];
94 | }
95 |
96 | /**
97 | * Deals multiple cards at once.
98 | *
99 | * @param noOfCards
100 | * The number of cards to deal.
101 | *
102 | * @return The cards.
103 | *
104 | * @throws IllegalArgumentException
105 | * If the number of cards is invalid.
106 | * @throws IllegalStateException
107 | * If there are no cards left in the deck.
108 | */
109 | public List deal(int noOfCards) {
110 | if (noOfCards < 1) {
111 | throw new IllegalArgumentException("noOfCards < 1");
112 | }
113 | if (nextCardIndex + noOfCards >= NO_OF_CARDS) {
114 | throw new IllegalStateException("No cards left in deck");
115 | }
116 | List dealtCards = new ArrayList();
117 | for (int i = 0; i < noOfCards; i++) {
118 | dealtCards.add(cards[nextCardIndex++]);
119 | }
120 | return dealtCards;
121 | }
122 |
123 | /**
124 | * Deals a specific card.
125 | *
126 | * @param rank
127 | * The card's rank.
128 | * @param suit
129 | * The card's suit.
130 | *
131 | * @return The card if available, otherwise null.
132 | *
133 | * @throws IllegalStateException
134 | * If there are no cards left in the deck.
135 | */
136 | public Card deal(int rank, int suit) {
137 | if (nextCardIndex + 1 >= NO_OF_CARDS) {
138 | throw new IllegalStateException("No cards left in deck");
139 | }
140 | Card card = null;
141 | int index = -1;
142 | for (int i = nextCardIndex; i < NO_OF_CARDS; i++) {
143 | if ((cards[i].getRank() == rank) && (cards[i].getSuit() == suit)) {
144 | index = i;
145 | break;
146 | }
147 | }
148 | if (index != -1) {
149 | if (index != nextCardIndex) {
150 | Card nextCard = cards[nextCardIndex];
151 | cards[nextCardIndex] = cards[index];
152 | cards[index] = nextCard;
153 | }
154 | card = deal();
155 | }
156 | return card;
157 | }
158 |
159 | /** {@inheritDoc} */
160 | @Override
161 | public String toString() {
162 | StringBuilder sb = new StringBuilder();
163 | for (Card card : cards) {
164 | sb.append(card);
165 | sb.append(' ');
166 | }
167 | return sb.toString().trim();
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Hand.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.util.Collection;
21 |
22 | /**
23 | * A generic hand of game cards.
24 | *
25 | *
26 | * The cards are ordered highest to lowest.
27 | *
28 | *
29 | * NOTE: This class is implemented with the focus on performance (instead of clean design).
30 | *
31 | * @author Oscar Stigter
32 | */
33 | public class Hand {
34 |
35 | /** The maximum number of cards in a hand. */
36 | private static final int MAX_NO_OF_CARDS = 7;
37 |
38 | /** The cards in this hand. */
39 | private Card[] cards = new Card[MAX_NO_OF_CARDS];
40 |
41 | /** The current number of cards in this hand. */
42 | private int noOfCards = 0;
43 |
44 | /**
45 | * Constructor for an empty hand.
46 | */
47 | public Hand() {
48 | // Empty implementation.
49 | }
50 |
51 | /**
52 | * Constructor with an array of initial cards.
53 | *
54 | * @param cards
55 | * The initial cards.
56 | *
57 | * @throws IllegalArgumentException
58 | * If the array is null or the number of cards is invalid.
59 | */
60 | public Hand(Card[] cards) {
61 | addCards(cards);
62 | }
63 |
64 | /**
65 | * Constructor with a collection of initial cards.
66 | *
67 | * @param cards
68 | * The initial cards.
69 | */
70 | public Hand(Collection cards) {
71 | if (cards == null) {
72 | throw new IllegalArgumentException("Null array");
73 | }
74 | for (Card card : cards) {
75 | addCard(card);
76 | }
77 | }
78 |
79 | /**
80 | * Constructor with a string representing the initial cards.
81 | *
82 | * The string must contain of one or more cards.
83 | * A card must be represented by a rank and a suit character.
84 | * The cards must be separated by a space character.
85 | *
86 | * Example: "Kh 7d 4c As Js"
87 | *
88 | * @param s
89 | * The string to parse.
90 | *
91 | * @throws IllegalArgumentException
92 | * If the string could not be parsed or the number of cards is
93 | * too high.
94 | */
95 | public Hand(String s) {
96 | if (s == null || s.length() == 0) {
97 | throw new IllegalArgumentException("Null or empty string");
98 | }
99 |
100 | String[] parts = s.split("\\s");
101 | if (parts.length > MAX_NO_OF_CARDS) {
102 | throw new IllegalArgumentException("Too many cards in hand");
103 | }
104 | for (String part : parts) {
105 | addCard(new Card(part));
106 | }
107 | }
108 |
109 | /**
110 | * Returns the number of cards.
111 | *
112 | * @return The number of cards.
113 | */
114 | public int size() {
115 | return noOfCards;
116 | }
117 |
118 | /**
119 | * Adds a single card.
120 | *
121 | * The card is inserted at such a position that the hand remains sorted
122 | * (highest ranking cards first).
123 | *
124 | * @param card
125 | * The card to add.
126 | *
127 | * @throws IllegalArgumentException
128 | * If the card is null.
129 | */
130 | public void addCard(Card card) {
131 | if (card == null) {
132 | throw new IllegalArgumentException("Null card");
133 | }
134 |
135 | int insertIndex = -1;
136 | for (int i = 0; i < noOfCards; i++) {
137 | if (card.compareTo(cards[i]) > 0) {
138 | insertIndex = i;
139 | break;
140 | }
141 | }
142 | if (insertIndex == -1) {
143 | // Could not insert anywhere, so append at the end.
144 | cards[noOfCards++] = card;
145 | } else {
146 | for (int i = noOfCards; i > insertIndex; i--) {
147 | cards[i] = cards[i - 1];
148 | }
149 | cards[insertIndex] = card;
150 | noOfCards++;
151 | }
152 | }
153 |
154 | /**
155 | * Adds multiple cards.
156 | *
157 | * The cards are inserted at such a position that the hand remains sorted
158 | * (highest ranking cards first).
159 | *
160 | * @param cards
161 | * The cards to add.
162 | */
163 | public void addCards(Card[] cards) {
164 | if (cards == null) {
165 | throw new IllegalArgumentException("Null array");
166 | }
167 | if (cards.length > MAX_NO_OF_CARDS) {
168 | throw new IllegalArgumentException("Too many cards");
169 | }
170 | for (Card card : cards) {
171 | addCard(card);
172 | }
173 | }
174 |
175 | /**
176 | * Adds multiple cards.
177 | *
178 | * The cards are inserted at such a position that the hand remains sorted
179 | * (highest ranking cards first).
180 | *
181 | * @param cards
182 | * The cards to add.
183 | */
184 | public void addCards(Collection cards) {
185 | if (cards == null) {
186 | throw new IllegalArgumentException("Null collection");
187 | }
188 | if (cards.size() > MAX_NO_OF_CARDS) {
189 | throw new IllegalArgumentException("Too many cards");
190 | }
191 | for (Card card : cards) {
192 | addCard(card);
193 | }
194 | }
195 |
196 | /**
197 | * Returns the cards.
198 | *
199 | * @return The cards.
200 | */
201 | public Card[] getCards() {
202 | Card[] dest = new Card[noOfCards];
203 | System.arraycopy(cards, 0, dest, 0, noOfCards);
204 | return dest;
205 | }
206 |
207 | /**
208 | * Removes all cards.
209 | */
210 | public void removeAllCards() {
211 | noOfCards = 0;
212 | }
213 |
214 | /** {@inheritDoc} */
215 | @Override
216 | public String toString() {
217 | StringBuilder sb = new StringBuilder();
218 | for (int i = 0; i < noOfCards; i++) {
219 | sb.append(cards[i]);
220 | if (i < (noOfCards - 1)) {
221 | sb.append(' ');
222 | }
223 | }
224 | return sb.toString();
225 | }
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/HandEvaluator.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | /**
21 | * Evaluator for calculating the value of a poker hand.
22 | *
23 | *
24 | * NOTE: This class is implemented with the focus on performance (instead of clean design).
25 | *
26 | * @author Oscar Stigter
27 | */
28 | public class HandEvaluator {
29 |
30 | /** The number of hand rankings. */
31 | private static final int NO_OF_RANKINGS = 6;
32 |
33 | /** The maximum number of counting pairs. */
34 | private static final int MAX_NO_OF_PAIRS = 2;
35 |
36 | /** The ranking factors (powers of 13, the number of ranks). */
37 | private static final int[] RANKING_FACTORS = {371293, 28561, 2197, 169, 13, 1};
38 |
39 | /** The hand value type. */
40 | private HandValueType type;
41 |
42 | /** The hand value as integer number. */
43 | private int value = 0;
44 |
45 | /** The cards. */
46 | private final Card[] cards;
47 |
48 | /** The rank distribution (number of cards for each rank). */
49 | private int[] rankDist = new int[Card.NO_OF_RANKS];
50 |
51 | /** The suit distribution (number of cards for each suit). */
52 | private int[] suitDist = new int[Card.NO_OF_SUITS];
53 |
54 | /** The number of pairs. */
55 | private int noOfPairs = 0;
56 |
57 | /** The ranks of the pairs. */
58 | private int[] pairs = new int[MAX_NO_OF_PAIRS];
59 |
60 | /** The suit of the Flush. */
61 | private int flushSuit = -1;
62 |
63 | /** The rank of the Flush. */
64 | private int flushRank = -1;
65 |
66 | /** The rank of the Straight. */
67 | private int straightRank = -1;
68 |
69 | /** Whether we have a Straight with a wheeling Ace. */
70 | private boolean wheelingAce = false;
71 |
72 | /** The rank of the Three-of-a-Kind. */
73 | private int tripleRank = -1;
74 |
75 | /** The rank of the Four-of-a-Kind. */
76 | private int quadRank = -1;
77 |
78 | /** The weighed components of the hand value (highest first). */
79 | private int[] rankings = new int[NO_OF_RANKINGS];
80 |
81 | /**
82 | * Constructor.
83 | *
84 | * @param hand The hand to evaulate.
85 | */
86 | public HandEvaluator(Hand hand) {
87 | cards = hand.getCards();
88 |
89 | // Find patterns.
90 | calculateDistributions();
91 | findStraight();
92 | findFlush();
93 | findDuplicates();
94 |
95 | // Find special values.
96 | boolean isSpecialValue =
97 | (isStraightFlush() ||
98 | isFourOfAKind() ||
99 | isFullHouse() ||
100 | isFlush() ||
101 | isStraight() ||
102 | isThreeOfAKind() ||
103 | isTwoPairs() ||
104 | isOnePair());
105 | if (!isSpecialValue) {
106 | calculateHighCard();
107 | }
108 |
109 | // Calculate value.
110 | for (int i = 0; i < NO_OF_RANKINGS; i++) {
111 | value += rankings[i] * RANKING_FACTORS[i];
112 | }
113 | }
114 |
115 | /**
116 | * Returns the hand value type.
117 | *
118 | * @return the hand value type
119 | */
120 | public HandValueType getType() {
121 | return type;
122 | }
123 |
124 | /**
125 | * Returns the hand value as an integer.
126 | *
127 | * This method should be used to compare hands.
128 | *
129 | * @return the hand value
130 | */
131 | public int getValue() {
132 | return value;
133 | }
134 |
135 | /**
136 | * Calculates the rank and suit distributions.
137 | */
138 | private void calculateDistributions() {
139 | for (Card card : cards) {
140 | rankDist[card.getRank()]++;
141 | suitDist[card.getSuit()]++;
142 | }
143 | }
144 |
145 | /**
146 | * Looks for a flush, i.e. five cards with the same suit.
147 | */
148 | private void findFlush() {
149 | for (int i = 0; i < Card.NO_OF_SUITS; i++) {
150 | if (suitDist[i] >= 5) {
151 | flushSuit = i;
152 | for (Card card : cards) {
153 | if (card.getSuit() == flushSuit) {
154 | if (!wheelingAce || card.getRank() != Card.ACE) {
155 | flushRank = card.getRank();
156 | break;
157 | }
158 | }
159 | }
160 | break;
161 | }
162 | }
163 | }
164 |
165 | /**
166 | * Looks for a Straight, i.e. five cards with sequential ranks.
167 | *
168 | * The Ace has the rank of One in case of a Five-high Straight (5-4-3-2-A).
169 | */
170 | private void findStraight() {
171 | boolean inStraight = false;
172 | int rank = -1;
173 | int count = 0;
174 | for (int i = Card.NO_OF_RANKS - 1; i >= 0 ; i--) {
175 | if (rankDist[i] == 0) {
176 | inStraight = false;
177 | count = 0;
178 | } else {
179 | if (!inStraight) {
180 | // First card of the potential Straight.
181 | inStraight = true;
182 | rank = i;
183 | }
184 | count++;
185 | if (count >= 5) {
186 | // Found a Straight!
187 | straightRank = rank;
188 | break;
189 | }
190 | }
191 | }
192 | // Special case for the 'Steel Wheel' (Five-high Straight with a 'wheeling Ace') .
193 | if ((count == 4) && (rank == Card.FIVE) && (rankDist[Card.ACE] > 0)) {
194 | wheelingAce = true;
195 | straightRank = rank;
196 | }
197 | }
198 |
199 | /**
200 | * Finds duplicates (pairs, triples and quads), i.e. two or more cards with
201 | * the same rank.
202 | */
203 | private void findDuplicates() {
204 | // Find quads, triples and pairs.
205 | for (int i = Card.NO_OF_RANKS - 1; i >= 0 ; i--) {
206 | if (rankDist[i] == 4) {
207 | quadRank = i;
208 | } else if (rankDist[i] == 3) {
209 | tripleRank = i;
210 | } else if (rankDist[i] == 2) {
211 | if (noOfPairs < MAX_NO_OF_PAIRS) {
212 | pairs[noOfPairs++] = i;
213 | }
214 | }
215 | }
216 | }
217 |
218 | /**
219 | * Calculates the hand value based on the highest ranks.
220 | */
221 | private void calculateHighCard() {
222 | type = HandValueType.HIGH_CARD;
223 | rankings[0] = type.getValue();
224 | // Get the five highest ranks.
225 | int index = 1;
226 | for (Card card : cards) {
227 | rankings[index++] = card.getRank();
228 | if (index > 5) {
229 | break;
230 | }
231 | }
232 | }
233 |
234 | /**
235 | * Returns true if this hand contains One Pair.
236 | *
237 | * The value of a One Pair is based on the rank of the pair.
238 | * The ranks of the remaining three cards are used as kickers.
239 | *
240 | * @return True if this hand contains One Pair.
241 | */
242 | private boolean isOnePair() {
243 | if (noOfPairs == 1) {
244 | type = HandValueType.ONE_PAIR;
245 | rankings[0] = type.getValue();
246 | // Get the rank of the pair.
247 | int pairRank = pairs[0];
248 | rankings[1] = pairRank;
249 | // Get the three kickers.
250 | int index = 2;
251 | for (Card card : cards) {
252 | int rank = card.getRank();
253 | if (rank != pairRank) {
254 | rankings[index++] = rank;
255 | if (index > 4) {
256 | // We don't need any more kickers.
257 | break;
258 | }
259 | }
260 | }
261 | return true;
262 | } else {
263 | return false;
264 | }
265 | }
266 |
267 | /**
268 | * Returns true if this hand contains Two Pairs.
269 | *
270 | * The value of a Two Pairs is primarily based on the rank of the highest
271 | * pair, secondarily on the rank of the lowest pair and tertiarily on the
272 | * ranks of the remaining one kicker.
273 | *
274 | * @return True if this hand contains Two Pairs.
275 | */
276 | private boolean isTwoPairs() {
277 | if (noOfPairs == 2) {
278 | type = HandValueType.TWO_PAIRS;
279 | rankings[0] = type.getValue();
280 | // Get the value of the high and low pairs.
281 | int highRank = pairs[0];
282 | int lowRank = pairs[1];
283 | rankings[1] = highRank;
284 | rankings[2] = lowRank;
285 | // Get the kicker card.
286 | for (Card card : cards) {
287 | int rank = card.getRank();
288 | if ((rank != highRank) && (rank != lowRank)) {
289 | rankings[3] = rank;
290 | break;
291 | }
292 | }
293 | return true;
294 | } else {
295 | return false;
296 | }
297 | }
298 |
299 | /**
300 | * Returns true if this hand contains a Three of a Kind.
301 | *
302 | * The value of a Three of a Kind is based on the rank of the triple.
303 | * The remaining two cards are used as kickers.
304 | *
305 | * @return True if this hand contains a Three of a Kind.
306 | */
307 | private boolean isThreeOfAKind() {
308 | if (tripleRank != -1) {
309 | type = HandValueType.THREE_OF_A_KIND;
310 | rankings[0] = type.getValue();
311 | rankings[1] = tripleRank;
312 | // Get the remaining two cards as kickers.
313 | int index = 2;
314 | for (Card card : cards) {
315 | int rank = card.getRank();
316 | if (rank != tripleRank) {
317 | rankings[index++] = rank;
318 | if (index > 3) {
319 | // We don't need any more kickers.
320 | break;
321 | }
322 | }
323 | }
324 | return true;
325 | } else {
326 | return false;
327 | }
328 | }
329 |
330 | /**
331 | * Returns true if this hand contains a Straight.
332 | *
333 | * The value of a Straight is based on the rank of the highest card in the
334 | * straight.
335 | *
336 | * @return True if this hand contains a Straight.
337 | */
338 | private boolean isStraight() {
339 | if (straightRank != -1) {
340 | type = HandValueType.STRAIGHT;
341 | rankings[0] = type.getValue();
342 | rankings[1] = straightRank;
343 | return true;
344 | } else {
345 | return false;
346 | }
347 | }
348 |
349 | /**
350 | * Returns true if this hand contains a Flush.
351 | *
352 | * The value of a Flush is based on the rank of the highest flushing card.
353 | * The remaining flushing cards are used as kickers.
354 | *
355 | * @return True if this hand contains a Flush.
356 | */
357 | private boolean isFlush() {
358 | if (flushSuit != -1) {
359 | type = HandValueType.FLUSH;
360 | rankings[0] = type.getValue();
361 | int index = 1;
362 | for (Card card : cards) {
363 | if (card.getSuit() == flushSuit) {
364 | int rank = card.getRank();
365 | if (index == 1) {
366 | flushRank = rank;
367 | }
368 | rankings[index++] = rank;
369 | if (index > 5) {
370 | // We don't need more kickers.
371 | break;
372 | }
373 | }
374 | }
375 | return true;
376 | } else {
377 | return false;
378 | }
379 | }
380 |
381 | /**
382 | * Returns true if this hand contains a Full House.
383 | *
384 | * The value of a Full House is primarily based on the rank of the triple
385 | * and secondarily on the rank of the pair. There are no kickers.
386 | *
387 | * @return True if this hand contains a Full House.
388 | */
389 | private boolean isFullHouse() {
390 | if ((tripleRank != -1) && (noOfPairs > 0)) {
391 | type = HandValueType.FULL_HOUSE;
392 | rankings[0] = type.getValue();
393 | rankings[1] = tripleRank;
394 | rankings[2] = pairs[0];
395 | return true;
396 | } else {
397 | return false;
398 | }
399 | }
400 |
401 | /**
402 | * Returns true if this hand contains a Four of a Kind.
403 | *
404 | * The value of a Four of a Kind is primarily based on the rank of the
405 | * quad. There remaining card is used as kicker.
406 | *
407 | * @return True if this hand contains a Four of a Kind.
408 | */
409 | private boolean isFourOfAKind() {
410 | if (quadRank != -1) {
411 | type = HandValueType.FOUR_OF_A_KIND;
412 | rankings[0] = type.getValue();
413 | rankings[1] = quadRank;
414 | // Get the remaining card as kicker.
415 | int index = 2;
416 | for (Card card : cards) {
417 | int rank = card.getRank();
418 | if (rank != quadRank) {
419 | rankings[index++] = rank;
420 | break;
421 | }
422 | }
423 | return true;
424 | } else {
425 | return false;
426 | }
427 | }
428 |
429 | /**
430 | * Returns true if this hand contains a Straight Flush.
431 | *
432 | * An Ace-high Straight Flush is a Royal Flush, which has a fixed hand value
433 | * (no kickers).
434 | *
435 | * The value of a (non-Royal Flush) Straight Flush is based on the rank of
436 | * the highest card of the Straight. There are no kickers.
437 | *
438 | * @return True if this hand contains a Straight Flush.
439 | */
440 | private boolean isStraightFlush() {
441 | if (straightRank != -1 && flushRank == straightRank) {
442 | // Flush and Straight (possibly separate); check for Straight Flush.
443 | int straightRank2 = -1;
444 | int lastSuit = -1;
445 | int lastRank = -1;
446 | int inStraight = 1;
447 | int inFlush = 1;
448 | for (Card card : cards) {
449 | int rank = card.getRank();
450 | int suit = card.getSuit();
451 | if (lastRank != -1) {
452 | int rankDiff = lastRank - rank;
453 | if (rankDiff == 1) {
454 | // Consecutive rank; possible straight!
455 | inStraight++;
456 | if (straightRank2 == -1) {
457 | straightRank2 = lastRank;
458 | }
459 | if (suit == lastSuit) {
460 | inFlush++;
461 | } else {
462 | inFlush = 1;
463 | }
464 | if (inStraight >= 5 && inFlush >= 5) {
465 | // Straight!
466 | break;
467 | }
468 | } else if (rankDiff == 0) {
469 | // Duplicate rank; skip.
470 | } else {
471 | // Non-consecutive; reset.
472 | straightRank2 = -1;
473 | inStraight = 1;
474 | inFlush = 1;
475 | }
476 | }
477 | lastRank = rank;
478 | lastSuit = suit;
479 | }
480 |
481 | if (inStraight >= 5 && inFlush >= 5) {
482 | if (straightRank == Card.ACE) {
483 | // Royal Flush.
484 | type = HandValueType.ROYAL_FLUSH;
485 | rankings[0] = type.getValue();
486 | return true;
487 | } else {
488 | // Straight Flush.
489 | type = HandValueType.STRAIGHT_FLUSH;
490 | rankings[0] = type.getValue();
491 | rankings[1] = straightRank2;
492 | return true;
493 | }
494 | } else if (wheelingAce && inStraight >= 4 && inFlush >= 4) {
495 | // Steel Wheel (Straight Flush with wheeling Ace).
496 | type = HandValueType.STRAIGHT_FLUSH;
497 | rankings[0] = type.getValue();
498 | rankings[1] = straightRank2;
499 | return true;
500 | } else {
501 | return false;
502 | }
503 | } else {
504 | return false;
505 | }
506 | }
507 |
508 | }
509 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/HandValue.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | /**
21 | * Represents the value of a poker hand.
22 | *
23 | *
24 | * Implements the Comparable interface with reversed
25 | * (descending sort) order.
26 | *
27 | * @author Oscar Stigter
28 | */
29 | public class HandValue implements Comparable {
30 |
31 | /** The hand. */
32 | private final Hand hand;
33 |
34 | /** The hand value type. */
35 | private final HandValueType type;
36 |
37 | /** The exact, numeric hand value. */
38 | private final int value;
39 |
40 | /**
41 | * Constructor.
42 | *
43 | * @param hand
44 | * The hand.
45 | */
46 | public HandValue(Hand hand) {
47 | this.hand = hand;
48 | HandEvaluator evaluator = new HandEvaluator(hand);
49 | type = evaluator.getType();
50 | value = evaluator.getValue();
51 | }
52 |
53 | /**
54 | * Returns the hand.
55 | *
56 | * @return The hand.
57 | */
58 | public Hand getHand() {
59 | return hand;
60 | }
61 |
62 | /**
63 | * Returns the hand value type.
64 | *
65 | * @return The hand value type.
66 | */
67 | public HandValueType getType() {
68 | return type;
69 | }
70 |
71 | /**
72 | * Returns a description of the hand value type.
73 | *
74 | * @return The description of the hand value type.
75 | */
76 | public String getDescription() {
77 | return type.getDescription();
78 | }
79 |
80 | /**
81 | * Returns the exact, numeric hand value.
82 | *
83 | * @return The exact, numeric hand value.
84 | */
85 | public int getValue() {
86 | return value;
87 | }
88 |
89 | /** {@inheritDoc} */
90 | @Override
91 | public int hashCode() {
92 | return value;
93 | }
94 |
95 | /** {@inheritDoc} */
96 | @Override
97 | public boolean equals(Object obj) {
98 | if (obj instanceof HandValue) {
99 | return ((HandValue) obj).getValue() == value;
100 | } else {
101 | return false;
102 | }
103 | }
104 |
105 | /** {@inheritDoc} */
106 | @Override
107 | public int compareTo(HandValue handValue) {
108 | if (value > handValue.getValue()) {
109 | return -1;
110 | } else if (value < handValue.getValue()) {
111 | return 1;
112 | } else {
113 | return 0;
114 | }
115 | }
116 |
117 | /** {@inheritDoc} */
118 | @Override
119 | public String toString() {
120 | return String.format("%s (%d)", type.getDescription(), value);
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/HandValueType.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | /**
21 | * The hand value types in poker.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public enum HandValueType {
26 |
27 | /** Royal flush (Ace-high Straight Flush). */
28 | ROYAL_FLUSH("a Royal Flush", 9),
29 |
30 | /** Straight Flush (a Straight and a Flush, less than Ace-high). */
31 | STRAIGHT_FLUSH("a Straight Flush", 8),
32 |
33 | /** Four of a Kind (four cards of the same rank). */
34 | FOUR_OF_A_KIND("Four of a Kind", 7),
35 |
36 | /** Full House (a Three of a Kind and Two Pairs). */
37 | FULL_HOUSE("a Full House", 6),
38 |
39 | /** Flush (five cards of the same suit). */
40 | FLUSH("a Flush", 5),
41 |
42 | /** Straight (five cards in sequential order). */
43 | STRAIGHT("a Straight", 4),
44 |
45 | /** Three of a Kind (three cards of the same rank). */
46 | THREE_OF_A_KIND("Three of a Kind", 3),
47 |
48 | /** Two Pairs (two pairs). */
49 | TWO_PAIRS("Two Pairs", 2),
50 |
51 | /** One Pair (two cards of the same rank). */
52 | ONE_PAIR("One Pair", 1),
53 |
54 | /** Highest Card (the card with the highest rank). */
55 | HIGH_CARD("a High Card", 0),
56 |
57 | ;
58 |
59 | /** The description. */
60 | private String description;
61 |
62 | /** The hand value. */
63 | private int value;
64 |
65 | /**
66 | * Constructor.
67 | *
68 | * @param description
69 | * The description.
70 | * @param value
71 | * The hand value.
72 | */
73 | HandValueType(String description, int value) {
74 | this.description = description;
75 | this.value = value;
76 | }
77 |
78 | /**
79 | * Returns the description.
80 | *
81 | * @return The description.
82 | */
83 | public String getDescription() {
84 | return description;
85 | }
86 |
87 | /**
88 | * Returns the hand value.
89 | *
90 | * @return The hand value.
91 | */
92 | public int getValue() {
93 | return value;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Player.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.util.List;
21 |
22 | import org.ozsoft.texasholdem.actions.Action;
23 |
24 | /**
25 | * A Texas Hold'em player.
26 | *
27 | *
28 | * The player's actions are delegated to a {@link Client}, which can be either
29 | * human-controlled or AI-controlled (bot).
30 | *
31 | * @author Oscar Stigter
32 | */
33 | public class Player {
34 |
35 | /** Name. */
36 | private final String name;
37 |
38 | /** Client application responsible for the actual behavior. */
39 | private final Client client;
40 |
41 | /** Hand of cards. */
42 | private final Hand hand;
43 |
44 | /** Current amount of cash. */
45 | private int cash;
46 |
47 | /** Whether the player has hole cards. */
48 | private boolean hasCards;
49 |
50 | /** Current bet. */
51 | private int bet;
52 |
53 | /** Last action performed. */
54 | private Action action;
55 |
56 | /**
57 | * Constructor.
58 | *
59 | * @param name
60 | * The player's name.
61 | * @param cash
62 | * The player's starting amount of cash.
63 | * @param client
64 | * The client application.
65 | */
66 | public Player(String name, int cash, Client client) {
67 | this.name = name;
68 | this.cash = cash;
69 | this.client = client;
70 |
71 | hand = new Hand();
72 |
73 | resetHand();
74 | }
75 |
76 | /**
77 | * Returns the client.
78 | *
79 | * @return The client.
80 | */
81 | public Client getClient() {
82 | return client;
83 | }
84 |
85 | /**
86 | * Prepares the player for another hand.
87 | */
88 | public void resetHand() {
89 | hasCards = false;
90 | hand.removeAllCards();
91 | resetBet();
92 | }
93 |
94 | /**
95 | * Resets the player's bet.
96 | */
97 | public void resetBet() {
98 | bet = 0;
99 | action = (hasCards() && cash == 0) ? Action.ALL_IN : null;
100 | }
101 |
102 | /**
103 | * Sets the hole cards.
104 | */
105 | public void setCards(List cards) {
106 | hand.removeAllCards();
107 | if (cards != null) {
108 | if (cards.size() == 2) {
109 | hand.addCards(cards);
110 | hasCards = true;
111 | System.out.format("[CHEAT] %s's cards:\t%s\n", name, hand);
112 | } else {
113 | throw new IllegalArgumentException("Invalid number of cards");
114 | }
115 | }
116 | }
117 |
118 | /**
119 | * Returns whether the player has his hole cards dealt.
120 | *
121 | * @return True if the hole cards are dealt, otherwise false.
122 | */
123 | public boolean hasCards() {
124 | return hasCards;
125 | }
126 |
127 | /**
128 | * Returns the player's name.
129 | *
130 | * @return The name.
131 | */
132 | public String getName() {
133 | return name;
134 | }
135 |
136 | /**
137 | * Returns the player's current amount of cash.
138 | *
139 | * @return The amount of cash.
140 | */
141 | public int getCash() {
142 | return cash;
143 | }
144 |
145 | /**
146 | * Returns the player's current bet.
147 | *
148 | * @return The current bet.
149 | */
150 | public int getBet() {
151 | return bet;
152 | }
153 |
154 | /**
155 | * Sets the player's current bet.
156 | *
157 | * @param bet
158 | * The current bet.
159 | */
160 | public void setBet(int bet) {
161 | this.bet = bet;
162 | }
163 |
164 | /**
165 | * Returns the player's most recent action.
166 | *
167 | * @return The action.
168 | */
169 | public Action getAction() {
170 | return action;
171 | }
172 |
173 | /**
174 | * Sets the player's most recent action.
175 | *
176 | * @param action
177 | * The action.
178 | */
179 | public void setAction(Action action) {
180 | this.action = action;
181 | }
182 |
183 | /**
184 | * Indicates whether this player is all-in.
185 | *
186 | * @return True if all-in, otherwise false.
187 | */
188 | public boolean isAllIn() {
189 | return hasCards() && (cash == 0);
190 | }
191 |
192 | /**
193 | * Returns the player's hole cards.
194 | *
195 | * @return The hole cards.
196 | */
197 | public Card[] getCards() {
198 | return hand.getCards();
199 | }
200 |
201 | /**
202 | * Posts the small blind.
203 | *
204 | * @param blind
205 | * The small blind.
206 | */
207 | public void postSmallBlind(int blind) {
208 | action = Action.SMALL_BLIND;
209 | cash -= blind;
210 | bet += blind;
211 | }
212 |
213 | /**
214 | * Posts the big blinds.
215 | *
216 | * @param blind
217 | * The big blind.
218 | */
219 | public void postBigBlind(int blind) {
220 | action = Action.BIG_BLIND;
221 | cash -= blind;
222 | bet += blind;
223 | }
224 |
225 | /**
226 | * Pays an amount of cash.
227 | *
228 | * @param amount
229 | * The amount of cash to pay.
230 | */
231 | public void payCash(int amount) {
232 | if (amount > cash) {
233 | throw new IllegalStateException("Player asked to pay more cash than he owns!");
234 | }
235 | cash -= amount;
236 | }
237 |
238 | /**
239 | * Wins an amount of money.
240 | *
241 | * @param amount
242 | * The amount won.
243 | */
244 | public void win(int amount) {
245 | cash += amount;
246 | }
247 |
248 | /**
249 | * Returns a clone of this player with only public information.
250 | *
251 | * @return The cloned player.
252 | */
253 | public Player publicClone() {
254 | Player clone = new Player(name, cash, null);
255 | clone.hasCards = hasCards;
256 | clone.bet = bet;
257 | clone.action = action;
258 | return clone;
259 | }
260 |
261 | /** {@inheritDoc} */
262 | @Override
263 | public String toString() {
264 | return name;
265 | }
266 |
267 | }
268 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/Pot.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.util.Collections;
21 | import java.util.HashSet;
22 | import java.util.Set;
23 |
24 | /**
25 | * A pot to which one or more players have contributed.
26 | *
27 | *
28 | * Each pot has an equal fixed amount for all contributing players. In case of a
29 | * partial call, bet or raise, the pot must be {@link #split}.
30 | *
31 | * @author Oscar Stigter
32 | */
33 | public class Pot {
34 |
35 | /** Bet for this pot. */
36 | private int bet;
37 |
38 | /** Contributing players to this pot. */
39 | public final Set contributors;
40 |
41 | /**
42 | * Constructor.
43 | *
44 | * @param bet
45 | * The bet for this pot.
46 | */
47 | public Pot(int bet) {
48 | this.bet = bet;
49 | contributors = new HashSet();
50 | }
51 |
52 | /**
53 | * Returns the bet.
54 | *
55 | * @return The bet.
56 | */
57 | public int getBet() {
58 | return bet;
59 | }
60 |
61 | /**
62 | * Returns the contributing players.
63 | *
64 | * @return The conributing players.
65 | */
66 | public Set getContributors() {
67 | return Collections.unmodifiableSet(contributors);
68 | }
69 |
70 | /**
71 | * Adds a contributing player.
72 | *
73 | * @param player
74 | * The player.
75 | */
76 | public void addContributer(Player player) {
77 | contributors.add(player);
78 | }
79 |
80 | /**
81 | * Indicates whether a specific player has contributed to this pot.
82 | *
83 | * @param player
84 | * The player.
85 | *
86 | * @return True if the player has contributed, otherwise false.
87 | */
88 | public boolean hasContributer(Player player) {
89 | return contributors.contains(player);
90 | }
91 |
92 | /**
93 | * Returns the total value of this pot.
94 | *
95 | * @return The total value.
96 | */
97 | public int getValue() {
98 | return bet * contributors.size();
99 | }
100 |
101 | /**
102 | * In case of a partial call, bet or raise, splits this pot into two pots,
103 | * with this pot keeping the lower bet and the other pot the remainder.
104 | *
105 | * @param player
106 | * The player with the partial call, bet or raise.
107 | * @param partialBet
108 | * The amount of the partial bet.
109 | *
110 | * @return The other pot, with the remainder.
111 | */
112 | public Pot split(Player player, int partialBet) {
113 | Pot pot = new Pot(bet - partialBet);
114 | for (Player contributer : contributors) {
115 | pot.addContributer(contributer);
116 | }
117 | bet = partialBet;
118 | contributors.add(player);
119 | return pot;
120 | }
121 |
122 | /**
123 | * Clears this pot.
124 | */
125 | public void clear() {
126 | bet = 0;
127 | contributors.clear();
128 | }
129 |
130 | /** {@inheritDoc} */
131 | @Override
132 | public String toString() {
133 | StringBuilder sb = new StringBuilder();
134 | sb.append(String.valueOf(bet));
135 | sb.append(": {");
136 | boolean isFirst = true;
137 | for (Player contributer : contributors) {
138 | if (isFirst) {
139 | isFirst = false;
140 | } else {
141 | sb.append(", ");
142 | }
143 | sb.append(contributer.getName());
144 | }
145 | sb.append('}');
146 | sb.append(" (Total: ");
147 | sb.append(String.valueOf(getValue()));
148 | sb.append(')');
149 | return sb.toString();
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/TableType.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | /**
21 | * Supported table types (betting structures).
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public enum TableType {
26 |
27 | /** Fixed-Limit Texas Hold'em. */
28 | FIXED_LIMIT("Fixed-Limit"),
29 |
30 | /** No-Limit Texas Hold'em. */
31 | NO_LIMIT("No-Limit"),
32 |
33 | ;
34 |
35 | /** Display name. */
36 | private String name;
37 |
38 | /**
39 | * Constructor.
40 | *
41 | * @param name
42 | * The display name.
43 | */
44 | TableType(String name) {
45 | this.name = name;
46 | }
47 |
48 | /**
49 | * Returns the display name.
50 | *
51 | * @return The display name.
52 | */
53 | public String getName() {
54 | return name;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/Action.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * Player action.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public abstract class Action {
26 |
27 | /** Player went all-in. */
28 | public static final Action ALL_IN = new AllInAction();
29 |
30 | /** Bet. */
31 | public static final Action BET = new BetAction(0);
32 |
33 | /** Posting the big blind. */
34 | public static final Action BIG_BLIND = new BigBlindAction();
35 |
36 | /** Call. */
37 | public static final Action CALL = new CallAction();
38 |
39 | /** Check. */
40 | public static final Action CHECK = new CheckAction();
41 |
42 | /** Continue. */
43 | public static final Action CONTINUE = new ContinueAction();
44 |
45 | /** Fold. */
46 | public static final Action FOLD = new FoldAction();
47 |
48 | /** Raise. */
49 | public static final Action RAISE = new RaiseAction(0);
50 |
51 | /** Posting the small blind. */
52 | public static final Action SMALL_BLIND = new SmallBlindAction();
53 |
54 | /** The action's name. */
55 | private final String name;
56 |
57 | /** The action's verb. */
58 | private final String verb;
59 |
60 | /** The amount (if appropriate). */
61 | private final int amount;
62 |
63 | /**
64 | * Constructor.
65 | *
66 | * @param name
67 | * The action's name.
68 | * @param verb
69 | * The action's verb.
70 | */
71 | public Action(String name, String verb) {
72 | this(name, verb, 0);
73 | }
74 |
75 | /**
76 | * Constructor.
77 | *
78 | * @param name
79 | * The action's name.
80 | * @param verb
81 | * The action's verb.
82 | * @param amount
83 | * The action's amount.
84 | */
85 | public Action(String name, String verb, int amount) {
86 | this.name = name;
87 | this.verb = verb;
88 | this.amount = amount;
89 | }
90 |
91 | /**
92 | * Returns the action's name.
93 | *
94 | * @return The action's name.
95 | */
96 | public final String getName() {
97 | return name;
98 | }
99 |
100 | /**
101 | * Returns the action's verb.
102 | *
103 | * @return The action's verb.
104 | */
105 | public final String getVerb() {
106 | return verb;
107 | }
108 |
109 | /**
110 | * Returns the action's amount.
111 | *
112 | * @return The action's amount.
113 | */
114 | public final int getAmount() {
115 | return amount;
116 | }
117 |
118 | /** {@inheritDoc} */
119 | @Override
120 | public String toString() {
121 | return name;
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/AllInAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of going all-in.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class AllInAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ AllInAction() {
31 | super("All-in", "goes all-in");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/BetAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of placing a bet.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class BetAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | *
30 | * @param amount
31 | * The amount to bet.
32 | */
33 | public BetAction(int amount) {
34 | super("Bet", "bets", amount);
35 | }
36 |
37 | /** {@inheritDoc} */
38 | @Override
39 | public String toString() {
40 | return String.format("Bet(%d)", getAmount());
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/BigBlindAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of posting the big blind.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class BigBlindAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ BigBlindAction() {
31 | super("Big blind", "posts the big blind");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/CallAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of calling a previous bet or raise.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class CallAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ CallAction() {
31 | super("Call", "calls");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/CheckAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of checking.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class CheckAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ CheckAction() {
31 | super("Check", "checks");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/ContinueAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of continuing (GUI action only).
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class ContinueAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ ContinueAction() {
31 | super("Continue", "continues");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/FoldAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of folding the current hand.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class FoldAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ FoldAction() {
31 | super("Fold", "folds");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/RaiseAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of raising a previous bet.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class RaiseAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | *
30 | * @param amount
31 | * The amount to raise with.
32 | */
33 | public RaiseAction(int amount) {
34 | super("Raise", "raises", amount);
35 | }
36 |
37 | /** {@inheritDoc} */
38 | @Override
39 | public String toString() {
40 | return String.format("Raise(%d)", getAmount());
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/actions/SmallBlindAction.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.actions;
19 |
20 | /**
21 | * The action of posting the small blind.
22 | *
23 | * @author Oscar Stigter
24 | */
25 | public class SmallBlindAction extends Action {
26 |
27 | /**
28 | * Constructor.
29 | */
30 | /* package */ SmallBlindAction() {
31 | super("Small blind", "posts the small blind");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/bots/BasicBot.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.bots;
19 |
20 | import java.util.List;
21 | import java.util.Set;
22 |
23 | import org.ozsoft.texasholdem.Card;
24 | import org.ozsoft.texasholdem.Player;
25 | import org.ozsoft.texasholdem.TableType;
26 | import org.ozsoft.texasholdem.actions.Action;
27 | import org.ozsoft.texasholdem.actions.BetAction;
28 | import org.ozsoft.texasholdem.actions.RaiseAction;
29 | import org.ozsoft.texasholdem.util.PokerUtils;
30 |
31 | /**
32 | * Basic Texas Hold'em poker bot.
33 | *
34 | *
35 | * The current implementation acts purely on the bot's hole cards, based on the
36 | * Chen formula, combined with a configurable level of tightness (when to play
37 | * or fold a hand ) and aggression (how much to bet or raise in case of good
38 | * cards or when bluffing).
39 | *
40 | *
41 | * TODO:
42 | *
43 | *
Improve basic bot AI
44 | *
bluffing
45 | *
consider board cards
46 | *
consider current bet
47 | *
consider pot
48 | *
49 | *
50 | * @author Oscar Stigter
51 | */
52 | public class BasicBot extends Bot {
53 |
54 | /** Tightness (0 = loose, 100 = tight). */
55 | private final int tightness;
56 |
57 | /** Betting aggression (0 = safe, 100 = aggressive). */
58 | private final int aggression;
59 |
60 | /** Table type. */
61 | private TableType tableType;
62 |
63 | /** The hole cards. */
64 | private Card[] cards;
65 |
66 | /**
67 | * Constructor.
68 | *
69 | * @param tightness
70 | * The bot's tightness (0 = loose, 100 = tight).
71 | * @param aggression
72 | * The bot's aggressiveness in betting (0 = careful, 100 =
73 | * aggressive).
74 | */
75 | public BasicBot(int tightness, int aggression) {
76 | if (tightness < 0 || tightness > 100) {
77 | throw new IllegalArgumentException("Invalid tightness setting");
78 | }
79 | if (aggression < 0 || aggression > 100) {
80 | throw new IllegalArgumentException("Invalid aggression setting");
81 | }
82 | this.tightness = tightness;
83 | this.aggression = aggression;
84 | }
85 |
86 | /** {@inheritDoc} */
87 | @Override
88 | public void joinedTable(TableType type, int bigBlind, List players) {
89 | this.tableType = type;
90 | }
91 |
92 | /** {@inheritDoc} */
93 | @Override
94 | public void messageReceived(String message) {
95 | // Not implemented.
96 | }
97 |
98 | /** {@inheritDoc} */
99 | @Override
100 | public void handStarted(Player dealer) {
101 | cards = null;
102 | }
103 |
104 | /** {@inheritDoc} */
105 | @Override
106 | public void actorRotated(Player actor) {
107 | // Not implemented.
108 | }
109 |
110 | /** {@inheritDoc} */
111 | @Override
112 | public void boardUpdated(List cards, int bet, int pot) {
113 | // Not implemented.
114 | }
115 |
116 | /** {@inheritDoc} */
117 | @Override
118 | public void playerUpdated(Player player) {
119 | if (player.getCards().length == NO_OF_HOLE_CARDS) {
120 | this.cards = player.getCards();
121 | }
122 | }
123 |
124 | /** {@inheritDoc} */
125 | @Override
126 | public void playerActed(Player player) {
127 | // Not implemented.
128 | }
129 |
130 | /** {@inheritDoc} */
131 | @Override
132 | public Action act(int minBet, int currentBet, Set allowedActions) {
133 | Action action = null;
134 | if (allowedActions.size() == 1) {
135 | // No choice, must check.
136 | action = Action.CHECK;
137 | } else {
138 | double chenScore = PokerUtils.getChenScore(cards);
139 | double chenScoreToPlay = tightness * 0.2;
140 | if ((chenScore < chenScoreToPlay)) {
141 | if (allowedActions.contains(Action.CHECK)) {
142 | // Always check for free if possible.
143 | action = Action.CHECK;
144 | } else {
145 | // Bad hole cards; play tight.
146 | action = Action.FOLD;
147 | }
148 | } else {
149 | // Good enough hole cards, play hand.
150 | if ((chenScore - chenScoreToPlay) >= ((20.0 - chenScoreToPlay) / 2.0)) {
151 | // Very good hole cards; bet or raise!
152 | if (aggression == 0) {
153 | // Never bet.
154 | if (allowedActions.contains(Action.CALL)) {
155 | action = Action.CALL;
156 | } else {
157 | action = Action.CHECK;
158 | }
159 | } else if (aggression == 100) {
160 | // Always go all-in!
161 | //FIXME: Check and bet/raise player's remaining cash.
162 | int amount = (tableType == TableType.FIXED_LIMIT) ? minBet : 100 * minBet;
163 | if (allowedActions.contains(Action.BET)) {
164 | action = new BetAction(amount);
165 | } else if (allowedActions.contains(Action.RAISE)) {
166 | action = new RaiseAction(amount);
167 | } else if (allowedActions.contains(Action.CALL)) {
168 | action = Action.CALL;
169 | } else {
170 | action = Action.CHECK;
171 | }
172 | } else {
173 | int amount = minBet;
174 | if (tableType == TableType.NO_LIMIT) {
175 | int betLevel = aggression / 20;
176 | for (int i = 0; i < betLevel; i++) {
177 | amount *= 2;
178 | }
179 | }
180 | if (currentBet < amount) {
181 | if (allowedActions.contains(Action.BET)) {
182 | action = new BetAction(amount);
183 | } else if (allowedActions.contains(Action.RAISE)) {
184 | action = new RaiseAction(amount);
185 | } else if (allowedActions.contains(Action.CALL)) {
186 | action = Action.CALL;
187 | } else {
188 | action = Action.CHECK;
189 | }
190 | } else {
191 | if (allowedActions.contains(Action.CALL)) {
192 | action = Action.CALL;
193 | } else {
194 | action = Action.CHECK;
195 | }
196 | }
197 | }
198 | } else {
199 | // Decent hole cards; check or call.
200 | if (allowedActions.contains(Action.CHECK)) {
201 | action = Action.CHECK;
202 | } else {
203 | action = Action.CALL;
204 | }
205 | }
206 | }
207 | }
208 | return action;
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/bots/Bot.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.bots;
19 |
20 | import org.ozsoft.texasholdem.Client;
21 |
22 | /**
23 | * Base class for all Texas Hold'em poker bot implementations.
24 | *
25 | * @author Oscar Stigter
26 | */
27 | public abstract class Bot implements Client {
28 |
29 | /** Number of hole cards. */
30 | protected static final int NO_OF_HOLE_CARDS = 2;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/bots/DummyBot.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.bots;
19 |
20 | import java.util.List;
21 | import java.util.Set;
22 |
23 | import org.ozsoft.texasholdem.Card;
24 | import org.ozsoft.texasholdem.Player;
25 | import org.ozsoft.texasholdem.TableType;
26 | import org.ozsoft.texasholdem.actions.Action;
27 |
28 | /**
29 | * Dummy Texas Hold'em poker bot that always just checks or calls.
30 | *
31 | *
32 | * This bot allowed for perfectly predictable behavior.
33 | *
34 | * @author Oscar Stigter
35 | */
36 | public class DummyBot extends Bot {
37 |
38 | /** {@inheritDoc} */
39 | @Override
40 | public void messageReceived(String message) {
41 | // Not implemented.
42 | }
43 |
44 | /** {@inheritDoc} */
45 | @Override
46 | public void joinedTable(TableType type, int bigBlind, List players) {
47 | // Not implemented.
48 | }
49 |
50 | /** {@inheritDoc} */
51 | @Override
52 | public void handStarted(Player dealer) {
53 | // Not implemented.
54 | }
55 |
56 | /** {@inheritDoc} */
57 | @Override
58 | public void actorRotated(Player actor) {
59 | // Not implemented.
60 | }
61 |
62 | /** {@inheritDoc} */
63 | @Override
64 | public void playerUpdated(Player player) {
65 | // Not implemented.
66 | }
67 |
68 | /** {@inheritDoc} */
69 | @Override
70 | public void boardUpdated(List cards, int bet, int pot) {
71 | // Not implemented.
72 | }
73 |
74 | /** {@inheritDoc} */
75 | @Override
76 | public void playerActed(Player player) {
77 | // Not implemented.
78 | }
79 |
80 | /** {@inheritDoc} */
81 | @Override
82 | public Action act(int minBet, int currentBet, Set allowedActions) {
83 | if (allowedActions.contains(Action.CHECK)) {
84 | return Action.CHECK;
85 | } else {
86 | return Action.CALL;
87 | }
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/AmountPanel.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.GridBagConstraints;
21 | import java.awt.GridBagLayout;
22 | import java.awt.Insets;
23 | import java.awt.event.ActionEvent;
24 | import java.awt.event.ActionListener;
25 | import java.util.HashMap;
26 |
27 | import javax.swing.JButton;
28 | import javax.swing.JLabel;
29 | import javax.swing.JPanel;
30 | import javax.swing.JSlider;
31 | import javax.swing.event.ChangeEvent;
32 | import javax.swing.event.ChangeListener;
33 |
34 | import org.ozsoft.texasholdem.actions.Action;
35 |
36 | /**
37 | * Panel for selecting the amount to bet or raise.
38 | *
39 | * @author Oscar Stigter
40 | */
41 | public class AmountPanel extends JPanel implements ChangeListener, ActionListener {
42 |
43 | /** Serial version UID. */
44 | private static final long serialVersionUID = 171860711156799253L;
45 |
46 | /** Number of increasing amounts to choose from (ticks on slider bar). */
47 | private static final int NO_OF_TICKS = 10;
48 |
49 | /** Slider with the amount to bet or raise. */
50 | private final JSlider amountSlider;
51 |
52 | /** Label with selected amount. */
53 | private final JLabel amountLabel;
54 |
55 | /** Bet/Raise button. */
56 | private final JButton betRaiseButton;
57 |
58 | /** Cancel button. */
59 | private final JButton cancelButton;
60 |
61 | /** Incremental bet amounts mapped to slider's index. */
62 | private final HashMap sliderAmounts;
63 |
64 | /** Monitor while waiting for user input. */
65 | private final Object monitor = new Object();
66 |
67 | private Action defaultAction;
68 |
69 | /** The selected action. */
70 | private Action selectedAction;
71 |
72 | /**
73 | * Constructor.
74 | */
75 | public AmountPanel() {
76 | setBackground(UIConstants.TABLE_COLOR);
77 |
78 | sliderAmounts = new HashMap();
79 |
80 | setLayout(new GridBagLayout());
81 | GridBagConstraints gbc = new GridBagConstraints();
82 |
83 | amountSlider = new JSlider();
84 | amountSlider.setBackground(UIConstants.TABLE_COLOR);
85 | amountSlider.setMajorTickSpacing(1);
86 | amountSlider.setMinorTickSpacing(1);
87 | amountSlider.setPaintTicks(true);
88 | amountSlider.setSnapToTicks(true);
89 | amountSlider.addChangeListener(this);
90 | gbc.gridx = 0;
91 | gbc.gridy = 0;
92 | gbc.gridwidth = 2;
93 | gbc.gridheight = 1;
94 | gbc.weightx = 0.0;
95 | gbc.weighty = 0.0;
96 | gbc.anchor = GridBagConstraints.CENTER;
97 | gbc.fill = GridBagConstraints.NONE;
98 | gbc.insets = new Insets(0, 0, 0, 5);
99 | add(amountSlider, gbc);
100 |
101 | amountLabel = new JLabel(" ");
102 | amountLabel.setForeground(UIConstants.TEXT_COLOR);
103 | gbc.gridx = 0;
104 | gbc.gridy = 1;
105 | gbc.gridwidth = 2;
106 | gbc.gridheight = 1;
107 | gbc.weightx = 0.0;
108 | gbc.weighty = 0.0;
109 | gbc.anchor = GridBagConstraints.CENTER;
110 | gbc.fill = GridBagConstraints.NONE;
111 | gbc.insets = new Insets(5, 0, 5, 0);
112 | add(amountLabel, gbc);
113 |
114 | betRaiseButton = new JButton("Bet");
115 | betRaiseButton.addActionListener(this);
116 | gbc.gridx = 0;
117 | gbc.gridy = 2;
118 | gbc.gridwidth = 1;
119 | gbc.gridheight = 1;
120 | gbc.weightx = 0.0;
121 | gbc.weighty = 0.0;
122 | gbc.anchor = GridBagConstraints.CENTER;
123 | gbc.fill = GridBagConstraints.NONE;
124 | gbc.insets = new Insets(0, 0, 0, 0);
125 | add(betRaiseButton, gbc);
126 |
127 | cancelButton = new JButton("Cancel");
128 | cancelButton.addActionListener(this);
129 | gbc.gridx = 1;
130 | gbc.gridy = 2;
131 | gbc.gridwidth = 1;
132 | gbc.gridheight = 1;
133 | gbc.weightx = 0.0;
134 | gbc.weighty = 0.0;
135 | gbc.anchor = GridBagConstraints.CENTER;
136 | gbc.fill = GridBagConstraints.NONE;
137 | gbc.insets = new Insets(0, 0, 0, 0);
138 | add(cancelButton, gbc);
139 | }
140 |
141 | /**
142 | * Resets and shows the panel.
143 | *
144 | * @param defaultAction
145 | * The default action.
146 | * @param minBet
147 | * The minimum bet.
148 | * @param maxBet
149 | * The maximum bet.
150 | *
151 | * @return The selected action.
152 | */
153 | public Action show(Action defaultAction, int minBet, int maxBet) {
154 | this.defaultAction = defaultAction;
155 | betRaiseButton.setText(defaultAction.getName());
156 | selectedAction = null;
157 |
158 | // Determine incremental amounts on slider bar.
159 | sliderAmounts.clear();
160 | int noOfValues = 0;
161 | int value = minBet;
162 | while (value < maxBet && noOfValues < (NO_OF_TICKS - 1)) {
163 | sliderAmounts.put(noOfValues, value);
164 | noOfValues++;
165 | value *= 2;
166 | }
167 | sliderAmounts.put(noOfValues, maxBet);
168 | amountSlider.setMinimum(0);
169 | amountSlider.setMaximum(noOfValues);
170 | amountSlider.setValue(0);
171 |
172 | // Wait for the user to select an amount or cancel.
173 | synchronized (monitor) {
174 | try {
175 | monitor.wait();
176 | } catch (InterruptedException e) {
177 | // Ignore.
178 | }
179 | }
180 |
181 | return selectedAction;
182 | }
183 |
184 | /**
185 | * Returns the selected amount.
186 | *
187 | * @return The selected amount.
188 | */
189 | public int getAmount() {
190 | int index = amountSlider.getValue();
191 | return sliderAmounts.get(index);
192 | }
193 |
194 | /** {@inheritDoc} */
195 | @Override
196 | public void stateChanged(ChangeEvent e) {
197 | int index = amountSlider.getValue();
198 | int amount = sliderAmounts.get(index);
199 | amountLabel.setText(String.format("$ %d", amount));
200 | }
201 |
202 | /** {@inheritDoc} */
203 | @Override
204 | public void actionPerformed(ActionEvent e) {
205 | if (e.getSource() == betRaiseButton) {
206 | selectedAction = defaultAction;
207 | } else if (e.getSource() == cancelButton) {
208 | selectedAction = null;
209 | }
210 |
211 | synchronized (monitor) {
212 | monitor.notifyAll();
213 | }
214 | }
215 |
216 | }
217 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/BoardPanel.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.Color;
21 | import java.awt.Dimension;
22 | import java.awt.GridBagConstraints;
23 | import java.awt.GridBagLayout;
24 | import java.awt.Insets;
25 | import java.util.List;
26 |
27 | import javax.swing.JLabel;
28 | import javax.swing.JPanel;
29 |
30 | import org.ozsoft.texasholdem.Card;
31 |
32 | /**
33 | * Board panel with the community cards and general information.
34 | *
35 | * @author Oscar Stigter
36 | */
37 | public class BoardPanel extends JPanel {
38 |
39 | /** The serial version UID. */
40 | private static final long serialVersionUID = 8530615901667282755L;
41 |
42 | /** The maximum number of community cards. */
43 | private static final int NO_OF_CARDS = 5;
44 |
45 | /** The control panel. */
46 | private final ControlPanel controlPanel;
47 |
48 | /** Label with the bet. */
49 | private final JLabel betLabel;
50 |
51 | /** Label with the pot. */
52 | private final JLabel potLabel;
53 |
54 | /** Labels with the community cards. */
55 | private final JLabel[] cardLabels;
56 |
57 | /** Label with a custom message. */
58 | private final JLabel messageLabel;
59 |
60 | /**
61 | * Constructor.
62 | *
63 | * @param controlPanel
64 | * The control panel.
65 | */
66 | public BoardPanel(ControlPanel controlPanel) {
67 | this.controlPanel = controlPanel;
68 |
69 | setBorder(UIConstants.PANEL_BORDER);
70 | setBackground(UIConstants.TABLE_COLOR);
71 | setLayout(new GridBagLayout());
72 | GridBagConstraints gc = new GridBagConstraints();
73 |
74 | JLabel label = new JLabel("Bet");
75 | label.setForeground(Color.GREEN);
76 | gc.gridx = 1;
77 | gc.gridy = 0;
78 | gc.gridwidth = 1;
79 | gc.gridheight = 1;
80 | gc.anchor = GridBagConstraints.CENTER;
81 | gc.fill = GridBagConstraints.NONE;
82 | gc.weightx = 1.0;
83 | gc.weighty = 0.0;
84 | gc.insets = new Insets(0, 5, 0, 5);
85 | add(label, gc);
86 |
87 | label = new JLabel("Pot");
88 | label.setForeground(Color.GREEN);
89 | gc.gridx = 3;
90 | gc.gridy = 0;
91 | gc.gridwidth = 1;
92 | gc.gridheight = 1;
93 | gc.anchor = GridBagConstraints.CENTER;
94 | gc.fill = GridBagConstraints.NONE;
95 | gc.weightx = 1.0;
96 | gc.weighty = 0.0;
97 | gc.insets = new Insets(0, 5, 0, 5);
98 | add(label, gc);
99 |
100 | betLabel = new JLabel(" ");
101 | betLabel.setBorder(UIConstants.LABEL_BORDER);
102 | betLabel.setForeground(Color.GREEN);
103 | betLabel.setHorizontalAlignment(JLabel.CENTER);
104 | gc.gridx = 1;
105 | gc.gridy = 1;
106 | gc.gridwidth = 1;
107 | gc.gridheight = 1;
108 | gc.anchor = GridBagConstraints.CENTER;
109 | gc.fill = GridBagConstraints.HORIZONTAL;
110 | gc.weightx = 1.0;
111 | gc.weighty = 0.0;
112 | gc.insets = new Insets(5, 5, 5, 5);
113 | add(betLabel, gc);
114 |
115 | potLabel = new JLabel(" ");
116 | potLabel.setBorder(UIConstants.LABEL_BORDER);
117 | potLabel.setForeground(Color.GREEN);
118 | potLabel.setHorizontalAlignment(JLabel.CENTER);
119 | gc.gridx = 3;
120 | gc.gridy = 1;
121 | gc.gridwidth = 1;
122 | gc.gridheight = 1;
123 | gc.anchor = GridBagConstraints.CENTER;
124 | gc.fill = GridBagConstraints.HORIZONTAL;
125 | gc.weightx = 1.0;
126 | gc.weighty = 0.0;
127 | gc.insets = new Insets(5, 5, 5, 5);
128 | add(potLabel, gc);
129 |
130 | // The five card positions.
131 | cardLabels = new JLabel[NO_OF_CARDS];
132 | for (int i = 0; i < 5; i++) {
133 | cardLabels[i] = new JLabel(ResourceManager.getIcon("/images/card_placeholder.png"));
134 | gc.gridx = i;
135 | gc.gridy = 2;
136 | gc.gridwidth = 1;
137 | gc.gridheight = 1;
138 | gc.anchor = GridBagConstraints.CENTER;
139 | gc.fill = GridBagConstraints.NONE;
140 | gc.weightx = 0.0;
141 | gc.weighty = 0.0;
142 | gc.insets = new Insets(5, 1, 5, 1);
143 | add(cardLabels[i], gc);
144 | }
145 |
146 | // Message label.
147 | messageLabel = new JLabel();
148 | messageLabel.setForeground(Color.YELLOW);
149 | messageLabel.setHorizontalAlignment(JLabel.CENTER);
150 | gc.gridx = 0;
151 | gc.gridy = 3;
152 | gc.gridwidth = 5;
153 | gc.gridheight = 1;
154 | gc.anchor = GridBagConstraints.CENTER;
155 | gc.fill = GridBagConstraints.HORIZONTAL;
156 | gc.weightx = 1.0;
157 | gc.weighty = 1.0;
158 | gc.insets = new Insets(0, 0, 0, 0);
159 | add(messageLabel, gc);
160 |
161 | // Control panel.
162 | gc.gridx = 0;
163 | gc.gridy = 4;
164 | gc.gridwidth = 5;
165 | gc.gridheight = 1;
166 | gc.insets = new Insets(0, 0, 0, 0);
167 | gc.anchor = GridBagConstraints.CENTER;
168 | gc.fill = GridBagConstraints.BOTH;
169 | gc.weightx = 1.0;
170 | gc.weighty = 1.0;
171 | add(controlPanel, gc);
172 |
173 | setPreferredSize(new Dimension(400, 270));
174 |
175 | update(null, 0, 0);
176 | }
177 |
178 | /**
179 | * Updates the current hand status.
180 | *
181 | * @param bet
182 | * The bet.
183 | * @param pot
184 | * The pot.
185 | */
186 | public void update(List cards, int bet, int pot) {
187 | if (bet == 0) {
188 | betLabel.setText(" ");
189 | } else {
190 | betLabel.setText("$ " + bet);
191 | }
192 | if (pot == 0) {
193 | potLabel.setText(" ");
194 | } else {
195 | potLabel.setText("$ " + pot);
196 | }
197 | int noOfCards = (cards == null) ? 0 : cards.size();
198 | for (int i = 0; i < NO_OF_CARDS; i++) {
199 | if (i < noOfCards) {
200 | cardLabels[i].setIcon(ResourceManager.getCardImage(cards.get(i)));
201 | } else {
202 | cardLabels[i].setIcon(ResourceManager.getIcon("/images/card_placeholder.png"));
203 | }
204 | }
205 | }
206 |
207 | /**
208 | * Sets a custom message.
209 | *
210 | * @param message
211 | * The message.
212 | */
213 | public void setMessage(String message) {
214 | if (message.length() == 0) {
215 | messageLabel.setText(" ");
216 | } else {
217 | messageLabel.setText(message);
218 | }
219 | }
220 |
221 | /**
222 | * Waits for the user to continue.
223 | */
224 | public void waitForUserInput() {
225 | controlPanel.waitForUserInput();
226 | }
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/ControlPanel.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.event.ActionEvent;
21 | import java.awt.event.ActionListener;
22 | import java.util.HashSet;
23 | import java.util.Set;
24 |
25 | import javax.swing.JButton;
26 | import javax.swing.JPanel;
27 | import javax.swing.SwingUtilities;
28 |
29 | import org.ozsoft.texasholdem.TableType;
30 | import org.ozsoft.texasholdem.actions.Action;
31 | import org.ozsoft.texasholdem.actions.BetAction;
32 | import org.ozsoft.texasholdem.actions.RaiseAction;
33 |
34 | /**
35 | * Panel with buttons to let a human player select an action.
36 | *
37 | * @author Oscar Stigter
38 | */
39 | public class ControlPanel extends JPanel implements ActionListener {
40 |
41 | /** Serial version UID. */
42 | private static final long serialVersionUID = 4059653681621749416L;
43 |
44 | /** The table type (betting structure). */
45 | private final TableType tableType;
46 |
47 | /** The Check button. */
48 | private final JButton checkButton;
49 |
50 | /** The Call button. */
51 | private final JButton callButton;
52 |
53 | /** The Bet button. */
54 | private final JButton betButton;
55 |
56 | /** The Raise button. */
57 | private final JButton raiseButton;
58 |
59 | /** The Fold button. */
60 | private final JButton foldButton;
61 |
62 | /** The Continue button. */
63 | private final JButton continueButton;
64 |
65 | /** The betting panel. */
66 | private final AmountPanel amountPanel;
67 |
68 | /** Monitor while waiting for user input. */
69 | private final Object monitor = new Object();
70 |
71 | /** The selected action. */
72 | private Action selectedAction;
73 |
74 | /**
75 | * Constructor.
76 | */
77 | public ControlPanel(TableType tableType) {
78 | this.tableType = tableType;
79 | setBackground(UIConstants.TABLE_COLOR);
80 | continueButton = createActionButton(Action.CONTINUE);
81 | checkButton = createActionButton(Action.CHECK);
82 | callButton = createActionButton(Action.CALL);
83 | betButton = createActionButton(Action.BET);
84 | raiseButton = createActionButton(Action.RAISE);
85 | foldButton = createActionButton(Action.FOLD);
86 | amountPanel = new AmountPanel();
87 | }
88 |
89 | /**
90 | * Waits for the user to click the Continue button.
91 | */
92 | public void waitForUserInput() {
93 | SwingUtilities.invokeLater(new Runnable() {
94 | @Override
95 | public void run() {
96 | removeAll();
97 | add(continueButton);
98 | repaint();
99 | }
100 | });
101 | Set allowedActions = new HashSet();
102 | allowedActions.add(Action.CONTINUE);
103 | getUserInput(0, 0, allowedActions);
104 | }
105 |
106 | /**
107 | * Waits for the user to click an action button and returns the selected
108 | * action.
109 | *
110 | * @param minBet
111 | * The minimum bet.
112 | * @param cash
113 | * The player's remaining cash.
114 | * @param allowedActions
115 | * The allowed actions.
116 | *
117 | * @return The selected action.
118 | */
119 | public Action getUserInput(int minBet, int cash, final Set allowedActions) {
120 | selectedAction = null;
121 | while (selectedAction == null) {
122 | // Show the buttons for the allowed actions.
123 | SwingUtilities.invokeLater(new Runnable() {
124 | @Override
125 | public void run() {
126 | removeAll();
127 | if (allowedActions.contains(Action.CONTINUE)) {
128 | add(continueButton);
129 | } else {
130 | if (allowedActions.contains(Action.CHECK)) {
131 | add(checkButton);
132 | }
133 | if (allowedActions.contains(Action.CALL)) {
134 | add(callButton);
135 | }
136 | if (allowedActions.contains(Action.BET)) {
137 | add(betButton);
138 | }
139 | if (allowedActions.contains(Action.RAISE)) {
140 | add(raiseButton);
141 | }
142 | if (allowedActions.contains(Action.FOLD)) {
143 | add(foldButton);
144 | }
145 | }
146 | repaint();
147 | }
148 | });
149 |
150 | // Wait for the user to select an action.
151 | synchronized (monitor) {
152 | try {
153 | monitor.wait();
154 | } catch (InterruptedException e) {
155 | // Ignore.
156 | }
157 | }
158 |
159 | // In case of a bet or raise, show panel to select amount.
160 | if (tableType == TableType.NO_LIMIT && (selectedAction == Action.BET || selectedAction == Action.RAISE)) {
161 | SwingUtilities.invokeLater(new Runnable() {
162 | @Override
163 | public void run() {
164 | removeAll();
165 | add(amountPanel);
166 | repaint();
167 | }
168 | });
169 | selectedAction = amountPanel.show(selectedAction, minBet, cash);
170 | if (selectedAction == Action.BET) {
171 | selectedAction = new BetAction(amountPanel.getAmount());
172 | } else if (selectedAction == Action.RAISE) {
173 | selectedAction = new RaiseAction(amountPanel.getAmount());
174 | } else {
175 | // User cancelled.
176 | selectedAction = null;
177 | }
178 | }
179 | }
180 |
181 | return selectedAction;
182 | }
183 |
184 | /*
185 | * (non-Javadoc)
186 | * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
187 | */
188 | @Override
189 | public void actionPerformed(ActionEvent e) {
190 | Object source = e.getSource();
191 | if (source == continueButton) {
192 | selectedAction = Action.CONTINUE;
193 | } else if (source == checkButton) {
194 | selectedAction = Action.CHECK;
195 | } else if (source == callButton) {
196 | selectedAction = Action.CALL;
197 | } else if (source == betButton) {
198 | selectedAction = Action.BET;
199 | } else if (source == raiseButton) {
200 | selectedAction = Action.RAISE;
201 | } else {
202 | selectedAction = Action.FOLD;
203 | }
204 | synchronized (monitor) {
205 | monitor.notifyAll();
206 | }
207 | }
208 |
209 | /**
210 | * Creates an action button.
211 | *
212 | * @param action
213 | * The action.
214 | *
215 | * @return The button.
216 | */
217 | private JButton createActionButton(Action action) {
218 | String label = action.getName();
219 | JButton button = new JButton(label);
220 | button.setMnemonic(label.charAt(0));
221 | button.setSize(100, 30);
222 | button.addActionListener(this);
223 | return button;
224 | }
225 |
226 | }
227 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/Main.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.Component;
21 | import java.awt.GridBagConstraints;
22 | import java.awt.GridBagLayout;
23 | import java.util.HashMap;
24 | import java.util.LinkedHashMap;
25 | import java.util.List;
26 | import java.util.Map;
27 | import java.util.Set;
28 |
29 | import javax.swing.JFrame;
30 |
31 | import org.ozsoft.texasholdem.Card;
32 | import org.ozsoft.texasholdem.Client;
33 | import org.ozsoft.texasholdem.Player;
34 | import org.ozsoft.texasholdem.Table;
35 | import org.ozsoft.texasholdem.TableType;
36 | import org.ozsoft.texasholdem.actions.Action;
37 | import org.ozsoft.texasholdem.bots.BasicBot;
38 |
39 | /**
40 | * The game's main frame.
41 | *
42 | * This is the core class of the Swing UI client application.
43 | *
44 | * @author Oscar Stigter
45 | */
46 | public class Main extends JFrame implements Client {
47 |
48 | /** Serial version UID. */
49 | private static final long serialVersionUID = -5414633931666096443L;
50 |
51 | /** Table type (betting structure). */
52 | private static final TableType TABLE_TYPE = TableType.NO_LIMIT;
53 |
54 | /** The size of the big blind. */
55 | private static final int BIG_BLIND = 10;
56 |
57 | /** The starting cash per player. */
58 | private static final int STARTING_CASH = 500;
59 |
60 | /** The table. */
61 | private final Table table;
62 |
63 | /** The players at the table. */
64 | private final Map players;
65 |
66 | /** The GridBagConstraints. */
67 | private final GridBagConstraints gc;
68 |
69 | /** The board panel. */
70 | private final BoardPanel boardPanel;
71 |
72 | /** The control panel. */
73 | private final ControlPanel controlPanel;
74 |
75 | /** The player panels. */
76 | private final Map playerPanels;
77 |
78 | /** The human player. */
79 | private final Player humanPlayer;
80 |
81 | /** The current dealer's name. */
82 | private String dealerName;
83 |
84 | /** The current actor's name. */
85 | private String actorName;
86 |
87 | /**
88 | * Constructor.
89 | */
90 | public Main() {
91 | super("Texas Hold'em poker");
92 |
93 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
94 | getContentPane().setBackground(UIConstants.TABLE_COLOR);
95 | setLayout(new GridBagLayout());
96 |
97 | gc = new GridBagConstraints();
98 |
99 | controlPanel = new ControlPanel(TABLE_TYPE);
100 |
101 | boardPanel = new BoardPanel(controlPanel);
102 | addComponent(boardPanel, 1, 1, 1, 1);
103 |
104 | players = new LinkedHashMap();
105 | humanPlayer = new Player("Player", STARTING_CASH, this);
106 | players.put("Player", humanPlayer);
107 | players.put("Joe", new Player("Joe", STARTING_CASH, new BasicBot(0, 75)));
108 | players.put("Mike", new Player("Mike", STARTING_CASH, new BasicBot(25, 50)));
109 | players.put("Eddie", new Player("Eddie", STARTING_CASH, new BasicBot(50, 25)));
110 |
111 | table = new Table(TABLE_TYPE, BIG_BLIND);
112 | for (Player player : players.values()) {
113 | table.addPlayer(player);
114 | }
115 |
116 | playerPanels = new HashMap();
117 | int i = 0;
118 | for (Player player : players.values()) {
119 | PlayerPanel panel = new PlayerPanel();
120 | playerPanels.put(player.getName(), panel);
121 | switch (i++) {
122 | case 0:
123 | // North position.
124 | addComponent(panel, 1, 0, 1, 1);
125 | break;
126 | case 1:
127 | // East position.
128 | addComponent(panel, 2, 1, 1, 1);
129 | break;
130 | case 2:
131 | // South position.
132 | addComponent(panel, 1, 2, 1, 1);
133 | break;
134 | case 3:
135 | // West position.
136 | addComponent(panel, 0, 1, 1, 1);
137 | break;
138 | default:
139 | // Do nothing.
140 | }
141 | }
142 |
143 | // Show the frame.
144 | pack();
145 | setResizable(false);
146 | setLocationRelativeTo(null);
147 | setVisible(true);
148 |
149 | // Start the game.
150 | table.run();
151 | }
152 |
153 | /**
154 | * The application's entry point.
155 | *
156 | * @param args
157 | * The command line arguments.
158 | */
159 | public static void main(String[] args) {
160 | new Main();
161 | }
162 |
163 | @Override
164 | public void joinedTable(TableType type, int bigBlind, List players) {
165 | for (Player player : players) {
166 | PlayerPanel playerPanel = playerPanels.get(player.getName());
167 | if (playerPanel != null) {
168 | playerPanel.update(player);
169 | }
170 | }
171 | }
172 |
173 | @Override
174 | public void messageReceived(String message) {
175 | boardPanel.setMessage(message);
176 | boardPanel.waitForUserInput();
177 | }
178 |
179 | @Override
180 | public void handStarted(Player dealer) {
181 | setDealer(false);
182 | dealerName = dealer.getName();
183 | setDealer(true);
184 | }
185 |
186 | @Override
187 | public void actorRotated(Player actor) {
188 | setActorInTurn(false);
189 | actorName = actor.getName();
190 | setActorInTurn(true);
191 | }
192 |
193 | @Override
194 | public void boardUpdated(List cards, int bet, int pot) {
195 | boardPanel.update(cards, bet, pot);
196 | }
197 |
198 | @Override
199 | public void playerUpdated(Player player) {
200 | PlayerPanel playerPanel = playerPanels.get(player.getName());
201 | if (playerPanel != null) {
202 | playerPanel.update(player);
203 | }
204 | }
205 |
206 | @Override
207 | public void playerActed(Player player) {
208 | String name = player.getName();
209 | PlayerPanel playerPanel = playerPanels.get(name);
210 | if (playerPanel != null) {
211 | playerPanel.update(player);
212 | Action action = player.getAction();
213 | if (action != null) {
214 | boardPanel.setMessage(String.format("%s %s.", name, action.getVerb()));
215 | if (player.getClient() != this) {
216 | boardPanel.waitForUserInput();
217 | }
218 | }
219 | } else {
220 | throw new IllegalStateException(
221 | String.format("No PlayerPanel found for player '%s'", name));
222 | }
223 | }
224 |
225 | @Override
226 | public Action act(int minBet, int currentBet, Set allowedActions) {
227 | boardPanel.setMessage("Please select an action:");
228 | return controlPanel.getUserInput(minBet, humanPlayer.getCash(), allowedActions);
229 | }
230 |
231 | /**
232 | * Adds an UI component.
233 | *
234 | * @param component
235 | * The component.
236 | * @param x
237 | * The column.
238 | * @param y
239 | * The row.
240 | * @param width
241 | * The number of columns to span.
242 | * @param height
243 | * The number of rows to span.
244 | */
245 | private void addComponent(Component component, int x, int y, int width, int height) {
246 | gc.gridx = x;
247 | gc.gridy = y;
248 | gc.gridwidth = width;
249 | gc.gridheight = height;
250 | gc.anchor = GridBagConstraints.CENTER;
251 | gc.fill = GridBagConstraints.NONE;
252 | gc.weightx = 0.0;
253 | gc.weighty = 0.0;
254 | getContentPane().add(component, gc);
255 | }
256 |
257 | /**
258 | * Sets whether the actor is in turn.
259 | *
260 | * @param isInTurn
261 | * Whether the actor is in turn.
262 | */
263 | private void setActorInTurn(boolean isInTurn) {
264 | if (actorName != null) {
265 | PlayerPanel playerPanel = playerPanels.get(actorName);
266 | if (playerPanel != null) {
267 | playerPanel.setInTurn(isInTurn);
268 | }
269 | }
270 | }
271 |
272 | /**
273 | * Sets the dealer.
274 | *
275 | * @param isDealer
276 | * Whether the player is the dealer.
277 | */
278 | private void setDealer(boolean isDealer) {
279 | if (dealerName != null) {
280 | PlayerPanel playerPanel = playerPanels.get(dealerName);
281 | if (playerPanel != null) {
282 | playerPanel.setDealer(isDealer);
283 | }
284 | }
285 | }
286 |
287 | }
288 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/PlayerPanel.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.Color;
21 | import java.awt.GridBagConstraints;
22 | import java.awt.GridBagLayout;
23 | import java.awt.Insets;
24 |
25 | import javax.swing.Icon;
26 | import javax.swing.JLabel;
27 | import javax.swing.JPanel;
28 | import javax.swing.border.Border;
29 | import javax.swing.border.EmptyBorder;
30 |
31 | import org.ozsoft.texasholdem.Card;
32 | import org.ozsoft.texasholdem.Player;
33 | import org.ozsoft.texasholdem.actions.Action;
34 |
35 | /**
36 | * Panel representing a player at the table.
37 | *
38 | * @author Oscar Stigter
39 | */
40 | public class PlayerPanel extends JPanel {
41 |
42 | /** The serial version UID. */
43 | private static final long serialVersionUID = 5851738752943098606L;
44 |
45 | /** Filled dealer button image when player is dealer. */
46 | private static final Icon BUTTON_PRESENT_ICON =
47 | ResourceManager.getIcon("/images/button_present.png");
48 |
49 | /** Empty dealer button image when player is not dealer. */
50 | private static final Icon BUTTON_ABSENT_ICON =
51 | ResourceManager.getIcon("/images/button_absent.png");
52 |
53 | private static final Icon CARD_PLACEHOLDER_ICON =
54 | ResourceManager.getIcon("/images/card_placeholder.png");
55 |
56 | private static final Icon CARD_BACK_ICON =
57 | ResourceManager.getIcon("/images/card_back.png");
58 |
59 | /** The border. */
60 | private static final Border BORDER = new EmptyBorder(10, 10, 10, 10);
61 |
62 | /** The label with the player's name. */
63 | private JLabel nameLabel;
64 |
65 | /** The label with the player's amount of cash. */
66 | private JLabel cashLabel;
67 |
68 | /** The label with the last action performed. */
69 | private JLabel actionLabel;
70 |
71 | /** The label with the player's current bet. */
72 | private JLabel betLabel;
73 |
74 | /** The label for the first hole card. */
75 | private JLabel card1Label;
76 |
77 | /** The label for the second hole card. */
78 | private JLabel card2Label;
79 |
80 | /** The label for the dealer button image. */
81 | private JLabel dealerButton;
82 |
83 | /**
84 | * Constructor.
85 | */
86 | public PlayerPanel() {
87 | setBorder(BORDER);
88 | setBackground(UIConstants.TABLE_COLOR);
89 | setLayout(new GridBagLayout());
90 | GridBagConstraints gc = new GridBagConstraints();
91 |
92 | nameLabel = new MyLabel();
93 | cashLabel = new MyLabel();
94 | actionLabel = new MyLabel();
95 | betLabel = new MyLabel();
96 | card1Label = new JLabel(CARD_PLACEHOLDER_ICON);
97 | card2Label = new JLabel(CARD_PLACEHOLDER_ICON);
98 | dealerButton = new JLabel(BUTTON_ABSENT_ICON);
99 |
100 | gc.gridx = 0;
101 | gc.gridy = 0;
102 | gc.gridwidth = 2;
103 | gc.gridheight = 1;
104 | gc.weightx = 1.0;
105 | gc.weighty = 1.0;
106 | gc.anchor = GridBagConstraints.CENTER;
107 | gc.fill = GridBagConstraints.NONE;
108 | add(dealerButton, gc);
109 | gc.gridx = 0;
110 | gc.gridy = 1;
111 | gc.gridwidth = 1;
112 | gc.gridheight = 1;
113 | gc.insets = new Insets(1, 1, 1, 1);
114 | gc.anchor = GridBagConstraints.CENTER;
115 | gc.fill = GridBagConstraints.HORIZONTAL;
116 | gc.weightx = 1.0;
117 | gc.weighty = 1.0;
118 | add(nameLabel, gc);
119 | gc.gridx = 1;
120 | gc.gridy = 1;
121 | gc.gridwidth = 1;
122 | gc.gridheight = 1;
123 | gc.weightx = 1.0;
124 | gc.weighty = 1.0;
125 | gc.anchor = GridBagConstraints.CENTER;
126 | gc.fill = GridBagConstraints.HORIZONTAL;
127 | add(cashLabel, gc);
128 | gc.gridx = 0;
129 | gc.gridy = 2;
130 | gc.gridwidth = 1;
131 | gc.gridheight = 1;
132 | gc.weightx = 1.0;
133 | gc.weighty = 1.0;
134 | gc.anchor = GridBagConstraints.CENTER;
135 | gc.fill = GridBagConstraints.HORIZONTAL;
136 | add(actionLabel, gc);
137 | gc.gridx = 1;
138 | gc.gridy = 2;
139 | gc.gridwidth = 1;
140 | gc.gridheight = 1;
141 | gc.weightx = 1.0;
142 | gc.weighty = 1.0;
143 | gc.anchor = GridBagConstraints.CENTER;
144 | gc.fill = GridBagConstraints.HORIZONTAL;
145 | add(betLabel, gc);
146 | gc.gridx = 0;
147 | gc.gridy = 3;
148 | gc.gridwidth = 1;
149 | gc.gridheight = 1;
150 | gc.weightx = 1.0;
151 | gc.weighty = 1.0;
152 | gc.anchor = GridBagConstraints.CENTER;
153 | gc.fill = GridBagConstraints.NONE;
154 | add(card1Label, gc);
155 | gc.gridx = 1;
156 | gc.gridy = 3;
157 | gc.gridwidth = 1;
158 | gc.gridheight = 1;
159 | gc.weightx = 1.0;
160 | gc.weighty = 1.0;
161 | gc.anchor = GridBagConstraints.CENTER;
162 | gc.fill = GridBagConstraints.NONE;
163 | add(card2Label, gc);
164 |
165 | setInTurn(false);
166 | setDealer(false);
167 | }
168 |
169 | /**
170 | * Updates the panel.
171 | *
172 | * @param player
173 | * The player.
174 | */
175 | public void update(Player player) {
176 | nameLabel.setText(player.getName());
177 | cashLabel.setText("$ " + player.getCash());
178 | int bet = player.getBet();
179 | if (bet == 0) {
180 | betLabel.setText(" ");
181 | } else {
182 | betLabel.setText("$ " + bet);
183 | }
184 | Action action = player.getAction();
185 | if (action != null) {
186 | actionLabel.setText(action.getName());
187 | } else {
188 | actionLabel.setText(" ");
189 | }
190 | if (player.hasCards()) {
191 | Card[] cards = player.getCards();
192 | if (cards.length == 2) {
193 | // Visible cards.
194 | card1Label.setIcon(ResourceManager.getCardImage(cards[0]));
195 | card2Label.setIcon(ResourceManager.getCardImage(cards[1]));
196 | } else {
197 | // Hidden cards (face-down).
198 | card1Label.setIcon(CARD_BACK_ICON);
199 | card2Label.setIcon(CARD_BACK_ICON);
200 | }
201 | } else {
202 | // No cards.
203 | card1Label.setIcon(CARD_PLACEHOLDER_ICON);
204 | card2Label.setIcon(CARD_PLACEHOLDER_ICON);
205 | }
206 | }
207 |
208 | /**
209 | * Sets whether the player is the dealer.
210 | *
211 | * @param isDealer
212 | * True if the dealer, otherwise false.
213 | */
214 | public void setDealer(boolean isDealer) {
215 | if (isDealer) {
216 | dealerButton.setIcon(BUTTON_PRESENT_ICON);
217 | } else {
218 | dealerButton.setIcon(BUTTON_ABSENT_ICON);
219 | }
220 | }
221 |
222 | /**
223 | * Sets whether it's this player's turn to act.
224 | *
225 | * @param inTurn
226 | * True if it's the player's turn, otherwise false.
227 | */
228 | public void setInTurn(boolean inTurn) {
229 | if (inTurn) {
230 | nameLabel.setForeground(Color.YELLOW);
231 | } else {
232 | nameLabel.setForeground(Color.GREEN);
233 | }
234 | }
235 |
236 | /**
237 | * Custom label for a player panel.
238 | *
239 | * @author Oscar Stigter
240 | */
241 | private static class MyLabel extends JLabel {
242 |
243 | /** Serial version UID. */
244 | private static final long serialVersionUID = 3607645928062082095L;
245 |
246 | /**
247 | * Constructor.
248 | */
249 | public MyLabel() {
250 | setBorder(UIConstants.LABEL_BORDER);
251 | setForeground(UIConstants.TEXT_COLOR);
252 | setHorizontalAlignment(JLabel.HORIZONTAL);
253 | setText(" ");
254 | }
255 |
256 | } // MyLabel
257 |
258 | }
259 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/ResourceManager.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.net.URL;
21 |
22 | import javax.swing.ImageIcon;
23 |
24 | import org.ozsoft.texasholdem.Card;
25 |
26 | /**
27 | * Utility class responsible for retrieving resource files.
28 | *
29 | * @author Oscar Stigter
30 | */
31 | public abstract class ResourceManager {
32 |
33 | private static final String IMAGE_PATH_FORMAT = "/images/card_%s.png";
34 |
35 | /**
36 | * Returns the image of a specific card.
37 | *
38 | * @param card
39 | * The card.
40 | *
41 | * @return The image.
42 | */
43 | public static ImageIcon getCardImage(Card card) {
44 | // Use image order, which is different from value order.
45 | int sequenceNr = card.getSuit() * Card.NO_OF_RANKS + card.getRank();
46 | String sequenceNrString = String.valueOf(sequenceNr);
47 | if (sequenceNrString.length() == 1) {
48 | sequenceNrString = "0" + sequenceNrString;
49 | }
50 | String path = String.format(IMAGE_PATH_FORMAT, sequenceNrString);
51 | return getIcon(path);
52 | }
53 |
54 | /**
55 | * Returns an image resource.
56 | *
57 | * @param path
58 | * The path on the classpath.
59 | *
60 | * @return The image resource.
61 | *
62 | * @throws RuntimeException
63 | * If the resource could not be found.
64 | */
65 | public static ImageIcon getIcon(String path) {
66 | URL url = ResourceManager.class.getResource(path);
67 | if (url != null) {
68 | return new ImageIcon(url);
69 | } else {
70 | throw new RuntimeException("Resource file not found: " + path);
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/gui/UIConstants.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.gui;
19 |
20 | import java.awt.Color;
21 |
22 | import javax.swing.border.Border;
23 | import javax.swing.border.CompoundBorder;
24 | import javax.swing.border.EmptyBorder;
25 | import javax.swing.border.LineBorder;
26 |
27 | /**
28 | * Shared UI constants.
29 | *
30 | * @author Oscar Stigter
31 | */
32 | public interface UIConstants {
33 |
34 | /** The table color. */
35 | Color TABLE_COLOR = new Color(0, 128, 0); // Dark green
36 |
37 | /** The text color. */
38 | Color TEXT_COLOR = Color.GREEN;
39 |
40 | /** The border used around labels. */
41 | Border LABEL_BORDER = new LineBorder(Color.BLACK, 1);
42 |
43 | /** The border used around panels. */
44 | Border PANEL_BORDER = new CompoundBorder(
45 | new LineBorder(Color.BLACK, 1), new EmptyBorder(10, 10, 10, 10));
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/texasholdem/src/main/java/org/ozsoft/texasholdem/util/PokerUtils.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.util;
19 |
20 | import org.ozsoft.texasholdem.Card;
21 |
22 | /**
23 | * Contains various utility methods.
24 | *
25 | * @author Oscar Stigter
26 | */
27 | public abstract class PokerUtils {
28 |
29 | /**
30 | * Returns the value of the hole cards based on the Chen formula.
31 | *
32 | * @param cards
33 | * The hole cards.
34 | *
35 | * @return The score based on the Chen formula.
36 | */
37 | public static double getChenScore(Card[] cards) {
38 | if (cards.length != 2) {
39 | throw new IllegalArgumentException("Invalid number of cards: " + cards.length);
40 | }
41 |
42 | // Analyze hole cards.
43 | int rank1 = cards[0].getRank();
44 | int suit1 = cards[0].getSuit();
45 | int rank2 = cards[1].getRank();
46 | int suit2 = cards[1].getSuit();
47 | int highRank = Math.max(rank1, rank2);
48 | int lowRank = Math.min(rank1, rank2);
49 | int rankDiff = highRank - lowRank;
50 | int gap = (rankDiff > 1) ? rankDiff - 1 : 0;
51 | boolean isPair = (rank1 == rank2);
52 | boolean isSuited = (suit1 == suit2);
53 |
54 | double score = 0.0;
55 |
56 | // 1. Base score highest rank only
57 | if (highRank == Card.ACE) {
58 | score = 10.0;
59 | } else if (highRank == Card.KING) {
60 | score = 8.0;
61 | } else if (highRank == Card.QUEEN) {
62 | score = 7.0;
63 | } else if (highRank == Card.JACK) {
64 | score = 6.0;
65 | } else {
66 | score = (highRank + 2) / 2.0;
67 | }
68 |
69 | // 2. If pair, double score, with minimum score of 5.
70 | if (isPair) {
71 | score *= 2.0;
72 | if (score < 5.0) {
73 | score = 5.0;
74 | }
75 | }
76 |
77 | // 3. If suited, add 2 points.
78 | if (isSuited) {
79 | score += 2.0;
80 | }
81 |
82 | // 4. Subtract points for gap.
83 | if (gap == 1) {
84 | score -= 1.0;
85 | } else if (gap == 2) {
86 | score -= 2.0;
87 | } else if (gap == 3) {
88 | score -= 4.0;
89 | } else if (gap > 3) {
90 | score -= 5.0;
91 | }
92 |
93 | // 5. Add 1 point for a 0 or 1 gap and both cards lower than a Queen.
94 | if (!isPair && gap < 2 && rank1 < Card.QUEEN && rank2 < Card.QUEEN) {
95 | score += 1.0;
96 | }
97 |
98 | // Minimum score is 0.
99 | if (score < 0.0) {
100 | score = 0.0;
101 | }
102 |
103 | // 6. Round half point scores up.
104 | return Math.round(score);
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/button_absent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/button_absent.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/button_present.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/button_present.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_00.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_01.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_02.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_03.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_04.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_05.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_06.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_07.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_08.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_09.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_10.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_11.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_12.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_13.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_14.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_15.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_16.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_17.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_18.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_19.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_20.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_21.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_22.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_23.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_24.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_25.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_26.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_27.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_28.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_29.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_30.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_31.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_32.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_33.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_34.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_35.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_35.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_36.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_37.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_38.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_39.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_39.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_40.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_41.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_41.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_42.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_43.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_43.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_44.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_45.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_46.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_47.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_47.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_48.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_49.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_50.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_51.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_51.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_back.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_joker_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_joker_black.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_joker_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_joker_red.png
--------------------------------------------------------------------------------
/texasholdem/src/main/resources/images/card_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ostigter/texasholdem-java/25676128d5198d289d6cd704f0a805bcffbf3d75/texasholdem/src/main/resources/images/card_placeholder.png
--------------------------------------------------------------------------------
/texasholdem/src/test/java/org/ozsoft/texasholdem/BasicBotTest.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import org.junit.Test;
21 |
22 | /**
23 | * Test suite for the BasicBot class.
24 | *
25 | * @author Oscar Stigter
26 | */
27 | public class BasicBotTest {
28 |
29 | @Test
30 | public void test() {
31 | // BasicBot bot = new BasicBot();
32 | // int value1, value2;
33 | //
34 | // bot.holeCardsUpdated(new Card[]{new Card("As"), new Card("Ah")});
35 | // value1 = bot.evaluateHoleCards();
36 | // bot.holeCardsUpdated(new Card[]{new Card("As"), new Card("Ks")});
37 | // value2 = bot.evaluateHoleCards();
38 | // Assert.assertTrue(value1 > value2);
39 | //
40 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("As"), new Card("Ah")});
41 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("Ac"), new Card("Ad")});
42 | // Assert.assertTrue(value1 == value2);
43 | //
44 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("As"), new Card("Ah")});
45 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("Ks"), new Card("Kh")});
46 | // Assert.assertTrue(value1 > value2);
47 | //
48 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("As"), new Card("Kh")});
49 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("Kd"), new Card("Kc")});
50 | // Assert.assertTrue(value1 > value2);
51 | //
52 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("Ks"), new Card("Kh")});
53 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("As"), new Card("Qs")});
54 | // Assert.assertTrue(value1 > value2);
55 | //
56 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("3d"), new Card("3c")});
57 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("2d"), new Card("2c")});
58 | // Assert.assertTrue(value1 > value2);
59 | //
60 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("4d"), new Card("3d")});
61 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("3c"), new Card("2c")});
62 | // Assert.assertTrue(value1 > value2);
63 | //
64 | // value1 = bot.evaluateHoleCards(new Card[]{new Card("2d"), new Card("2c")});
65 | // value2 = bot.evaluateHoleCards(new Card[]{new Card("3d"), new Card("2s")});
66 | // Assert.assertTrue(value1 > value2);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/texasholdem/src/test/java/org/ozsoft/texasholdem/CardTest.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 |
23 | /**
24 | * Test suite for the Card class.
25 | *
26 | * @author Oscar Stigter
27 | */
28 | public class CardTest {
29 |
30 | /**
31 | * Tests the basics (good-weather).
32 | */
33 | @Test
34 | public void basics() {
35 | Card card = new Card(Card.TEN, Card.HEARTS);
36 | Assert.assertNotNull(card);
37 | Assert.assertEquals(Card.TEN, card.getRank());
38 | Assert.assertEquals(Card.HEARTS, card.getSuit());
39 | Assert.assertEquals("Th", card.toString());
40 | card = new Card(" As "); // Automatic trimming.
41 | Assert.assertNotNull(card);
42 | Assert.assertEquals(Card.ACE, card.getRank());
43 | Assert.assertEquals(Card.SPADES, card.getSuit());
44 | Assert.assertEquals("As", card.toString());
45 | }
46 |
47 | /**
48 | * Tests the constructors (bad-weather).
49 | */
50 | @Test
51 | public void testConstructors() {
52 | @SuppressWarnings("unused")
53 | Card card = null;
54 |
55 | // Numeric rank too low.
56 | try {
57 | card = new Card(-1, 0);
58 | Assert.fail("No exception thrown");
59 | } catch (IllegalArgumentException e) {
60 | // OK.
61 | }
62 |
63 | // Numeric rank too high.
64 | try {
65 | card = new Card(Card.NO_OF_RANKS, 0);
66 | Assert.fail("No exception thrown");
67 | } catch (IllegalArgumentException e) {
68 | // OK.
69 | }
70 |
71 | // Numeric suit too low.
72 | try {
73 | card = new Card(0, -1);
74 | Assert.fail("No exception thrown");
75 | } catch (IllegalArgumentException e) {
76 | // OK.
77 | }
78 |
79 | // Numeric suit too high.
80 | try {
81 | card = new Card(0, Card.NO_OF_SUITS);
82 | Assert.fail("No exception thrown");
83 | } catch (IllegalArgumentException e) {
84 | // OK.
85 | }
86 |
87 | // Null string.
88 | try {
89 | card = new Card(null);
90 | Assert.fail("No exception thrown");
91 | } catch (IllegalArgumentException e) {
92 | // OK.
93 | }
94 |
95 | // Empty string.
96 | try {
97 | card = new Card("");
98 | Assert.fail("No exception thrown");
99 | } catch (IllegalArgumentException e) {
100 | // OK.
101 | }
102 |
103 | // String too short.
104 | try {
105 | card = new Card("A");
106 | Assert.fail("No exception thrown");
107 | } catch (IllegalArgumentException e) {
108 | // OK.
109 | }
110 |
111 | // String too long.
112 | try {
113 | card = new Card("Ahx");
114 | Assert.fail("No exception thrown");
115 | } catch (IllegalArgumentException e) {
116 | // OK.
117 | }
118 |
119 | // Unknown rank character.
120 | try {
121 | card = new Card("xh");
122 | Assert.fail("No exception thrown");
123 | } catch (IllegalArgumentException e) {
124 | // OK.
125 | }
126 |
127 | // Unknown rank character.
128 | try {
129 | card = new Card("xh");
130 | Assert.fail("No exception thrown");
131 | } catch (IllegalArgumentException e) {
132 | // OK.
133 | }
134 |
135 | // Unknown suit character.
136 | try {
137 | card = new Card("Ax");
138 | Assert.fail("No exception thrown");
139 | } catch (IllegalArgumentException e) {
140 | // OK.
141 | }
142 | }
143 |
144 | /**
145 | * Tests the card ordering.
146 | */
147 | @Test
148 | public void sortOrder() {
149 | // Diamond is lower, Clubs is higher.
150 | Card _2d = new Card("2d");
151 | Card _3d = new Card("3d");
152 | Card _2c = new Card("2c");
153 | Card _3c = new Card("3c");
154 | Assert.assertEquals(_2d, _2d);
155 | Assert.assertFalse(_2d.equals(_3d));
156 | Assert.assertFalse(_2d.equals(_2c));
157 | Assert.assertEquals(0, _2d.hashCode());
158 | Assert.assertEquals(1, _2c.hashCode());
159 | Assert.assertEquals(4, _3d.hashCode());
160 | Assert.assertEquals(5, _3c.hashCode());
161 | Assert.assertTrue(_2d.compareTo(_2d) == 0);
162 | Assert.assertTrue(_2d.compareTo(_3d) < 0);
163 | Assert.assertTrue(_3d.compareTo(_2d) > 0);
164 | Assert.assertTrue(_2d.compareTo(_2c) < 0);
165 | Assert.assertTrue(_2c.compareTo(_2d) > 0);
166 | }
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/texasholdem/src/test/java/org/ozsoft/texasholdem/HandEvaluatorTest.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 |
23 | /**
24 | * Test suite for the HandEvaluator class.
25 | *
26 | * @author Oscar Stigter
27 | */
28 | public class HandEvaluatorTest {
29 |
30 | /**
31 | * Tests the High Card hand type.
32 | */
33 | @Test
34 | public void highCard() {
35 | HandEvaluator evaluator = null;
36 | int value1, value2;
37 |
38 | // Base hand.
39 | evaluator = new HandEvaluator(new Hand("As Qh Tc 8d 5d 4h 2c"));
40 | Assert.assertEquals(HandValueType.HIGH_CARD, evaluator.getType());
41 | value1 = evaluator.getValue();
42 |
43 | // Different suits.
44 | evaluator = new HandEvaluator(new Hand("Ac Qd Td 8h 5s 4c 2d"));
45 | Assert.assertEquals(HandValueType.HIGH_CARD, evaluator.getType());
46 | value2 = evaluator.getValue();
47 | Assert.assertTrue(value1 == value2);
48 |
49 | // Major rank.
50 | evaluator = new HandEvaluator(new Hand("Ks Qh Tc 8d 5d 4h 2c"));
51 | Assert.assertEquals(HandValueType.HIGH_CARD, evaluator.getType());
52 | value2 = evaluator.getValue();
53 | Assert.assertTrue(value1 > value2);
54 |
55 | // Minor rank.
56 | evaluator = new HandEvaluator(new Hand("Ks Qh Tc 8d 4d 3h 2c"));
57 | Assert.assertEquals(HandValueType.HIGH_CARD, evaluator.getType());
58 | value2 = evaluator.getValue();
59 | Assert.assertTrue(value1 > value2);
60 |
61 | // Discarded cards (more than 5).
62 | evaluator = new HandEvaluator(new Hand("As Qh Tc 8d 5d 4h 3c"));
63 | Assert.assertEquals(HandValueType.HIGH_CARD, evaluator.getType());
64 | value2 = evaluator.getValue();
65 | Assert.assertTrue(value1 == value2);
66 | }
67 |
68 | /**
69 | * Tests the One Pair hand type.
70 | */
71 | @Test
72 | public void onePair() {
73 | HandEvaluator evaluator = null;
74 | int value1, value2;
75 |
76 | // Base hand.
77 | evaluator = new HandEvaluator(new Hand("Qs Qh 9c 7c 5d 3s 2h"));
78 | Assert.assertEquals(HandValueType.ONE_PAIR, evaluator.getType());
79 | value1 = evaluator.getValue();
80 |
81 | // Rank.
82 | evaluator = new HandEvaluator(new Hand("Js Jh 9c 7c 5d 3s 2h"));
83 | Assert.assertEquals(HandValueType.ONE_PAIR, evaluator.getType());
84 | value2 = evaluator.getValue();
85 | Assert.assertTrue(value1 > value2);
86 |
87 | // Major kicker.
88 | evaluator = new HandEvaluator(new Hand("Qs Qh 8c 7c 5d 3s 2h"));
89 | Assert.assertEquals(HandValueType.ONE_PAIR, evaluator.getType());
90 | value2 = evaluator.getValue();
91 | Assert.assertTrue(value1 > value2);
92 |
93 | // Minor kicker.
94 | evaluator = new HandEvaluator(new Hand("Qs Qh 9c 7c 4d 3s 2h"));
95 | Assert.assertEquals(HandValueType.ONE_PAIR, evaluator.getType());
96 | value2 = evaluator.getValue();
97 | Assert.assertTrue(value1 > value2);
98 |
99 | // Discarded cards (more than 5).
100 | evaluator = new HandEvaluator(new Hand("Qs Qh 9c 7c 5d 2d"));
101 | Assert.assertEquals(HandValueType.ONE_PAIR, evaluator.getType());
102 | value2 = evaluator.getValue();
103 | Assert.assertTrue(value1 == value2);
104 | }
105 |
106 | /**
107 | * Tests the Two Pairs hand type.
108 | */
109 | @Test
110 | public void twoPairs() {
111 | HandEvaluator evaluator = null;
112 | int value1, value2;
113 |
114 | // Base hand.
115 | evaluator = new HandEvaluator(new Hand("Ks Qh Tc 5d 5c 2h 2c"));
116 | Assert.assertEquals(HandValueType.TWO_PAIRS, evaluator.getType());
117 | value1 = evaluator.getValue();
118 |
119 | // High pair.
120 | evaluator = new HandEvaluator(new Hand("Ks Qh Tc 4d 4d 2h 2c"));
121 | Assert.assertEquals(HandValueType.TWO_PAIRS, evaluator.getType());
122 | value2 = evaluator.getValue();
123 | Assert.assertTrue(value1 > value2);
124 |
125 | // Low pair.
126 | evaluator = new HandEvaluator(new Hand("Ks Qh Tc 4d 4d 3h 3c"));
127 | Assert.assertEquals(HandValueType.TWO_PAIRS, evaluator.getType());
128 | value2 = evaluator.getValue();
129 | Assert.assertTrue(value1 > value2);
130 |
131 | // Major kicker.
132 | evaluator = new HandEvaluator(new Hand("As Qh Tc 5d 5d 2h 2c"));
133 | Assert.assertEquals(HandValueType.TWO_PAIRS, evaluator.getType());
134 | value2 = evaluator.getValue();
135 | Assert.assertTrue(value1 < value2);
136 |
137 | // Discarded cards (more than 5).
138 | evaluator = new HandEvaluator(new Hand("Ks Jh Tc 5d 5d 2h 2c"));
139 | Assert.assertEquals(HandValueType.TWO_PAIRS, evaluator.getType());
140 | value2 = evaluator.getValue();
141 | Assert.assertTrue(value1 == value2);
142 | }
143 |
144 | /**
145 | * Tests the Three of a Kind hand type.
146 | */
147 | @Test
148 | public void threeOfAKind() {
149 | HandEvaluator evaluator = null;
150 | int value1, value2;
151 |
152 | // Base hand.
153 | evaluator = new HandEvaluator(new Hand("Ah Qs Qh Qc Th 8s 6c"));
154 | Assert.assertEquals(HandValueType.THREE_OF_A_KIND, evaluator.getType());
155 | value1 = evaluator.getValue();
156 |
157 | // Rank.
158 | evaluator = new HandEvaluator(new Hand("Ah Js Jh Jc Th 8s 6c"));
159 | Assert.assertEquals(HandValueType.THREE_OF_A_KIND, evaluator.getType());
160 | value2 = evaluator.getValue();
161 | Assert.assertTrue(value1 > value2);
162 |
163 | // Major kicker.
164 | evaluator = new HandEvaluator(new Hand("Ks Qs Qh Qc Th 8s 6c"));
165 | Assert.assertEquals(HandValueType.THREE_OF_A_KIND, evaluator.getType());
166 | value2 = evaluator.getValue();
167 | Assert.assertTrue(value1 > value2);
168 |
169 | // Minor kicker.
170 | evaluator = new HandEvaluator(new Hand("As Qs Qh Qc 9h 8s 6c"));
171 | Assert.assertEquals(HandValueType.THREE_OF_A_KIND, evaluator.getType());
172 | value2 = evaluator.getValue();
173 | Assert.assertTrue(value1 > value2);
174 |
175 | // Discarded cards (more than 5).
176 | evaluator = new HandEvaluator(new Hand("As Qs Qh Qc Th 7s 6c"));
177 | Assert.assertEquals(HandValueType.THREE_OF_A_KIND, evaluator.getType());
178 | value2 = evaluator.getValue();
179 | Assert.assertTrue(value1 == value2);
180 | }
181 |
182 | /**
183 | * Tests the Straight hand type.
184 | */
185 | @Test
186 | public void straight() {
187 | HandEvaluator evaluator = null;
188 | int value1, value2;
189 |
190 | // Base hand.
191 | evaluator = new HandEvaluator(new Hand("Ks Th 9s 8d 7c 6h 4c"));
192 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
193 | value1 = evaluator.getValue();
194 |
195 | // Broadway (Ace-high Straight).
196 | evaluator = new HandEvaluator(new Hand("As Ks Qs Js Th 4d 2c"));
197 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
198 | value2 = evaluator.getValue();
199 | Assert.assertTrue(value2 > value1);
200 |
201 | // Different suit (tie).
202 | evaluator = new HandEvaluator(new Hand("Ks Tc 9d 8h 7d 6s 4c"));
203 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
204 | value2 = evaluator.getValue();
205 | Assert.assertTrue(value1 == value2);
206 |
207 | // Rank.
208 | evaluator = new HandEvaluator(new Hand("Ks 9d 8h 7d 6s 5c 2d"));
209 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
210 | value2 = evaluator.getValue();
211 | Assert.assertTrue(value1 > value2);
212 |
213 | // Discarded cards (more than 5).
214 | evaluator = new HandEvaluator(new Hand("As Th 9s 8d 7c 6h 4c"));
215 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
216 | value2 = evaluator.getValue();
217 | Assert.assertTrue(value1 == value2);
218 |
219 | // Wheel (5-high Straight with wheeling Ace).
220 | evaluator = new HandEvaluator(new Hand("Ad Qc Th 5s 4d 3h 2c"));
221 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
222 | }
223 |
224 | /**
225 | * Tests the Flush hand type.
226 | */
227 | @Test
228 | public void flush() {
229 | HandEvaluator evaluator = null;
230 | int value1, value2;
231 |
232 | // Base hand.
233 | evaluator = new HandEvaluator(new Hand("As Qs Ts 8s 6s 4d 2c"));
234 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
235 | value1 = evaluator.getValue();
236 |
237 | // Different suit (tie).
238 | evaluator = new HandEvaluator(new Hand("Ad Qd Td 8d 6d 4c 2h"));
239 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
240 | value2 = evaluator.getValue();
241 | Assert.assertTrue(value1 == value2);
242 |
243 | // Missing one.
244 | evaluator = new HandEvaluator(new Hand("Kh Jh Jd 8h 6d 5s 3h"));
245 | Assert.assertFalse(evaluator.getType() == HandValueType.FLUSH);
246 | value2 = evaluator.getValue();
247 | Assert.assertTrue(value1 > value2);
248 |
249 | // Major rank.
250 | evaluator = new HandEvaluator(new Hand("Ks Qs Ts 8s 6s 4d 2c"));
251 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
252 | value2 = evaluator.getValue();
253 | Assert.assertTrue(value1 > value2);
254 |
255 | // Minor rank.
256 | evaluator = new HandEvaluator(new Hand("As Qs Ts 8s 5s 4d 2c"));
257 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
258 | value2 = evaluator.getValue();
259 | Assert.assertTrue(value1 > value2);
260 |
261 | // Discarded cards (more than 5).
262 | evaluator = new HandEvaluator(new Hand("As Qs Ts 8s 6s 5s 2s"));
263 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
264 | value2 = evaluator.getValue();
265 | Assert.assertTrue(value1 == value2);
266 | }
267 |
268 | /**
269 | * Tests the Full House hand type.
270 | */
271 | @Test
272 | public void fullHouse() {
273 | HandEvaluator evaluator = null;
274 | int value1, value2;
275 |
276 | // Base hand.
277 | evaluator = new HandEvaluator(new Hand("As Qs Qh Qc Tc Td 4c"));
278 | Assert.assertEquals(HandValueType.FULL_HOUSE, evaluator.getType());
279 | value1 = evaluator.getValue();
280 |
281 | // Triple.
282 | evaluator = new HandEvaluator(new Hand("As Js Jh Jc Tc Td 4c"));
283 | Assert.assertEquals(HandValueType.FULL_HOUSE, evaluator.getType());
284 | value2 = evaluator.getValue();
285 | Assert.assertTrue(value1 > value2);
286 |
287 | // Pair.
288 | evaluator = new HandEvaluator(new Hand("As Qs Qh Qc 9c 9d 4c"));
289 | Assert.assertEquals(HandValueType.FULL_HOUSE, evaluator.getType());
290 | value2 = evaluator.getValue();
291 | Assert.assertTrue(value1 > value2);
292 |
293 | // Triple over pair.
294 | evaluator = new HandEvaluator(new Hand("As Js Jh Jc Kc Kd 4c"));
295 | Assert.assertEquals(HandValueType.FULL_HOUSE, evaluator.getType());
296 | value2 = evaluator.getValue();
297 | Assert.assertTrue(value1 > value2);
298 |
299 | // Discarded cards (more than 5).
300 | evaluator = new HandEvaluator(new Hand("Ks Qs Qh Qc Tc Td 4c"));
301 | Assert.assertEquals(HandValueType.FULL_HOUSE, evaluator.getType());
302 | value2 = evaluator.getValue();
303 | Assert.assertTrue(value1 == value2);
304 | }
305 |
306 | /**
307 | * Tests the Four of a Kind hand type.
308 | */
309 | @Test
310 | public void fourOfAKind() {
311 | HandEvaluator evaluator = null;
312 | int value1, value2;
313 |
314 | // Base hand.
315 | evaluator = new HandEvaluator(new Hand("As Ah Ac Ad Qs Th 8c"));
316 | Assert.assertEquals(HandValueType.FOUR_OF_A_KIND, evaluator.getType());
317 | value1 = evaluator.getValue();
318 |
319 | // Rank.
320 | evaluator = new HandEvaluator(new Hand("Ks Kh Kc Kd Qs Th 8c"));
321 | Assert.assertEquals(HandValueType.FOUR_OF_A_KIND, evaluator.getType());
322 | value2 = evaluator.getValue();
323 | Assert.assertTrue(value1 > value2);
324 |
325 | // Kicker.
326 | evaluator = new HandEvaluator(new Hand("As Ah Ac Ad Js Th 8c"));
327 | Assert.assertEquals(HandValueType.FOUR_OF_A_KIND, evaluator.getType());
328 | value2 = evaluator.getValue();
329 | Assert.assertTrue(value1 > value2);
330 |
331 | // Discarded cards (more than 5).
332 | evaluator = new HandEvaluator(new Hand("As Ah Ac Ad Qs 3d 2c"));
333 | Assert.assertEquals(HandValueType.FOUR_OF_A_KIND, evaluator.getType());
334 | value2 = evaluator.getValue();
335 | Assert.assertTrue(value1 == value2);
336 | }
337 |
338 | /**
339 | * Tests the Straight Flush hand type.
340 | */
341 | @Test
342 | public void straightFlush() {
343 | HandEvaluator evaluator = null;
344 | int value1, value2;
345 |
346 | // Base hand.
347 | evaluator = new HandEvaluator(new Hand("Ks Qs Js Ts 9s 4d 2c"));
348 | Assert.assertEquals(HandValueType.STRAIGHT_FLUSH, evaluator.getType());
349 | value1 = evaluator.getValue();
350 |
351 | // Rank.
352 | evaluator = new HandEvaluator(new Hand("Qh Jh Th 9h 8h 4d 2c"));
353 | Assert.assertEquals(HandValueType.STRAIGHT_FLUSH, evaluator.getType());
354 | value2 = evaluator.getValue();
355 | Assert.assertTrue(value1 > value2);
356 |
357 | // Discarded cards (more than 5).
358 | evaluator = new HandEvaluator(new Hand("Ks Qs Js Ts 9s 3d 2c"));
359 | Assert.assertEquals(HandValueType.STRAIGHT_FLUSH, evaluator.getType());
360 | value2 = evaluator.getValue();
361 | Assert.assertTrue(value1 == value2);
362 |
363 | // Steel Wheel (5-high Straight Flush with wheeling Ace).
364 | evaluator = new HandEvaluator(new Hand("As Qc Td 5s 4s 3s 2s"));
365 | Assert.assertEquals(HandValueType.STRAIGHT_FLUSH, evaluator.getType());
366 |
367 | // Wheel (5-high Straight with wheeling Ace), but no Steel Wheel.
368 | evaluator = new HandEvaluator(new Hand("Ah Qc Td 5s 4s 3s 2s"));
369 | Assert.assertEquals(HandValueType.STRAIGHT, evaluator.getType());
370 |
371 | // Separate Flush and Straight (but no Straight Flush).
372 | evaluator = new HandEvaluator(new Hand("Kh Qs Jh Th 9h 4h 2c"));
373 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
374 | }
375 |
376 | /**
377 | * Tests the Royal Flush hand type.
378 | */
379 | @Test
380 | public void royalFlush() {
381 | HandEvaluator evaluator = null;
382 | int value1, value2;
383 |
384 | // Base hand.
385 | evaluator = new HandEvaluator(new Hand("As Ks Qs Js Ts 4d 2c"));
386 | Assert.assertEquals(HandValueType.ROYAL_FLUSH, evaluator.getType());
387 | value1 = evaluator.getValue();
388 |
389 | // Discarded cards (more than 5).
390 | evaluator = new HandEvaluator(new Hand("As Ks Qs Js Ts 3d 2c"));
391 | Assert.assertEquals(HandValueType.ROYAL_FLUSH, evaluator.getType());
392 | value2 = evaluator.getValue();
393 | Assert.assertTrue(value1 == value2);
394 |
395 | // Separate Flush and Straight, but no Straight Flush or Royal Flush.
396 | evaluator = new HandEvaluator(new Hand("As Kh Qs Js Ts 4s 2c"));
397 | Assert.assertEquals(HandValueType.FLUSH, evaluator.getType());
398 | }
399 |
400 | }
401 |
--------------------------------------------------------------------------------
/texasholdem/src/test/java/org/ozsoft/texasholdem/HandTest.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem;
19 |
20 | import java.util.ArrayList;
21 | import java.util.Collection;
22 |
23 | import org.junit.Assert;
24 | import org.junit.Test;
25 |
26 | /**
27 | * Test suite for the Hand class.
28 | *
29 | * @author Oscar Stigter
30 | */
31 | public class HandTest {
32 |
33 | /**
34 | * Tests the basics (good-weather).
35 | */
36 | @Test
37 | public void basics() {
38 | Hand hand = new Hand();
39 | Assert.assertNotNull(hand);
40 | Assert.assertEquals(0, hand.size());
41 |
42 | Card[] cards = hand.getCards();
43 | Assert.assertNotNull(cards);
44 | Assert.assertEquals(0, cards.length);
45 |
46 | hand.addCard(new Card("Th"));
47 | Assert.assertEquals(1, hand.size());
48 | cards = hand.getCards();
49 | Assert.assertNotNull(cards);
50 | Assert.assertEquals(1, cards.length);
51 | Assert.assertNotNull(cards[0]);
52 | Assert.assertEquals("Th", cards[0].toString());
53 |
54 | hand.addCards(new Card[]{new Card("2d"), new Card("Jc")});
55 | Assert.assertEquals(3, hand.size());
56 | cards = hand.getCards();
57 | Assert.assertNotNull(cards);
58 | Assert.assertEquals(3, cards.length);
59 | Assert.assertEquals("Jc", cards[0].toString());
60 | Assert.assertEquals("Th", cards[1].toString());
61 | Assert.assertEquals("2d", cards[2].toString());
62 |
63 | hand.removeAllCards();
64 | Assert.assertEquals(0, hand.size());
65 | }
66 |
67 | /**
68 | * Tests the constructors (bad-weather).
69 | */
70 | @Test
71 | public void constructors() {
72 | @SuppressWarnings("unused")
73 | Hand hand = null;
74 |
75 | // Null card array.
76 | try {
77 | Card[] cards = null;
78 | hand = new Hand(cards);
79 | Assert.fail("No exception thrown");
80 | } catch (IllegalArgumentException e) {
81 | // OK.
82 | }
83 |
84 | // Card array with a null card.
85 | try {
86 | Card[] cards = new Card[1];
87 | hand = new Hand(cards);
88 | Assert.fail("No exception thrown");
89 | } catch (IllegalArgumentException e) {
90 | // OK.
91 | }
92 |
93 | // Card array with too many cards.
94 | try {
95 | Card[] cards = new Card[11];
96 | hand = new Hand(cards);
97 | Assert.fail("No exception thrown");
98 | } catch (IllegalArgumentException e) {
99 | // OK.
100 | }
101 |
102 | // Null card collection.
103 | try {
104 | Collection cards = null;
105 | hand = new Hand(cards);
106 | Assert.fail("No exception thrown");
107 | } catch (IllegalArgumentException e) {
108 | // OK.
109 | }
110 |
111 | // Card collection with a null card.
112 | try {
113 | Collection cards = new ArrayList();
114 | cards.add(null);
115 | hand = new Hand(cards);
116 | Assert.fail("No exception thrown");
117 | } catch (IllegalArgumentException e) {
118 | // OK.
119 | }
120 |
121 | // Card array with too many cards.
122 | try {
123 | Card[] cards = new Card[11];
124 | hand = new Hand(cards);
125 | Assert.fail("No exception thrown");
126 | } catch (IllegalArgumentException e) {
127 | // OK.
128 | }
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/texasholdem/src/test/java/org/ozsoft/texasholdem/util/PokerUtilsTest.java:
--------------------------------------------------------------------------------
1 | // This file is part of the 'texasholdem' project, an open source
2 | // Texas Hold'em poker application written in Java.
3 | //
4 | // Copyright 2009 Oscar Stigter
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package org.ozsoft.texasholdem.util;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 | import org.ozsoft.texasholdem.Card;
23 |
24 | /**
25 | * Test suite for the PokerUtils class.
26 | *
27 | * @author Oscar Stigter
28 | */
29 | public class PokerUtilsTest {
30 |
31 | private static final double DELTA = 1e-08;
32 |
33 | /**
34 | * Tests the implementation of the Chen formula calculator.
35 | */
36 | @Test
37 | public void chenFormula() {
38 | Card card1 = null;
39 | Card card2 = null;
40 |
41 | card1 = new Card(Card.ACE, Card.SPADES);
42 | card2 = new Card(Card.ACE, Card.HEARTS);
43 | Assert.assertEquals(20.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
44 |
45 | card1 = new Card(Card.ACE, Card.SPADES);
46 | card2 = new Card(Card.KING, Card.SPADES);
47 | Assert.assertEquals(12.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
48 |
49 | card1 = new Card(Card.KING, Card.SPADES);
50 | card2 = new Card(Card.KING, Card.HEARTS);
51 | Assert.assertEquals(16.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
52 |
53 | card1 = new Card(Card.TEN, Card.CLUBS);
54 | card2 = new Card(Card.TEN, Card.DIAMONDS);
55 | Assert.assertEquals(10.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
56 |
57 | card1 = new Card(Card.FIVE, Card.CLUBS);
58 | card2 = new Card(Card.SEVEN, Card.CLUBS);
59 | Assert.assertEquals(6.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
60 |
61 | card1 = new Card(Card.DEUCE, Card.CLUBS);
62 | card2 = new Card(Card.SEVEN, Card.DIAMONDS);
63 | Assert.assertEquals(0.0, PokerUtils.getChenScore(new Card[] {card1, card2}), DELTA);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------