# DESIGN Document for Ooga Livia Seibert - las120 Martha Aboagye - mfa23 Patrick Liu - pyl8 Montana Lee - mal115 ## Role(s) Livia - My primary role was to work on the data module of the project. I created the layout for the XML files, the XML parser module, the game objects, the win managers, and the win rule engine. Rachel - My primary role was to work on the data aspect of the project. I created the XML Writer package, and helped create the game objects. Martha - My primary role was to work on the view and the controller classes to connect user action to the game engine. Patrick - My primary role was to work on the engine component of the project, including bet management, action management, and player money management. I also contributed to the controller classes to facilitate communication between the back-end and front-end. Montana - Filled in gaps throughout the Engine and View Packages, including Automated Players, Observables, and Settings ## Design Goals One of our main design goals for this project was to make our code as flexible as possible in order to be able to implement lots of different types of poker. To accomplish this, we researched existing types of poker variations and thought about the main components that differentiated each type from each other. Then, we thought about how to create abstractions for these components that would allow us to swap pieces of the engine in and out to handle different behavior. Another one of our design goals was to encapsulate each of our APIs well. The data, the view, and the engine each have such distinct responsibilities, and we didn't want these roles to overlap and get confusing. We also wanted to shield implementation details between APIs; for example, we consciously designed our `CardCollection` API to shield the actual implementation of the list of cards. ## High-Level Design There are two main types of XML files that can be used to create poker games, ones to create a completely new game from scratch and one to load a game from a previously saved game state. When the save game button is clicked, the current game state is saved to an XML file using DataXMLWriter. There is also a form that can be filled out to create the game from scratch which calls the FormXMLWriter. These two main classes of the XML Writer both extend XMLWriter and XMLUtilityWriter to write the game state into an agreed-upon XML file format. These both call their own WinXMLWriters to write the win conditions XML file from this format, and they call DeckXMLWriter and BetXMLWriter to make those XML files based on the exisiting format. Writing the XML files in this way allows the XML Parser to easily read in the files. There are two corresponding functions in GameDataInitializer to handle these options, loadNewGame and loadExistingGame. Both loadNewGame and loadExistingGame rely on the xmlparser package to read the data off of these XML files and instantiate the corresponding objects for the game. The xmlparser package contains an abstract XMLParser class from which many different XML parser subclasses inherit (BetXMLParser, PlayerXMLParser, etc.). These subclasses each handle a specific type of object needed for the game, and many of them rely on reflection to be able to create different varieties of the same type of object. For example, the PlayerXMLParser uses reflection to create the player type specified in the XML, which can be Player, EasyPlayer, or HardPlayer. GameDataInitializer uses the public methods in the parsers to retrieve the objects it needs to create an instance of a Data record, which specifies the initial game state for the game. This data record is then passed to the engine's constructor, which is a dependency injection. That way, the actual parsing functionality of the data module stays completely encapsulated, and only the Data object is accessible in the engine. In the Engine component of the project, the main APIs are `ActionManager`, `BetManager`, `PokerAction`, and `RaiseLimitRule`. These APIs provide services to `PokerGame`, the main class of the engine where basic dealing of cards and checking for win conditions is conducted. All of these APIs are data-driven, as subclasses of `BetManager` and `RaiseLimitRule` differ in functionality, can be used interchangeably with polymorphism, and can be created using reflection. In addition, `PokerGame` takes in a `Data` object that stores all pertinent information about the game, including the mechanics of each `Round`. `ActionManager` shields the implementation details of giving inputs to user actions and running actions, while `BetManager` shields the implementation details of determining possible betting actions and moving money between players and the pot. These APIs are easy to use and extend since the superclass methods have been reduced to the most essential ones, especially for `PokerAction`; creating a new action requires overriding the `run` method and adding any required inputs to the `requiredInputs` ArrayList in the constructor. ## Assumptions or Simplifications We based our design off of the main poker variations specified by the Paget Poker Website referenced above. Based on what we read from that site, we came up with the different components that we thought would lend themselves to implementing as many poker variations as possible. While there are many poker variations out there, this site is what we used to limit the scope of our project. In order to focus on a well-rounded design for the engine, games are expected to start with all players having the same amount of money. This simplifcation avoids situations where a player wants to call but does not have enough money, thereby going "all in." This situation is more of a logic challenge than a design challenge, so it was left out. Another simplification we made is to make all user inputs during betting/discarding rounds textboxes in order to fully leverage the View's support for collecting user input. While entering a raise amount is intuitive, this format causes confusion for discarding cards since the indices of the cards have to be entered in a specific format. We wanted to focus more on the design of how user actions are presented to the View and how `ActionManager` classes handle user selections, but if given more time we would make cards clickable so the user can more intuitively select cards. ## Changes from the Plan I changed the XML layout for the win conditions a lot from how I initially intended to implement them. I didn't originally account for the different rules that could be placed on winning hands, such as in variations where two cards have to come from the player's hand and three have to come from the community cards. I also didn't yet know how we were going to structure the win manager, so I put too much information in the XML about the rank of each card. While the core engine APIs remained the same from the Plan (`Action`, `ActionManager`, `BetManager`), the inheritance hierarchies changed slightly. Since bet actions and card actions had different constructors because they needed access to different game objects, we created separate `BetAction` and `CardAction` classes to distinguish between them. Another major change from the Plan was in our controller. We initially planned to almost exclusively use observables to notify the view of changes in engine properties (community pool, minimum bet amount, etc.). However, this system required a lot of extraneous passing around of view objects (`GameStatusBar`), so we opted for a more old-school controller class that facilitates communication from the engine to the view. ## How to Add New Features ### Add a New Game To add a new game variation, all you need to do is create a new XML file with different input values. This can be done manually by writing an XML file from scratch, or by using the form within our program that allows the user to choose from possible game options to create a variation of poker that is entirely their own. If you write a file manually for an existing type of poker, you can create an option for it on the selection page of the game so that it can be accessed easily. If you use the custom form option, you can run your poker variation with the load button on the poker selection page that pops up a file chooser with all previously-created files. ### Add a New Action To create a new type of betting or card action, simply extend `BetAction` or `CardAction`. In the constructor, add the type of input required to run the action (right now, the API supports `Doubles` and `CardCollections`), or use the default constructor if the action does not require inputs. Then override the `run` method with the desired functionality of the action. For new betting actions, the logic for when these actions appear available to the user must be added in the `getPossibleBetActionsForPlayer` method of the `BetManager` class. ### Add a New Rule To demonstrate the power of using inheritance hierarchies for rules, there is a `RaiseLimitRule` superclass in the engine package. To create a new individual raise limit rule, extend this class and override the `getMaximumRaise` method with the desired calculation. Data can now recognize the name of the subclass using reflection, and the `BetManager` is already set up to use any `RaiseLimitRule` object, taking advantage of polymorphism. ### Add a New AI Player It is possible to create many types of automated players, each with their own strategies. To add a new player with a different strategy, extend the AutoPlayer class and implement the desired strategy. Next, in the StartupScene add the name of the player class so that the user can select that type of player to play against.