CSC108H Assignment 2, Summer 2011
Due Monday, June 27, 11:55 pm
Introduction
The purpose of this assignment is to give you more practice
writing functions and programs in Python, and in particular
writing code with strings, lists, and loops.
You should spend at least one hour
reading through this handout to make sure you understand what is
required, so that you don't waste your time going in circles, or worse yet,
hand in something you think is correct and find out later that you
misunderstood the specifications.
Highlight the handout, scribble on it, and find all the things
you're not sure about as soon as possible.
It is probably worth spending at least a day thinking about the assignment before writing code of any sort. Try to think through potential problems to catch them before they appear. This will save hoers of frustrating debugging time.
Portable game notation
Chess games are often written down in what is known as algebraic game notation. This has been extended to a file type known as .pgn for portable game notation. These are files that chess programs can read in order to replay games or look at commentary.
We will be building a basic pgn parser that will be working with a limited version of pgn files, that will be able to output game summaries, game descriptions, and that will be able to keep track of what the board looks like after each move. This will involve lots of string and list manipulation.
Our version of .pgn
We will have a slightly simpler version of .pgn notation. A description of .pgn can be found here. We will have the following changes:
- The only tags we will use are Event, Site, Date, White, Black, Result.
- There will always be some tags. In particular the players will always be there. However, it is not true that Event, Site and Date will always be there.
- All files that we will use are guaranteed to have only one game in them.
- None of our games will have alternative lines. This means that each game will only contain a single line of play.
- None of our games will have any annotations. This means that we don't need to worry about seeing $ signs in the .pgn files.
- None of our games will have any en passant captures.
- Our .pgn files will not contain any comments.
- All move indicators will be for white. That is, all moves will be denoted by "N. whmv blmv" where N is an integer, whmv is the notation for the white move, and blmv is the notation for the black move. The only exception to this will be if the game ends before blacks move. You will never see anything like "N... blmv".
- You do not need to worry about incorrectly formatted files.
Things that you do have to worry about:
- There will be checks, captures and checkmates.
- There will be pawn promotions.
- There will be moves where the piece that is moving is not perfectly specified by the final square and piece type.
A summary of .pgn notation
- The first part of a .pgn file is tags. These are written in the format: [tag_name: "tag_information"]
- Each tag is on a single line.
- The tags occur in the order Event, Site, Date, White, Black, Result
- Result is 1-0 for a white win, 0-1 for a black win, 1/2-1/2 for a draw.
- Following the tags, the move notation starts.
- Each turn has the format: N. whmv blmv
- N is the turn number (starts at 1.), whmv is the move notatio for the white mv, and blmv is the notation for the black move
- If the move results in a check, the mv ends in +, if it ends in checkmate, the mv ends in #
- Kingside castling is indicated by O-O, queenside castling by O-O-O. Note that these are capital os and not 0s.
- Generally a move is indicated by Amn, where A is the piece name, and mn is the square that the piece moves to in algebraic notation (for example a1).
- pawn moves omit the A, rooks are denoted by R, bishops by B, knights by N, the king by K, the queen by Q.
- Captures are denoted by Axmn. Here x represents the character x. For a pawn capture A is replaced with the column in which the pawn started. So a pawn capture from a2 to b3 would be axb3.
- Pawn promotions are denoted by mn=A, where mn is the square on which the pawn is promoted, = is the equals sign, and A is the type of piece to which the pawn was promoted.
- Sometimes the final square and piece type is not enough information to specify the moving piece. In this case we may additionally specify by adding the letter, number or letter and number combination in that order of preference. So Nge2 means the knight on the g column moves to e2, N3e3 means that the knight on the third row moves to e3 and Ng3e2 means the the knight on g3 moves to e3.
- The movetext terminates with the result of the game.
Your Task
You are going to write a program that takes a string obtained from a .pgn file, and extracts the tag and move information from it, as well as providing a function that will return board information as specified points in the game. For tag information, the information must be returned as a string, with each of the tags matching the following format:
- Event:
This game was played at event_name.
- Site:
This game was played in site_name.
- Date:
This game was played on date_info.
- White, Black, Result:
This game was played between white_name with white and black_name with black, and resulted in result_info.
Here result info should be a draw
in case of a draw, a win for white
if white won, and otherwise a win for black
Each of the preceding tags must be on it's own line. The move information must similarly be written in a restrictive format, with each move being it's own line:
- A standard move:
player_colour moves piece_name from initial_location to final_location
- player colour is White or Black, piece_name is is pawn, rook, knight, bishop, queen, or king
- A capture:
player_colour captures the piece_name at final_location with the piece_name at initial_location
- Ending the line: If it is a regular move, end the line with a period. If the move causes check, end it with
; causing check.
, if the move causes mate, end it with ; causing checkmate.
If the move results in a promotion end it with , promoting the pawn to piece_name
followed by the appropriate ending depending on whether there is check, mate, or nothing.
- Castling is denoted by
player_colour castles castle_side
, where castle_side is either kingside or queenside. This is followed by the appropriate ending depending on whether there is check, mate, or nothing.
- The final line must have the result of the game. This can be
The game ends in a draw.
or player_colour wins by win_type
where win_type is either mate or resignation.
The final major function that you need to write will return a two-dimensional list that represents the chess board. The first dimension corresponds to the letters in algebraic notation, with 0 corresponding to 'a', 1 to 'b' and so on. The second corresponds to number with 0 corresponding to '1', 1 corresponding to '2' and so on. The list elements should be of the form 'cA', where c is 'w' or 'b' depending on the colour of the piece, and A is the type of piece, so 'P' for pawn, 'B' for bishop, 'N' for knight, 'R' for rook, 'K' for King and 'Q' for queen. Empty squares should be be denoted by the empty string.
To be explicit, you are to fill in game_summary
, move_summary
, board_state
, from_alg_notn
and to_alg_notn
in assignment2.py. You should not modify load_game_file
. You may use the if __name__ == '__main__' block for testing if you which, but you are not obliged to.
Additional requirements
-
Where a docstring says a function can assume something about a parameter
(e.g., it might say "text is a non-empty list") the function should not check that
this thing is actually true.
Instead, when you call the function make sure that it is indeed true.
-
Do not add any user input or output
-
You must not use any
break
or continue
statements.
Any functions that do will receive a mark of zero.
We are imposing this restriction (and we have not even taught you these
statements)
because they are very easy to "abuse," resulting in terrible code.
How to tackle this assignment
This program is much larger than what you wrote for Assignment 1, so you'll
need a good strategy for how to tackle it. Here is our suggestion. First download the code from assignment2.py.
Principles:
-
To avoid getting overwhelmed, deal with one function at a time.
Start with functions that don't call any other functions; this will allow
you to test them right away. The steps listed below give you a
reasonable order in which to write the functions.
-
For each function that you write, plan test cases for that function and
actually write the Python code to implement those tests before you
write the function.
It is hard to have the discipline to do this, but you will have a huge
advantage over your peers if you do.
-
Keep in mind throughout that any function you have might be a useful helper
for another function.
Part of your marks will be for taking advantage of opportunities to call an existing
function.
-
As you write each function, begin by designing it in English, using only a few
sentences. If your design is longer than that, shorten it by describing the
steps at a higher level that leaves out some of the details.
When you translate your design into Python, look for steps that are described at such
a high level that they don't translate directly into Python.
Design a helper function for each of these, and put a call to the helpers into
your code.
Don't forget to write a great docstring for each helper!
Advice:
This program can be broken down into several separate aspects. Some of these follow:
-
Read this handout thoroughly and carefully, making sure you understand everything
in it, particularly the the subset of .pgn you are supposed to cover.
- To parse this, one needs to do several things.
- One needs to extract the tags.
- Given a tag, one needs to extract the pertinent information.
- One needs to separate the tags from the move text.
- Given the movetext one needs to extract the individual moves from it.
- Given an individual move, one needs to extract all the information from it.
- Once you're able to do this, one needs to then take that information and keep track of it.
- If you can extract a move, take out the information from it, and keep track of it, then you should be able to loop through the movetext.
- Both the game summary and the board will probably rely on a bunch of the same code, so make sure to intelligently reuse code.
- Make sure to test the code as you're writing each small bit, so that you can ferret out problems early.
- The shell can be useful for testing half-written functions.
- A set of .pgn files can be found here. Make sure that the files themselves are in the same directory as assignment2.py.
Marking
These are the aspects of your work that we will
focus on in the marking:
-
Correctness: Your code
should perform as specified.
Correctness, as measured by our tests, will count for the
largest single portion of your marks.
-
Docstrings: For each function that you design from scratch,
write a good
docstring
.
(Do not change the docstrings that we have already written for you.)
Make sure that you read the Assignment rules page for some important
rules and guidelines about docstrings.
-
Internal comments: Within
functions, the more complicated parts of your code should also be
described using "internal" comments.
For this assignment, internal comments will be more important
than on assignment 1.
-
Programming style: Your variable names should be meaningful and
your code as simple and clear as possible.
-
Good use of helper functions: If you find yourself repeating a task, you should add
a helper function and call that function instead of duplicating the
code.
And if a function is more than about 20 lines long, consider introducing
helper functions to do some of the work -- even if they will only be called once.
-
Formatting style: Make sure that you read the Assignment rules page for some important
rules and guidelines about formatting your code.
You must hand in your work electronically, using the MarkUs system.
Log in to it
here,
using your cdf login and password.
To declare your partnership, one of you needs to invite the other
to be a partner, and then they need to accept the invitation.
To invite a partner, navigate to the Assignment 2 page,
find "Group Information", and click on "Invite".
You will be prompted for the other student's cdf user name; enter it.
To accept an invitation, find "Group Information" on the Assignment 2 page,
find the invitation listed there, and click on "Join".
Note that, when working in a pair, only one person should submit the assignment.
To submit your work, again navigate to the Assignment 2 page,
then click on the "Submissions" tab near the top.
Click "Add a New File" and either type a file name or use the "Browse" button
to choose one.
Then click "Submit".
For this assignment, hand in just one file:
Once you have submitted, be sure to check that you have submitted
the correct version; new or missing files will not be accepted after
the due date.
Remember that spelling of filenames, including case, counts.
If your file is not named exactly as above,
your code will receive zero for correctness.