Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

In this problem, you will need to create a class named Board that implements some of the features of the Connect Four game. The Board

In this problem, you will need to create a class named Board that implements some of the features of the Connect Four game. The Board class will have three instance variables: there will be a two-dimensonal list (a list of lists) containing characters to represent the game area, name this 2D list data, and a pair of variables holding the number of rows and columns on the board (6 rows and 7 columns is standard), but your Board datatype will be able to handle boards of any size. Name these two instance variables height(for rows) and width (for columns).

Even as we allow arbitrary board sizes, however, we will preserve the four-in-a-row requirement for winning the game. Admittedly, this makes it hard to win the game on a 33 board

Your task is to write the Board class. Details appear here:

The Board class

Your Board class should have at least three instance variables:

A variable data storing the two-dimensional array (list of lists), which is the game board

A variable height storing the number of rows on the game board

A variable width storing the number of columns on the game board

Note that the two-dimensional list is a two-dimensional list of characters, which are just strings of length 1. You should represent an empty slot by , which is the space character not the empty string. You should represent player Xs checkers with an X (the capital x character) and you should represent player Os checkers with an O (the capital o character).

Warning!

A very difficult bug to find occurs if you use the zero0 character instead of the O character (capital-O) to represent one of the players. The problem occurs when you or the graders start comparing values in the board with the wrong one! Be sure to stay consistent with the capital-O character.

For the game, you must have a main function connect4() that calls all the other functions of your game. When we test your program, we will use this name.

Methods required for the Board class

You shall provide your Board class with the following methods. Be sure to try the supplied tests after writing each! The first two methods were probably written in class and are provided for copy-and-paste, below. However, they may have been written with magic numbers of 7 columns and 6 rows. If so, you will need to change the code so that arbitrarily-sized boards are available.

__init__, the constructor

__init__(self, width, height):This is a constructor for Board objects that takes two arguments. (Remember that self refers to the object being constructed and that it is not explicitly passed into the constructor.) This constructor takes in a number of columns and rows (7 and 6 are the connect-four standard, but our datatype will handle arbitrarily-sized boards). The constructor will set the values of the instance variables of the object. In addition, it will initialize the two-dimensional list representing the board. You will want to construct a list of lists very much in the spirit of the Game-of-Life lab. Note that you dont want self.data to contain all of the characters that go into printing the board only the ones that affect the play of the game. The extra characters will be generated in the __repr__ method.

__repr__, for printing or any string representation

__repr__(self):This method returns a string representing the Board object that calls it. Basically, each checker takes up one space, and all columns are separated by vertical bars (|). The columns are labeled at the bottom. Here is an example for a 6-row and 7-column (67) board (see the code below for details)

| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | --------------- 0 1 2 3 4 5 6 

In order to keep things in line, the column-numbering should be done mod 10, as this larger 5-row, 15-column (515) example shows:

| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ------------------------------- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 

One string, multiple lines?

The string represents the newline character in Python. Thus, you can get multiple lines into a single string by adding . For example,

>>> s = 'This is the top line.' >>> s += ' ' >>> s += 'This is a second line! ' >>> print(s) This is the top line. This is a second line! >>> 

Notice that the can be included within a string, as well. In this case, it added an extra blank line at the end of s.

The code to start with

Here is the code to start with. In __repr__, you are to add the bottom of the board and the numbers beneath it.

class Board: """ A datatype representing a C4 board with an arbitrary number of rows and cols. """ def __init__(self, width, height): """ Constructs objects of type Board. """ self.width = width self.height = height self.data = [[' '] * width for row in range(height)] # we do not need to return inside a constructor! def __repr__(self): """ Returns a string representation for an object of type Board. """ s = '' # the string to return for row in range(self.height): s += '|' # add the spacer character for col in range(self.width): s += self.data[row][col] + '|' s += ' ' # *** You add the bottom of the board # and the numbers underneath here *** return s # the board is complete, return it 

Next, implement the following methods in your Board class. Be sure to test each one after you write it its much easier to make sure each works one-at-a-time than trying to debug a huge collection of methods all at once. We expect to see doctests in every function/method that you write.

addMove, for dropping a checker into the board

addMove(self, col, ox):

This method takes two inputs: the first input col represents the index of the column to which the checker will be added; the second input ox will be a 1-character string representing the checker to add to the board. That is, ox should either be X or O (again, capital O, not zero). This would be a good place to add an assert function to check the input parameter ox. If due to a programming error ox has the wrong value, the assert will print a violation message and stop the program.

# Asserts the Boolean expression is true. # If not, it will print a violation message and stop the program. assert(ox == 'X' or ox == 'O') 

Remember that the checker slides down from the top of the board! Thus, your code will have to find the appropriate row number available in column col and put the checker in that row. In addMove you do not have to check that col is a legal column number or that there is space in column col. That checking is important, however. The next method, which is called isMoveLegal, will do just that

Testing addMove

Here is a sequence for testing addMove try it out!

>>> board = Board(7, 6) >>> board.addMove(0, 'X') >>> board.addMove(0, 'O') >>> board.addMove(0, 'X') >>> board.addMove(3, 'O') >>> board.addMove(4, 'O') # Cheat and let O go again! >>> board.addMove(5, 'O') >>> board.addMove(6, 'O') >>> board | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | | | |O| | | | | | | |X| | |O|O|O|O| --------------- 0 1 2 3 4 5 6 

clear, should clear the board that calls it.

Not much to say about clear(self) Its useful, though!

setBoard, for applying many moves to a board

This one is really useful for quickly creating a board to test your lookahead in next weeks assignment. Here is the code we used for setBoard you should include this in your Board class, because it makes testing much easier!

def setBoard(self, moveString): """ Takes in a string of columns and places alternating checkers in those columns, starting with 'X'. For example, call board.setBoard('0123456') to see 'X's and 'O's alternate on the bottom row, or board.setBoard('000000') to see them alternate in the left column. moveString must be a string of integers. """ nextChar = 'X' # start by playing 'X' for colString in moveString: col = int(colString) if 0 <= col < self.width: self.addMove(col, nextChar) if nextChar == 'X': nextChar = 'O' else: nextChar = 'X' 

isMoveLegal, for checking if a column is a legal move

isMoveLegal(self, col):

This method should return True if the calling object (of type Board) doesallow a move into column col. It returns False if column col is not a legal column number for the calling object. It also returns False if column col is full. Thus, this method should check to be sure that col is within the range from 0 to the last column and make sure that there is still room left in the column!

Testing isMoveLegal

Here is an example sequence for testing try it!

>>> board = Board(2, 2) >>> print(board) | | | | | | ----- 0 1 >>> board.addMove(0, 'X') >>> board.addMove(0, 'O') >>> print(board) |O| | |X| | ----- 0 1 >>> board.isMoveLegal(-1) False >>> board.isMoveLegal(0) False >>> board.isMoveLegal(1) True >>> board.isMoveLegal(2) False 

isFull, checks if the board is full

isFull(self):This method should return True if the calling object (of type Board) is completely full of checkers. It should return False otherwise. Notice that you can leverage isMoveLegal to make this method very concise! Unless youre supernaturally patient, youll want to test this on small boards:

Testing isFull

Here is an example sequence for testing (it uses setBoard, above)

>>> board = Board(2, 2) >>> board.isFull() False >>> board.setBoard('0011') >>> print(board) |O|O| |X|X| ----- 0 1 >>> board.isFull() True 

deleteMove, removes a checker from the board

deleteMove(self, col):This method should do the opposite of addMove. It should remove the top checker from the column col. If the column is empty, then deleteMove should do nothing. This function may not seem useful now, but it will become very useful when you try to implement your own Connect Four AI player

Testing deleteMove

Here is an example sequence for testing:

>>> board = Board(2, 2) >>> board.setBoard('0011') >>> board.deleteMove(1) >>> board.deleteMove(1) >>> board.deleteMove(1) >>> board.deleteMove(0) >>> print(board) | | | |X| | ----- 0 1 

isWinFor, checks if someone has won the game

isWinFor(self, ox):

This methods input ox is a 1-character checker: either X or O. [Another great place to use an assert that ox is properly set.] It should return True if there are four checkers of type ox in a row on the board. It should return False otherwise. Important Note: you need to check if the player has won horizontally, vertically, or diagonally (and there are two different directions for a diagonal win).

One way to approach this is to consider each possible anchor checker that might start a four-in-a-row run. For example, all of the anchors that might start a horizontal run (going from left to right) must be in the columns at least four places from the end of the board. That constraint will help you avoid out-of-bounds errors. Here is some starter code that illustrates this technique:

def isHorizontalWin(self, ox): """ Checks for a horizontal win. """ for row in range(self.height): for col in range(self.width - 3): if self.data[row][col] == self.data[row][col + 1] ==\ self.data[row][col + 2] == self.data[row][col + 3] == ox: return True return False 

Note the backslash character this tells Python that the line of code will continue on the next line of the file Note, too, the -3 that keeps the checking in bounds. Different directions will require different guards against going out of bounds.

We suggest you create a separate helper function for each of the tests that you need to test for a win. We got you started by creating isHorizontalWin, now create isVerticalWin and isDiagonalWin. (Should there be two versions of isDiagonalWin, one for each type of diagonal win?) Having a separate function for each test will make your code easier to test and understand. When your helper functions are working, call them from within the function isWinFor.

Warning We would advise against explicitly counting checkers to see if you reach four. The problem is that you must visit each checker in the right order. Vertical and horizontal orderings arent bad, but visiting each checker in diagonal order is neither easy nor informative. Its more convenient to check for all four checkers at once, as in the previous example.

This is an important method to test thoroughly! The following is only one test:

Testing isWinFor Here is an example sequence for testing:

>>> board = Board(7, 6) >>> board.setBoard('00102030') >>> print(board) | | | | | | | | |O| | | | | | | |O| | | | | | | |O| | | | | | | |O| | | | | | | |X|X|X|X| | | | --------------- 0 1 2 3 4 5 6 >>> board.isWinFor('X') True >>> board.isWinFor('O') True >>> board.clear() >>> board.setBoard('23344545515') >>> board | | | | | | | | | | | | | | | | | | | | | |X| | | | | | |X|X| | | | | |X|X|O| | | |O|X|O|O|O| | --------------- 0 1 2 3 4 5 6 >>> board.isWinFor('X') # diagonal True >>> board.isWinFor('O') False 

hostGame, hosts a full game of Connect Four

hostGame(self): This method brings everything together into the familiar game It should host a game of connect four, using the methods listed above to do so. In particular, it should alternate turns between X (who will always go first) and O (who will always go second). It should ask the user (with the input function) to select a column number for each move. See below for an example of how the interaction should work, but here are a few important points to keep in mind:

This method should print the board before prompting for each move.

After each input, you should check if the column chosen is a valid one. Thus, this method should detect illegal moves, either out-of-bounds or a full column, and prompt for another move instead. You do not have to check if the input is an integer, however; you may assume it will always be one.

This method should place the checker into its (valid) column. Then, it should check if that player has won the game or if the board is now full.

If the game is over for either reason, the game should stop, the board should be printed out one last time, and the program should report who won (or that it was a tie.)

If the game is not over, the other player should be prompted to make a move, and so on

Be sure to test this method by playing the game a few times (with each possible ending)!

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

SQL For Data Science Data Cleaning Wrangling And Analytics With Relational Databases

Authors: Antonio Badia

1st Edition

3030575918, 978-3030575915

More Books

Students also viewed these Databases questions

Question

Does any part of your business involve e-business?

Answered: 1 week ago