Question

In: Computer Science

Using Python to play Checkers: 1) Create classes to represent the necessary objects for game play....

Using Python to play Checkers:

1) Create classes to represent the necessary objects for game play. This will include, at least, the game board, the two types of pieces and the two sides. You will need to determine the best way to represent the relationship between them.

2) Set up one side of the board. Print the status of the board.

Solutions

Expert Solution

A simple checkers engine written in Python with the pygame 1.9.1 libraries.

This is almost completely object-oriented.
Functionalities include:
- Having the pieces and board drawn to the screen
- The ability to move pieces by clicking on the piece you want to move, then clicking on the square you would
like to move to. You can change your mind about the piece you would like to move, just click on a new piece of yours.
- Knowledge of what moves are legal. When moving pieces, you'll be limited to legal moves.
- Capturing
- DOUBLE capturing etc.
- Turn changes
- Automatic kinging and the ability for them to move backward
- Automatic check for and end game.
- A silky smooth 60 FPS!

import pygame, sys
from pygame.locals import *

pygame.font.init()

##COLORS##
# R G B
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GOLD = (255, 215, 0)
HIGH = (160, 190, 255)

##DIRECTIONS##
NORTHWEST = "northwest"
NORTHEAST = "northeast"
SOUTHWEST = "southwest"
SOUTHEAST = "southeast"

class Game:
   """
   The main game control.
   """

   def __init__(self):
       self.graphics = Graphics()
       self.board = Board()
      
       self.turn = BLUE
       self.selected_piece = None # a board location.
       self.hop = False
       self.selected_legal_moves = []

   def setup(self):
       """Draws the window and board at the beginning of the game"""
       self.graphics.setup_window()

   def event_loop(self):
       """
       The event loop. This is where events are triggered
       (like a mouse click) and then effect the game state.
       """
       self.mouse_pos = self.graphics.board_coords(pygame.mouse.get_pos()) # what square is the mouse in?
       if self.selected_piece != None:
           self.selected_legal_moves = self.board.legal_moves(self.selected_piece, self.hop)

       for event in pygame.event.get():

           if event.type == QUIT:
               self.terminate_game()

           if event.type == MOUSEBUTTONDOWN:
               if self.hop == False:
                   if self.board.location(self.mouse_pos).occupant != None and self.board.location(self.mouse_pos).occupant.color == self.turn:
                       self.selected_piece = self.mouse_pos

                   elif self.selected_piece != None and self.mouse_pos in self.board.legal_moves(self.selected_piece):

                       self.board.move_piece(self.selected_piece, self.mouse_pos)
                  
                       if self.mouse_pos not in self.board.adjacent(self.selected_piece):
                           self.board.remove_piece((self.selected_piece[0] + (self.mouse_pos[0] - self.selected_piece[0]) / 2, self.selected_piece[1] + (self.mouse_pos[1] - self.selected_piece[1]) / 2))
                      
                           self.hop = True
                           self.selected_piece = self.mouse_pos

                       else:
                           self.end_turn()

               if self.hop == True:                  
                   if self.selected_piece != None and self.mouse_pos in self.board.legal_moves(self.selected_piece, self.hop):
                       self.board.move_piece(self.selected_piece, self.mouse_pos)
                       self.board.remove_piece((self.selected_piece[0] + (self.mouse_pos[0] - self.selected_piece[0]) / 2, self.selected_piece[1] + (self.mouse_pos[1] - self.selected_piece[1]) / 2))

                   if self.board.legal_moves(self.mouse_pos, self.hop) == []:
                           self.end_turn()

                   else:
                       self.selected_piece = self.mouse_pos


   def update(self):
       """Calls on the graphics class to update the game display."""
       self.graphics.update_display(self.board, self.selected_legal_moves, self.selected_piece)

   def terminate_game(self):
       """Quits the program and ends the game."""
       pygame.quit()
       sys.exit

   def main(self):
       """"This executes the game and controls its flow."""
       self.setup()

       while True: # main game loop
           self.event_loop()
           self.update()

   def end_turn(self):
       """
       End the turn. Switches the current player.
       end_turn() also checks for and game and resets a lot of class attributes.
       """
       if self.turn == BLUE:
           self.turn = RED
       else:
           self.turn = BLUE

       self.selected_piece = None
       self.selected_legal_moves = []
       self.hop = False

       if self.check_for_endgame():
           if self.turn == BLUE:
               self.graphics.draw_message("RED WINS!")
           else:
               self.graphics.draw_message("BLUE WINS!")

   def check_for_endgame(self):
       """
       Checks to see if a player has run out of moves or pieces. If so, then return True. Else return False.
       """
       for x in xrange(8):
           for y in xrange(8):
               if self.board.location((x,y)).color == BLACK and self.board.location((x,y)).occupant != None and self.board.location((x,y)).occupant.color == self.turn:
                   if self.board.legal_moves((x,y)) != []:
                       return False

       return True

class Graphics:
   def __init__(self):
       self.caption = "Checkers"

       self.fps = 60
       self.clock = pygame.time.Clock()

       self.window_size = 600
       self.screen = pygame.display.set_mode((self.window_size, self.window_size))
       self.background = pygame.image.load('resources/board.png')

       self.square_size = self.window_size / 8
       self.piece_size = self.square_size / 2

       self.message = False

   def setup_window(self):
       """
       This initializes the window and sets the caption at the top.
       """
       pygame.init()
       pygame.display.set_caption(self.caption)

   def update_display(self, board, legal_moves, selected_piece):
       """
       This updates the current display.
       """
       self.screen.blit(self.background, (0,0))
      
       self.highlight_squares(legal_moves, selected_piece)
       self.draw_board_pieces(board)

       if self.message:
           self.screen.blit(self.text_surface_obj, self.text_rect_obj)

       pygame.display.update()
       self.clock.tick(self.fps)

   def draw_board_squares(self, board):
       """
       Takes a board object and draws all of its squares to the display
       """
       for x in xrange(8):
           for y in xrange(8):
               pygame.draw.rect(self.screen, board[x][y].color, (x * self.square_size, y * self.square_size, self.square_size, self.square_size), )
  
   def draw_board_pieces(self, board):
       """
       Takes a board object and draws all of its pieces to the display
       """
       for x in xrange(8):
           for y in xrange(8):
               if board.matrix[x][y].occupant != None:
                   pygame.draw.circle(self.screen, board.matrix[x][y].occupant.color, self.pixel_coords((x,y)), self.piece_size)

                   if board.location((x,y)).occupant.king == True:
                       pygame.draw.circle(self.screen, GOLD, self.pixel_coords((x,y)), int (self.piece_size / 1.7), self.piece_size / 4)


   def pixel_coords(self, board_coords):
       """
       Takes in a tuple of board coordinates (x,y)
       and returns the pixel coordinates of the center of the square at that location.
       """
       return (board_coords[0] * self.square_size + self.piece_size, board_coords[1] * self.square_size + self.piece_size)

   def board_coords(self, (pixel_x, pixel_y)):
       """
       Does the reverse of pixel_coords(). Takes in a tuple of of pixel coordinates and returns what square they are in.
       """
       return (pixel_x / self.square_size, pixel_y / self.square_size)  

   def highlight_squares(self, squares, origin):
       """
       Squares is a list of board coordinates.
       highlight_squares highlights them.
       """
       for square in squares:
           pygame.draw.rect(self.screen, HIGH, (square[0] * self.square_size, square[1] * self.square_size, self.square_size, self.square_size))  

       if origin != None:
           pygame.draw.rect(self.screen, HIGH, (origin[0] * self.square_size, origin[1] * self.square_size, self.square_size, self.square_size))

   def draw_message(self, message):
       """
       Draws message to the screen.
       """
       self.message = True
       self.font_obj = pygame.font.Font('freesansbold.ttf', 44)
       self.text_surface_obj = self.font_obj.render(message, True, HIGH, BLACK)
       self.text_rect_obj = self.text_surface_obj.get_rect()
       self.text_rect_obj.center = (self.window_size / 2, self.window_size / 2)

class Board:
   def __init__(self):
       self.matrix = self.new_board()

   def new_board(self):
       """
       Create a new board matrix.
       """

       # initialize squares and place them in matrix

       matrix = [[None] * 8 for i in xrange(8)]

       # The following code block has been adapted from
       # http://itgirl.dreamhosters.com/itgirlgames/games/Program%20Leaders/ClareR/Checkers/checkers.py
       for x in xrange(8):
           for y in xrange(8):
               if (x % 2 != 0) and (y % 2 == 0):
                   matrix[y][x] = Square(WHITE)
               elif (x % 2 != 0) and (y % 2 != 0):
                   matrix[y][x] = Square(BLACK)
               elif (x % 2 == 0) and (y % 2 != 0):
                   matrix[y][x] = Square(WHITE)
               elif (x % 2 == 0) and (y % 2 == 0):
                   matrix[y][x] = Square(BLACK)

       # initialize the pieces and put them in the appropriate squares

       for x in xrange(8):
           for y in xrange(3):
               if matrix[x][y].color == BLACK:
                   matrix[x][y].occupant = Piece(RED)
           for y in xrange(5, 8):
               if matrix[x][y].color == BLACK:
                   matrix[x][y].occupant = Piece(BLUE)

       return matrix

   def board_string(self, board):
       """
       Takes a board and returns a matrix of the board space colors. Used for testing new_board()
       """

       board_string = [[None] * 8] * 8

       for x in xrange(8):
           for y in xrange(8):
               if board[x][y].color == WHITE:
                   board_string[x][y] = "WHITE"
               else:
                   board_string[x][y] = "BLACK"


       return board_string
  
   def rel(self, dir, (x,y)):
       """
       Returns the coordinates one square in a different direction to (x,y).
       ===DOCTESTS===
       >>> board = Board()
       >>> board.rel(NORTHWEST, (1,2))
       (0,1)
       >>> board.rel(SOUTHEAST, (3,4))
       (4,5)
       >>> board.rel(NORTHEAST, (3,6))
       (4,5)
       >>> board.rel(SOUTHWEST, (2,5))
       (1,6)
       """
       if dir == NORTHWEST:
           return (x - 1, y - 1)
       elif dir == NORTHEAST:
           return (x + 1, y - 1)
       elif dir == SOUTHWEST:
           return (x - 1, y + 1)
       elif dir == SOUTHEAST:
           return (x + 1, y + 1)
       else:
           return 0

   def adjacent(self, (x,y)):
       """
       Returns a list of squares locations that are adjacent (on a diagonal) to (x,y).
       """

       return [self.rel(NORTHWEST, (x,y)), self.rel(NORTHEAST, (x,y)),self.rel(SOUTHWEST, (x,y)),self.rel(SOUTHEAST, (x,y))]

   def location(self, (x,y)):
       """
       Takes a set of coordinates as arguments and returns self.matrix[x][y]
       This can be faster than writing something like self.matrix[coords[0]][coords[1]]
       """

       return self.matrix[x][y]

   def blind_legal_moves(self, (x,y)):
       """
       Returns a list of blind legal move locations from a set of coordinates (x,y) on the board.
       If that location is empty, then blind_legal_moves() return an empty list.
       """

       if self.matrix[x][y].occupant != None:
          
           if self.matrix[x][y].occupant.king == False and self.matrix[x][y].occupant.color == BLUE:
               blind_legal_moves = [self.rel(NORTHWEST, (x,y)), self.rel(NORTHEAST, (x,y))]
              
           elif self.matrix[x][y].occupant.king == False and self.matrix[x][y].occupant.color == RED:
               blind_legal_moves = [self.rel(SOUTHWEST, (x,y)), self.rel(SOUTHEAST, (x,y))]

           else:
               blind_legal_moves = [self.rel(NORTHWEST, (x,y)), self.rel(NORTHEAST, (x,y)), self.rel(SOUTHWEST, (x,y)), self.rel(SOUTHEAST, (x,y))]

       else:
           blind_legal_moves = []

       return blind_legal_moves

   def legal_moves(self, (x,y), hop = False):
       """
       Returns a list of legal move locations from a given set of coordinates (x,y) on the board.
       If that location is empty, then legal_moves() returns an empty list.
       """

       blind_legal_moves = self.blind_legal_moves((x,y))
       legal_moves = []

       if hop == False:
           for move in blind_legal_moves:
               if hop == False:
                   if self.on_board(move):
                       if self.location(move).occupant == None:
                           legal_moves.append(move)

                       elif self.location(move).occupant.color != self.location((x,y)).occupant.color and self.on_board((move[0] + (move[0] - x), move[1] + (move[1] - y))) and self.location((move[0] + (move[0] - x), move[1] + (move[1] - y))).occupant == None: # is this location filled by an enemy piece?
                           legal_moves.append((move[0] + (move[0] - x), move[1] + (move[1] - y)))

       else: # hop == True
           for move in blind_legal_moves:
               if self.on_board(move) and self.location(move).occupant != None:
                   if self.location(move).occupant.color != self.location((x,y)).occupant.color and self.on_board((move[0] + (move[0] - x), move[1] + (move[1] - y))) and self.location((move[0] + (move[0] - x), move[1] + (move[1] - y))).occupant == None: # is this location filled by an enemy piece?
                       legal_moves.append((move[0] + (move[0] - x), move[1] + (move[1] - y)))

       return legal_moves

   def remove_piece(self, (x,y)):
       """
       Removes a piece from the board at position (x,y).
       """
       self.matrix[x][y].occupant = None

   def move_piece(self, (start_x, start_y), (end_x, end_y)):
       """
       Move a piece from (start_x, start_y) to (end_x, end_y).
       """

       self.matrix[end_x][end_y].occupant = self.matrix[start_x][start_y].occupant
       self.remove_piece((start_x, start_y))

       self.king((end_x, end_y))

   def is_end_square(self, coords):
       """
       Is passed a coordinate tuple (x,y), and returns true or
       false depending on if that square on the board is an end square.
       ===DOCTESTS===
       >>> board = Board()
       >>> board.is_end_square((2,7))
       True
       >>> board.is_end_square((5,0))
       True
       >>>board.is_end_square((0,5))
       False
       """

       if coords[1] == 0 or coords[1] == 7:
           return True
       else:
           return False

   def on_board(self, (x,y)):
       """
       Checks to see if the given square (x,y) lies on the board.
       If it does, then on_board() return True. Otherwise it returns false.
       ===DOCTESTS===
       >>> board = Board()
       >>> board.on_board((5,0)):
       True
       >>> board.on_board(-2, 0):
       False
       >>> board.on_board(3, 9):
       False
       """

       if x < 0 or y < 0 or x > 7 or y > 7:
           return False
       else:
           return True


   def king(self, (x,y)):
       """
       Takes in (x,y), the coordinates of square to be considered for kinging.
       If it meets the criteria, then king() kings the piece in that square and kings it.
       """
       if self.location((x,y)).occupant != None:
           if (self.location((x,y)).occupant.color == BLUE and y == 0) or (self.location((x,y)).occupant.color == RED and y == 7):
               self.location((x,y)).occupant.king = True

class Piece:
   def __init__(self, color, king = False):
       self.color = color
       self.king = king

class Square:
   def __init__(self, color, occupant = None):
       self.color = color # color is either BLACK or WHITE
       self.occupant = occupant # occupant is a Square object

def main():
   game = Game()
   game.main()

if __name__ == "__main__":
   main()


Related Solutions

Create a C++ code for the mastermind game using classes(private classes and public classes). Using this...
Create a C++ code for the mastermind game using classes(private classes and public classes). Using this uml as a reference.
Need this program Using Classes , Objects, Save to file, and Printbill Simple python assignment Write...
Need this program Using Classes , Objects, Save to file, and Printbill Simple python assignment Write a menu-driven program for Food Court. (You need to use functions!) Display the food menu to a user (Just show the 5 options' names and prices - No need to show the Combos or the details!) Ask the user what he/she wants and how many of it. (Check the user inputs) AND Use strip() function to strip your inputs. Keep asking the user until...
PYTHON BEGINNER Problem Create a program that lets the user play a simplified game of Blackjack,...
PYTHON BEGINNER Problem Create a program that lets the user play a simplified game of Blackjack, which is played between the user and an automated dealer as follows. The dealer shuffles a standard deck of 52 cards, draws two cards, and gives them to the user. The user can then choose to request another card from the dealer, adding it to their hand. The user can continue to request cards or choose to stop at any time. After each time...
Objectives: 1. Create classes to model objects Instructions: 1. Create a new folder named Lab6 and...
Objectives: 1. Create classes to model objects Instructions: 1. Create a new folder named Lab6 and save all your files for this lab into this new folder. 2. You can use any IDE (such as SciTE, NetBeans or Eclipse) or any online site (such as repl.it or onlinegdb.com) to develop your Java programs 3. All your programs must have good internal documentation. For information on internal documentation, refer to the lab guide. Problems [30 marks] Problem 1: The Account class...
Objectives: 1. Create classes to model objects Instructions: 1. Create a new folder named Lab6 and...
Objectives: 1. Create classes to model objects Instructions: 1. Create a new folder named Lab6 and save all your files for this lab into this new folder. 2. You can use any IDE (such as SciTE, NetBeans or Eclipse) or any online site (such as repl.it or onlinegdb.com) to develop your Java programs 3. All your programs must have good internal documentation. For information on internal documentation, refer to the lab guide. Problem : The Fraction class (Filename: TestFraction.java) Design...
In python please Problem Create two server objects using the class create a function, biggest_server_object_sum, outside...
In python please Problem Create two server objects using the class create a function, biggest_server_object_sum, outside of the ServerClass class, that: 1. Takes the IP 2. Sums the octets of the IP together (example 127.0.0.1 = 127+0+0+1 = 128) 3. Returns the Server object with the larger sum Example: server_one = ServerClass("127.0.0.1") server_two = ServerClass("192.168.0.1") result = biggest_ip_sum(server_one, server_two) print(result) Hint Modify get_server_ip in the previous problem. -------------------- Please use this code to start class ServerClass: """ Server class for...
This task is about classes and objects, and is solved in Python 3. We will look...
This task is about classes and objects, and is solved in Python 3. We will look at two different ways to represent a succession of monarchs, e.g. the series of Norwegian kings from Haakon VII to Harald V, and print it out like this: King Haakon VII of Norway, accession: 1905 King Olav V of Norway, accession: 1957 King Harald V of Norway, accession: 1991 >>> Make a class Monarch with three attributes: the name of the monarch, the nation...
Write a program using Python that allows the user to play a guessing game (please provide...
Write a program using Python that allows the user to play a guessing game (please provide a picture of code so it is easier to read). The game will choose a "secret number", a positive integer less than 10000. The user has 10 tries to guess the number. Requirements: Normally, we would have the program select a random number as the "secret number". However, for the purpose of testing your program (as well as grading it), simply use an assignment...
Classes and Objects Write a program that will create two classes; Services and Supplies. Class Services...
Classes and Objects Write a program that will create two classes; Services and Supplies. Class Services should have two private attributes numberOfHours and ratePerHour of type float. Class Supplies should also have two private attributes numberOfItems and pricePerItem of type float. For each class, provide its getter and setter functions, and a constructor that will take the two of its private attributes. Create method calculateSales() for each class that will calculate the cost accrued. For example, the cost accrued for...
Make a Tic Tac Toe game for 2 players to play using 2D arrays and classes....
Make a Tic Tac Toe game for 2 players to play using 2D arrays and classes. Do not add more #include functions other than the ones listed (such as #include <stdio.h> etc). Using the tictactoeGame class, write a main program that uses a tictactoeGame to implement a game in which two players (you and a friend) take turns placing X’s and O’s onto the board. After each turn, the current board configuration should be displayed, and once a player connects...
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT