├── 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 | --------------------------------------------------------------------------------