| 6.170 | Laboratory in Software Engineering
Fall 2003 Final Project: Antichess Due: See Schedule |
Quick links:
Contents:
Antichess is a variant of chess in which the goal is to either lose all of your pieces (except your king) or force your opponent to checkmate you.
Antichess is played between two opponents by moving pieces on a square board. The board is composed of 64 equal squares. The eight vertical lines of squares are called columns. The eight horizontal lines of squares are called rows. The squares are colored black and white alternately. The lines of squares of the same color, touching corner to corner, are called diagonals. The chessboard is placed between the players in such a way that the near corner to the right of each player is white. The columns are labeled a to h from left to right. The rows are numbered 1 to 8 from bottom to top.
At the beginning of the game, one player ("white") has 16 white pieces, and the other ("black") has 16 black pieces. The white player pieces are: one King (e1), one Queen (d1), two bishops (c1 and f1), two knights (b1 and g1), two rooks (a1 and h1), and eight pawns (row 2). The black player pieces are: one King (e8), one Queen (d8), two bishops (c8 and f8), two knights (b8 and g8), two rooks (a8 and h8), and eight pawns (row 7). The initial position of the pieces on the chessboard is shown to the right.
A move is defined by the following rules:
A player's moves are limited by the following fact: A player is forced to capture an opponent's piece whenever possible. If a player can take several of the opponent's pieces, he/she is free to choose which piece to take. This limitation does not exist in regular chess. The two exceptions to this rule are being in check and passing.
All the pieces move exactly as they do in standard chess. An excellent description of how each piece moves and captures is here http://www.princeton.edu/~jedwards/cif/intro.html. Pay special attention to the descriptions of castling and en passant. There are two additional moves that are native to antichess:
The number of starting pass chips given to each player can be specified when the game is started, and can be zero. Your AI should be optimized to handle both the case of zero pass chips and a small number of pass chips (roughly up to five).
In short, each move of player A must observe the following:
The king is in check when the square it occupies is attackable by one or more of the opponent's pieces; in this case, the latter is/are said to be checking the king. A player may not make a move which leaves his king on a square attackable by any of his opponent's pieces; e.g., the player cannot move the king into check. Check must be resolved by the move immediately following. If any check cannot be parried, the king is said to be checkmated or mated.
It is the foremost obligation of each player to move the king out of a check. This overrides the rule that you must take an opponent's piece. For example, in the figure below to the left, it is black's turn and black must move its king out of check even though it can take white's bishop on c6 with its rook.
If it is possible for a player to remove the king from check as well take a piece of the opponent, then the player must do so. For example, suppose the black player's king is under check from white's rook. Further, suppose black has two choices to move away from check -- remove the check with or without taking a white piece. In that case, black must take white's piece and remove the check. In the figure below to the right, black's king must take the white bishop with the king in the next move (it cannot simply move the king away from check without taking the bishop).
We shall play antichess with time restrictions, as is often the case in chess games. Each player is allocated a fixed amount of time T to make all the moves, e.g., 5 minutes. There is a clock for each player that is set to T minutes at the start of the game. If it is player A's turn to move, A's clock counts down until the move is made. While it is B's turn to move, A's clock is suspended, and B's clock runs down. If a player's clock runs down to zero while the game is in progress, the player loses. This ensures that the game is over in less than 2*T minutes, because by then at least one of the clocks has run down to zero.
Player A wins the game against player B if:
The game is drawn when the king of the player who has the move is not in check, and this player cannot make any legal move. The player's king is then said to be stalemated. This immediately ends the game in a draw, i.e., neither player wins or loses the game. Since discarding a pass chip is a legal move when the king is not in check, a stalemate cannot occur unless the stalemated player is out of pass chips.
| Stage | Due date |
% of project grade | Graded on |
|---|---|---|---|
| Preliminary design | Wed, Nov 12 | Have you identified the issues? | |
| Weekly meetings with TA | Mon, Nov 3 through Fri, Dec 5 | Did all of the team members participate constructively? | |
| Preliminary Release | Mon, Nov 24 | Is it a good design? Is the required functionality present? | |
| Final report | Mon, Dec 8 | Quality of entire documentation including amendment and design critique. Are the tradeoffs & alternatives analyzed? | |
| Implementation & Test | Mon, Dec 8 | Does it work? Have you demonstrated that it works? What is the quality of the code, the design, and the tests? | |
| User Interface and Quality of Play | Mon, Dec 8 | How is the user experience? Is it easy-to-use? How sophisticated is the computer player? |
You will work in teams of three or four. Each team member should be responsible for a significant part of the design, documentation, code and testing. All members of a team will get the same grade, except in unusual circumstances. If your group is experiencing internal problems, see your TA immediately.
As you can see, more than half of your grade depends on design and documentation. Please realize that the most important aspect of any large software endeavor is design. A good, well documented design will make the rest of a group's work faster, easier and more enjoyable.
Each stage of this assignment should be handed in electronically to your TA by 4:30 PM on its due date. All of the source and compiled code should be put online on Dec 8, in your team project directory.
The final report is due by 4:30 pm on Dec 8, 2003. Because of end of term constraints, late reports will not be accepted.
You should express your preliminary design in under 15 pages. Your document will be a subset of that described in the Documenting a Software System handout. It will include a revised specification, a design, and an implementation overview (including an object model or models and a module dependency diagram). You do not need to include information about your testing strategy or provide a reflection of your experience (after all, you haven't really finished the project yet).
The revised specification, design, and implementation overview must discuss, among other issues:
The preliminary design should also include a project plan, which lists milestones for the team and allocation of tasks to each team member. A milestone is what you expect to be done by some date, such as a tested module or a working feature -- an achievement that is objective, easy to evaluate, and significant. There must be at least two milestones in the project between the preliminary design and the final deadline. The division of labor should be equitable. (It is most useful to combine the milestones and the task allocation into a single table with task, who, and when columns, rather than making the milestones and task allocation into to separate documents which cannot be easily related.)
The preliminary design will be graded for clarity of expression and for whether you have thought rigorously about the problem, identified the major issues and challenges, and proposed a design that makes sense.
Since the final design is due as part of the preliminary release milestone, you should have found all major mistakes in your design. Therefore the final design will be graded on whether it is a good design, in addition to clarity of expression.
In order to demo what you had done at the preliminary release deadline, even if the demo is slightly later and you have made modifications in the meanwhile, you must retain a copy of your code as it existed before the deadline. You can create a snapshot of your source and/or compiled code by using a jar file. Then, you can run the demo by placing the jarfile in your classpath, or by making the jar itself executable.
Your group must demonstrate the following features:
Follow these steps to create the tag:
Later, if you wish to go back to the tagged version, run cvs update -r preliminary-release. This will put that revision in your workspace. You will not be able to commit from that workspace. If you wish to go back to the main trunk, run cvs update -A.
You should email your TA with the following information:
Your ta will run "cvs -d <your cvs root> co -r preliminary-release <your module>" and then follow your instructions to test the demo.
Put your code online in your team project directory. You do not need to turn in a printout of your code. In general, your group must turn in code that you wrote yourself. Therefore, you are generally not allowed to use third-party Java libraries. If you have some code that you found and you are unsure of whether or not you can use it, please see your TA.
The final report includes a section on Design Changes. Detail what changes you have made to the design that was submitted on Nov 24th. Be precise. It is vitally important that your TA have versions of the descriptive parts of the Revised Specification, Implementation Overview, and Validation Strategy that accurately describe your submitted code and what you actually did for testing or validation.
For demonstrations (as described immediately below), you must also make a jar file of your implementation named /mit/6.170/groups/seMMN/final.jar. This file must be runnable and must include all of your code in both source and compiled form.
Your AI player must be written in pure Java; we will compile all submissions from source and run them on a computer and JVM of our choosing. In other words, you should focus on high-level algorithmic optimizations, not low-level ones such as choice of bytecode or Java implementation.
Judging will be done initially by the TAs and final judgments will be made by the lecturers. Winners will be announced at the last class on Dec 10.
In addition we provide you with a specification for machine players, and for the TextUI. We also provide a jar that implements the interfaces and extra classes needed to implement the machine player specification.
Within the constraints of correctness and clarity, a faster implementation will perform better in the competition. This section discusses some speed-related issues. You should also see Bloch's Effective Java.
If you wish to optimize, you should focus on high-level issues such as representations and algorithms, which may give you orders of magnitude more speed increase than low-level optimizations can. Are you repeating computation? Are you needlessly creating objects? Does a more efficient algorithm exist? Even more importantly for Antichess, does a better static evaluation function exist?
When thinking about speed, you should never bother with low-level issues like whether to inline a particular procedure or whether i+=1 is faster than i=i+1. The first reason is that a good JIT already does a good job at such optimizations; it can be far more effective working at the machine code level than you can at the source level. The second reason is that you are likely to get these wrong; one reason that many modern compilers lack an inlining directive is that experience has shown that programmers' intuitions about inlining are wrong more often than they are right. The third reason is that such tiny performance improvements are unlikely to make a real difference: a couple of percent won't matter either way in the competition (or in most real-world environments).
In order to discourage counterproductive optimizations, and for other reasons, we require you to submit source in pure Java. We will compile it with a compiler of our choice and run it on a JIT of our choice. Both will be state-of-the-art tools, so you don't have to worry about low-level optimizations. Use of a uniform compiler will ensure fair comparison across students: we don't want to test a student's infrastructure or toolset, but the code.
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. - William A. Wulf
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. - Donald E. Knuth
We follow two rules in the matter of optimization: Rule 1. Don't do it. Rule 2 (for experts only). Don't do it yet - that is, not until you have a perfectly clear and unoptimized solution. -- M. A. Jackson
java -Xrunhprof:cpu=samples,file=log.txt,depth=4 MyClass
This will generate a file called log.txt. (Warning: this will take an order of magnitude longer than just calling "java MyClass". If your program is already taking a long time, you may very well want to run it on a small input for profiling purposes.) Go to the end of log.txt, and look for a ranked table of method calls. The methods at the top of the table are eating up most of the cpu time. For more detail on how a particular method is being called, look at the "trace" column, and note the ID number given there. If the ID, for example, is 437, then search in log.txt for "TRACE 437", which will tell you from which methods your suspect method is being called. For more information about reading this file, see here
Once you know where all your time is being taken, you have generally two options:
We have initialized your lockers with cvs directory structure containing a working ant build environment to help you get started on your project. You can read more about how to get started with your locker here.
You must have in the root directory of your project executable files named "build" and "demo". "build" should be a shell script that builds your project to a playable configuration, and "demo" should run a human vs computer game in the graphical UI with one pass chip per player and five minutes per side. In order to play your game, the TA should simply be able to cvs checkout your project, run "build", and run "demo". If you're not familiar with writing a shell script, see here. We recommend you consider using the very helpful java build tool ant.
To learn more about jar files, review the jar tool manual from Sun.
As a quick reference, here are a few sample uses of the jar command:
To create antichess.jar from classes in package antichess:
jar cvf antichess.jar antichessTo list the contents of the jar file, use:
jar tf antichess.jarTo create a runnable antichess.jar
jar cvfm antichess.jar JarMainManifest antichessIn the example above, the file JarMainManifest should contain two lines. One is a single line which names the entry point:
Main-Class: antichess.AntichessoThe other specifies your AI player factory, as discussed in the AiPlayerFactory spec To run the application using the jar file, use:
java -jar antichess.jar
Using a Makefile, as described the section above, can simplify and automate the creation of jar files.
Your program should be runnable by the following command:
java antichess.AntichessThe basic mode of your game will be to have a human play against a machine player. Your application should use the Java Swing to provide a graphical user interface for this form of play, as described in Section 4.2.
In addition, we will provide a referee which will allow your machine player to play against machine players from other groups. In order to be able to do this, you must provide a MachinePlayer class which conforms to the specification.
The referee will use the information about what has changed on the board, plus its knowledge of the current state, to display the status of the game. It will check each response for legality, it will keep track of the time left for each player, and it will display the status of the game. We will provide our own referee that does these things. We will use this referee in the tournament. You will not implement the referee in this problem set; only the antichess player. Of course, in a human-computer game, your program has to provide functionalities very similar to the referee (e.g. checking for illegal moves, displaying status, etc.).
Your machine player cannot simply make arbitrary moves. As such, you must implement decision heuristics to enable your machine to play well. Do not let this task intimidate you. Any of several basic and easy to understand algorithms will be sufficient. For example, you might read up on minimax or alpha-beta search methods. A good introductory text on such search methods is Russell & Norvig, AI: A Modern Approach.
We define a standard string format for a chess move. The string should be 5 characters long. The first two characters represent the square where the piece began, the third character is a dash (-), and the next two characters represent the square where the piece moved to. In the case of a castle, the move should be represented by the movement of the king. In the event of discarding a pass chip, the move should be represented as the string Ipass
You must implement a class that implements the AiPlayerFactory interface given in the specification. Note that this factory may return different concrete classes from the createPlayer method, depending on amount of time given, rule set, etc.
Your machine player is allowed to use multiple threads and be thinking while the opponent is thinking and making his move. However, you are not allowed to use the resources of a computer other than the one running the machine player.
[init] RuleSet 6170-fall-2003 InitTimeSeconds 300 [setup] AddChips white 1 AddChips black 1 [moves] white 003.247 d2-d4 black 001.609 g8-f6 white 006.665 b2-b4 black 002.290 Ipass white 010.000 savedAnd here is an example of a setup that might never occur in normal play, but might be interesting as a puzzle (or testcase to the AI):
[init] RuleSet 6170-fall-2003 InitTimeSeconds 300 [setup] ClearBoard AddPiece black P a6 AddPiece white P b4 AddPiece white P c3 AddPiece white K d4 AddPiece white N e5 AddPiece black R e3 AddPiece black P f4 AddPiece black P g3 AddPiece white R g2 AddPiece black K h5 AddPiece black P h4 AddPiece white P h3 [moves]The game file has three major sections. "init" includes the following information, in this order:
"moves" recounts a game history. Each line has a thinking time, which must be represented in seconds in the format ###.### (Suggesting that thinking times should be represented as an integer number of milliseconds). Leading and trailing zeros must be used to pad the thinking time out to seven characters. The thinking time is followed by either a move specification (including possibly "Ipass"), or the string "saved", which indicates that the player was thinking for that long before the game was saved (that think time is charged against the player when the game is resumed). The "moves" section can include as a last line the command "GameOver", which indicates that the last player to move won the game. The moves alternate between white and black.
Note that the board position is not explicitly included in the game file. Instead, the board position must be built from the initial setup and the history of moves. The number of passes and time left must be similarly computed. You can assume that the setup and moves are legal, and leave your program's behavior undefined in the face of an illegal move. The time remaining for each player can be inferred from the initial time allotment and the thinking times for each move.
The game file has the following formal grammar. Note that \n = newline, \t = tab, \w = single space. Also, | is a metacharacter that represents or. ? is a metacharacter representing "zero or one", * means "zero or more", and () are grouping metacharacters.
The "type" symbols represent pieces as follows: Pawn, King, kNight, Rook, Queen, Bishop.
This section lists clarifications and answers to common questions about Antichess.