Sungka v0.06 Copyright (c) 2002 by Michael Barrientos mbarrien@geocities.com -------- Overview -------- Sungka is one of the oldest games in the world, with almost every culture having some form of the game. This is an implementation of the Filipino variation, with some enhancements to allow for more than 2 players. ---------- Game rules ---------- (These rules will describe the standard 2 player game.) A Sungka Board consists of a set of cups that hold stones. Each player has 6 playing cups, along with a home cup at the far right end. Each cup (except for the home cup) initially holds 7 stones. A diagram is shown below: The players take turns removing the stones from a cup on their side, and placing a single stone in the other cups, proceeding counterclockwise. When the player reaches the end of his own row, he will drop a stone in his own home cup, then continue to drop stones on his opponents side. If he should reach the end of his opponent's row, he will not drop a stone in his opponent's home cup. The following example shows the board after the player has taken stones from cup number 3. When the player runs out of stones, several things can happen depending on where the last stone was dropped. 1. If the players last stone was dropped on the opponents side, his turn ends. 2. If the players last stone was dropped in his own home cup, his turn continues, and the player may select any cup on his own side to pick up stones from. Play continues until his turn ends. 3. If the players last stone was dropped on his own side and the cup he dropped it into was not previously empty, he must take all the stones from this last cup, and continue dropping stones in a counterclockwise fashion. This can occur multiple times in 1 turn, and continues until his turn ends by one of the other rules. 4. If the players last stone was dropped on his own side and the cup he dropped it into was not previously empty (i.e. there is now exactly one stone in the cup), this is a capture. The player takes his own stone and the stones in the cup directly across from his, and deposits all of them in his own home cup. The players turn then ends. Play continues until all stones are in the home cups. If a player has no possible moves (i.e. there are no stones in any of the cups in his own side), the player forfeits his turn. When the game is over, both players count the number of stones in their own home cup. Whoever has the most stones wins. Sungka also supports multiplayer variations. When a capture occurs, the player will capture all the stones in the next player's opposing cup. Play continues in a rotating fashion among all 3 players. ------------------------------- Build Requirements/Instructions ------------------------------- Sungka requires Sun JDK 1.4 to compile and to run. (JDK 1.4 introduced the new POA architecture which we utilize. The server accesses some internal Sun classes, and the GUI uses the Java2D features that were introduced in JDK 1.4.) Build instructions: 1. Expand all the files into a temporary directory. 2. From within the temporary directory, run "idlj -fall SungkaInterface.idl" to create the CORBA stub classes. 3. javac -g *.java 4. jar cvfm Sungka.jar sungka.manifest *.class *.properties To run: To play a local only game, Sungka currently requires at least 3 windows open: one for the server, two for the players. The sungka server now runs the CORBA name server internally, and will have no need to run it separately. 1. Start the game server by running "java -cp Sungka.jar SungkaRegisterServant -ORBPersistentServerPort 1050". 2. Start the 2 players by running "java -cp Sungka.jar TextSungkaPlayerView". The game will prompt for a server to connect to. To connect to the server as instructed above, enter "localhost:1050". Alternatively, there is a GUI version, which can be started by running "java -cp Sungka.jar GUISungkaPlayerView". The port and host will be asked for in a dialog in the program. 3. An observer can also be added to the game by starting another xxxSungkaPlayerView. The game can also be run over the Internet, with the players, board, and all on separate computers. --------------------- Architecture Overview --------------------- This Sungka game consists of 2 main parts: a Board class, and a Player class. The Board class (implemented by SungkaRegisterServant) holds all the game logic. The Player classes (implemented by SungkaPlayerServant) implements the interface between user and Board. Internally, it only knows basic rules about the board layout and a suggested order of player, nothing more. The Board class holds all information about the order the players go, the rules of the game, adding and subtracting pieces from spaces, checking whether a move is legal, etc. The player class acts essentially as a dummy terminal. A View class provides the actual user interfaces that the user plays on. It associates itself with a Player, then receives messages when the game state changes. A Player may only have 1 view at a time. In CORBA terms, the Board and Player are both servers and clients at the same time. Each exposes an interface that the other can call. There are 2 kinds of "players" in Sungka: an active player, or an observer. An active player actually plays the game, and has the permission to make moves. An observer solely watches the progress of the game; it receives updates of each move, but does not actually make moves. ------------------ Initial connection ------------------ The Board class registers with the CORBA Name Server with the name "Sungka". The Board class uses the SungkaRegister interface, exposing only a function joinGame to allow a new player to join. The Player class joins a game by calling the joinGame function of the Board, passing its own user name, whether it wants to be an observer, and a reference to itself. If the Board allows the player to join, it will return both the player's ID number, and a reference to a SungkaBoard object to expose the game playing interface to the player. The Board uses the SungkaPlayer interface passed to it to notify each player of game events. ----------------- Ending connection ----------------- If a Player wants to leave the game, it can do so at any time just by quitting and closing the CORBA connection. The Board will detect this, and notify all other players of the departure. If the player leaving is an active player, the game ends with no winner. ------------------- Player Architecture ------------------- Our player object consists of a main waiting loop, and a message queue. Whenever a message is received from the Board, the message is placed into a queue, which then wakes the main loop. The main loops sole job is to dequeue messages, then process them. A Message object is another Java object, implementing the Runnable interface. To process a message, the main loop just calls the run() method of each message, which will do some sort of processing and game updating. Since we have multiple threads running (the main loop, CORBA-created threads, etc.), we make sure to lock necessary data structures. Our message queue is synchronized to prevent race conditions. We also synchronize some methods on "this" as another lock for concurrency checking. ------------------- Server Architecture ------------------- Messages coming from Players are usually processed right away. A few functions (e.g. player removal) are queued similar to the queueing structure of the player, for performance reasons, or to prevent concurrent reading/modification of data structures. To notify each player of an event, we loop through the list of players and call the corresponding function. In cases where the function call would pass the same arguments to all the Players (e.g. chat messages), we use Java reflection to simplify the task. Instead of having to write a special iteration function for each and every client call, we just use a general notify method which would call the same function on each Player. We try to maintain the illusion that each player is the "first" player by rotating the board we send to each. When a player calls getBoard, the data in row 0 always belongs to the player calling getBoard. Also, each player will get a playerAdded message with the order number rotated so that the caller is #0. If the player calling getBoard is an observer, we just use the server's internal numbering to determine the order. There is also a notion that a player "owns" a certain row of the board. When each player gets a setCup or addToCup message, the player number received is the game's player number. It is up to each individual player to map from the player number to which cup to change. We use the order number to do the mapping right now, but this can be implmented multiple ways. ----- To do (in no particular order) ------------------------------ * Create a MAKEFILE * Clean up code to better separate model & view (Model-View-Controller pattern) * Test across a firewall/router * Clean up Player/Participant terminology better in code * Change more of the Java interfaces to CORBA objects * Determine a set of test cases * Add more error checking for rogue servers (ArrayOutOfBounds checking) * Notify about all multiple winners (i.e. 2 players tied in game w/ >2 players) * Add documentation of command line arguments * Add more command line arguments to allow setting options (e.g. ports) * Save settings between each program run (and each time dialog is shown) * Implement player-to-player chat (not just broadcast chat) * Convert into applet * Add accessibility support * Verify security so references cannot be passed maliciously between clients * Print out game state to new observer in text only version * Allow server to host multiple games * Change "observer" model to "stand up/sit down" model * Generalize API to allow multiple kinds of games (our architecture is Sungka specific, and frankly a little crappy since we cannot use just one message passing function and are forced to simulate functional programming) * Customize CORBA stubs so calls to clients can be made asynchronously (can't use oneway since we want to verify receipt) (or wait until JDK gets CORBA 3.0 support, which supports delayed synchronous calls) * Work on rules for multiplayer version * Create AI player * Port Player GUI to C++ (hey, this IS a learning experience for me) * Add support for wireless devices/cellular phones (use J2ME?) * Look at memory usage for each player using own SungkaBoard CORBA reference ------- History ------- v0.01: (unreleased) Initial implementation, local only, make Sungka game rules. v0.02: (unreleased) Separated player and board into their own objects. v0.03: (unreleased) Integrated CORBA, fixed observer implementation, fixed multithreading bugs. v0.04: Added Registration interface. Added documentation. v0.05: Added initial observer GUI, fixed Board side bugs with order v0.10: Increased access protection of some methods, added message type to logging interface, removed QueueRunnable/RemoveRunnable classes (since I found out about final modifiers in signatures), polished GUI a bit, added easy GUI for entering server/port/username, fixed updates of GUI from outside event thread, resolved server side thread safety problems, changed terminology from "active player" to "participant", changed methods for player removal, began support for message for exiting, added pinging, can choose between Initial Naming and Interoperable Naming, added localization support, made player turn more visible, began MVC pattern separation, merged server and player GUI, unnested classes.