$ mkdir ~/cs170/labs/lab11 $ cd ~/cs170/labs/lab11
So you saw how to create and catch exceptions. However, you don't really understand why you would use them. Let's talk briefly about that, before we get into the test review.
In addition to the written portion of the test, there will be a coding portion. This will be done on the computers. For practice, attempt the following exercises, alone:
Point_3D
, which represents a
point in 3 dimensional space. This class should have methods for
adding points together (which is just the sum of each component).
This method should return a new Point_3D, instead of modifying one
of the points. You should also include a method that can be used
when printing the point.
Bin
, which stores a list of
all of the elements currently inside of the bin. Create another
class called RecycleBin
, which inherits the Bin class.
Your RecycleBin class should have at least a method called
empty
, which removes everything from the bin.
We didn't quite get through this one last time, so let's finish it up today!
Battleship is a classic board game that consists of two 2-dimensional grids containing some number of battleships. Players take turns firing "missiles" at locations in their opponents 2-dimensional grid. This game has a reputation for being a very easy game to cheat at.
Let's see if we can use Exceptions to help make it a little harder to cheat at the game. You are going to make a very simple, single player version of battleship. You will read in a battleship specification from a file, and allow a player to take turns choosing grid locations to destroy. Your program should handle invalid files and invalid player input gracefully.
Create a file called battleship.py to house your battleship
program. Your program should have at least two functions:
read_configuration_file(file_name)
and
process_user_input(game_board)
.
read_configuration_file(file_name)
should read a
battleship configuration file specified in the parameter. This file
will be of the following format:
1000000000 1000000000 0011110000 0000000000 0111000010 0000000010 0000000010 0000000010 0011100010 0000000000Which represents this battleship board.
Notice that a valid configuration is a 10 × 10 board, with 17
1's on the board. Any other board is invalid. You should define a
InvalidBattleshipBoard
exception, and your read function
should raise this exception if the board is invalid.
Once you have read a valid board, you should call
process_user_input(game_board)
. This should read input
from the user via the command line. The user should be able to
specify coordinates like a traditional battleship game: Rows specified
with letters from A-J, and columns specified with an integer in the
range [1-10]. If the user doesn't specify a valid coordinate, you
should raise an InvalidCoordinate
exception, which of
course you should write.
If the users input is valid, you should process it as normal. Marks hits with x's and misses with o's.
The following is a sample output without exception handling. You should handle the exceptions you see below gracefully.
$ cat default.in 1000000000 1000000000 0011110000 0000000000 0111000010 0000000010 0000000010 0000000010 0011100010 0000000000 $ cat error.in 1111111111 1111111110 1111111100 1111111000 1111110000 1111100000 1111000000 1110000000 1100000000 1000000000 $ python3 >>> import battleship >>> board = battleship.read_configuration_file("default.in") >>> battleship.process_user_input(board) Current Board: 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 Your move: A1 HIT! x000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 Your move: A2 MISS xo00000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 0000000000 Your move: Z11 ...snip... During handling of the above exception, another exception occurred: Traceback (most recent call last): File "battleship.py", line 77, inprocess_user_input(board) File "battleship.py", line 70, in process_user_input " is not a valid coordinate!") __main__.InvalidCoordinate: Z11 is not a valid coordinate! >>> board = battleship.read_configuration_file("error.in") Traceback (most recent call last): File "battleship.py", line 76, in board = read_configuration_file(fname) File "battleship.py", line 41, in read_configuration_file raise InvalidBattleshipBoard("Invalid board size, or invalid number of pieces") __main__.InvalidBattleshipBoard: Invalid board size, or invalid number of pieces >>> quit()
You can open a file in python using the open
function. This function takes two parameters: a string that is
the name of the file you want to open, and a string representing
your permissions. For this, you only need 'r' (read)
permissions.
Don't forget to close your files when you are done!
Your exception classes are going to be very similar. As a matter of fact, if you are sneaky you can define the classes with very little code.
You are going to want to catch various exceptions when reading files, so that you can raise your InvalidBattleshipBoard exception. You also need to keep a running sum of the number of 1's on the board. If it does not equal 17 after reading the entire board, you also have an InvalidBattleshipBoard.
Remember, you can use ord
to convert from strings
to ASCII values. You can actually decompose every ASCII
character to an integer this way.
Instead of having an if statement for handling invalid
coordinates, you can simply try/except an
IndexError
when attempting to check the value of
the game board. If an IndexError is raised, you just re-raise
(by raising an exception in the exception handler) and
InvalidCoordinate exception.
An easy way to make the program more "idiot-proof" is to make it incredibly easy to interact with. Instead of relying on the user to type coordinates to input, simply have them click on locations they want to "fire" missiles at.
That's right, it's tkinter
time! Create a grid that
the user can click on, and allow them to click to reveal locations.
Note that this does not mean you can completely get rid of
exceptions. You should raise an InvalidMove
exception
if they click on a location that is already uncovered.
It seems that raising an exception in the graphical program should have a different connotation than doing so via the command line. especially since it is a little difficult to notice that an exception was actually raised when using the graphical program.
Look at the documentation for tkMessageBox
dialogs. You should create a showerror
pop-up window
upon raising the exception. You will need the following import
statement in your code:
from tkinter import messagebox
When you have finished, create a tar file of your lab11
directory. To create a tar file, execute the following commands:
cd ~/cs170/labs tar czvf lab11.tgz lab11/
To submit your activity, go to cseval.roanoke.edu. You should
see an available assignment called Lab Assignment 11
.
Make sure you include a header listing the authors of the file.