Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified classes/__init__.py
100644 → 100755
Empty file.
5 changes: 3 additions & 2 deletions classes/board.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ def __init__(self, cols = 6, rows = 7, required_to_win = 4):
self.cols = cols
self.rows = rows
self.win = required_to_win
#set all the squares to none symbol
self.board = [[self.NONE] * rows for col in range(cols)]

def __str__(self):
b = '\n'
for row in self.board:
for row in self.board: #we add all the rows from the board to b
b += ''.join(row) + '\n'
b += " 0 1 2 3 4 5 6 \n"
b += " 0 1 2 3 4 5 6 \n" #add labels to each of the columns
return b
Empty file modified classes/exceptions.py
100644 → 100755
Empty file.
96 changes: 46 additions & 50 deletions classes/game.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,87 +1,83 @@
from sys import exit

from . import winchecker

#in this class we are defining all the general movement functions for the game
class Game:

P1 = 'P1'
P2 = 'P2'

def __init__(self, board):
self.current_player = self.P1
self.board = board
self.winchecker = winchecker.WinChecker(game=self, board=self.board)

def __init__(self, board): #function used to initially setup the game

self.current_player = self.P1 #set the first player to move as P1
self.board = board #set local board to equal the input board
self.winchecker = winchecker.WinChecker(game=self, board=self.board) #initiate the winchecker class and pass in the current game and board
print("Welcome to connect four! ")
self.make_move()

def make_move(self):
print("{}\n{}, you're up! ".format(self.board, self.current_player))
column_choice = self.get_column_choice()
self.make_move() #start game by calling for the first move

valid_column = self.place_checker(column=column_choice)
if not valid_column:
print("That column is full. Please enter a non-full column. ")
self.make_move()
def make_move(self): #this function will be used to get user input and make the necessary changes to the board
print("{}\n{}, you're up! ".format(self.board, self.current_player)) # ask current player to make a move
column_choice = self.get_column_choice() #get players move from function get_column_choice and store it
valid_column = self.place_checker(column=column_choice) #place the piece using place_checker function with the selected column
if not valid_column: #make sure it is legal
print("That column is full. Please enter a non-full column. ") #if column is not legal, tell the user
self.make_move() #call make_move again in order to make the user make a legal move
return False
win = True if self.check_for_win() else False
if not win:
win = True if self.check_for_win() else False #check if a player has won the game using check_for_win function
if not win: #if they did not win then change players and begin their turn
self.toggle_players()
self.make_move()
if win:
if win: #if a player has won then print the board and congratulate the winner
print(self.board)
print("\ncongratulations {}, you win!\n".format(self.current_player))

def get_column_choice(self):
def get_column_choice(self): #function used to get the users move
print("What column what you like to place your piece?\n")
column_choice = input("Valid choices are columns 0 through 6: ")
try:
if column_choice == "exit": exit()
column_choice = int(column_choice)
return column_choice if 0 <= column_choice <= 6 else self.get_column_choice()
except ValueError:
if column_choice == "exit": exit() #if player hits exit then quit
column_choice = int(column_choice) #otherwise store the column they chose
return column_choice if 0 <= column_choice <= 6 else self.get_column_choice() #if the user chose a location outside the board then get new input
except ValueError: #if player entered incorrect character then restart function
return self.get_column_choice()

def place_checker(self, column):
print("You've selected column {}".format(column))

if(self.board.board[0][column] != ' . '):

def place_checker(self, column): #this function will find the location for the piece the user has placed and put a piece there
print("You've selected column {}".format(column)) #tell the player what column they selected
if(self.board.board[0][column] != ' . '): #check to see if that column is full
# column is full, force player to re-choose
return False
lowest_available_row = self.find_lowest_row_in_column(column=column)
lowest_available_row = self.find_lowest_row_in_column(column=column) #find the lowest position in the chosen column
try:
self.board.board[lowest_available_row][column] = self.players_piece()
self.board.board[lowest_available_row][column] = self.players_piece() #place the players piece in that position
return True
except IndexError:
except IndexError: #just in case there is a array error we can catch it
# this should never happen
print("Array out of bounds error! Exiting...")
exit()

def find_lowest_row_in_column(self, column):
def find_lowest_row_in_column(self, column): #this function actually finds the next location in the selected column
column_as_list = []
for row in self.board.board:
column_as_list.append(row[column])

for row in self.board.board: #loop through all the rows in the board
column_as_list.append(row[column]) #add all these values to the array
try:
first_red = column_as_list.index(self.board.RED) - 1
first_red = column_as_list.index(self.board.RED) - 1 #find location above first red piece in the column
except ValueError:
first_red = None
first_red = None #set it to none if there are no red pieces
try:
first_blue = column_as_list.index(self.board.BLUE) - 1
first_blue = column_as_list.index(self.board.BLUE) - 1 #find the location above first blue piece in the column
except ValueError:
first_blue = None
first_blue = None #set it to none if there are no blue pieces

if first_blue == None and first_red == None:
return 5
elif first_blue == None or first_red == None:
return first_blue if first_blue != None else first_red
return 5 #if there are no pieces in the column then our row value is 5
elif first_blue == None or first_red == None:
return first_blue if first_blue != None else first_red # if there is only one colour then send the location above the highest one
else:
return min(first_blue, first_red)
return min(first_blue, first_red) #if there are two colours then send the location above the highest piece

def check_for_win(self):
def check_for_win(self): #this function simply checks to see if there is a winner using the winchecker class
return self.winchecker.check_for_win()

def toggle_players(self):
def toggle_players(self): #this function changes which player's turn it is
self.current_player = self.P2 if self.current_player == self.P1 else self.P1

def players_piece(self):
def players_piece(self): #this function returns the colour of the current players pieces
return self.board.RED if self.current_player == self.P1 else self.board.BLUE
38 changes: 19 additions & 19 deletions classes/winchecker.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
class WinChecker:

#this class is used to see if a player has connected four pieces
def __init__(self, game, board):
self.game = game
self.board = board

def check_for_win(self):
def check_for_win(self): #function is used to call the functions that check for different ways of winning
results = []
results.append(self.check_win_horizontally())
results.append(self.check_win_horizontally()) #append true if there is a win or append false if there is not
results.append(self.check_win_vertically())
results.append(self.check_win_diagonally_1())
results.append(self.check_win_diagonally_2())
try:
results.index(True)
# if the above statement does not generate a ValueError, then a win exists
# if the above statement does not generate a ValueError, then a win exists with except ValueError
return True
except ValueError:
return False

def check_win_horizontally(self):
def check_win_horizontally(self): #this functions checks to see if 4 are connected in any of the rows
win = False

for i in range(self.board.rows):
for i in range(self.board.rows): #we must loop through each of the rows
row = i
cols = [0, 1, 2, 3]
while not win:
while not win: #keep looping until win is changed to true
try:
# seq will represent the current 4 squares being examined
seq = []
for i in range(len(cols)):
# append current 4 squares to seq list
seq.append(self.board.board[row][cols[i]])
if self.check_equal(seq):
return True
if self.check_equal(seq): #check to see if all 4 pieces are the same
return True #if they are then we have a winner
else:
# increment each value in cols, this is how the horizontal
# win checking progresses from left to right
Expand All @@ -46,7 +46,7 @@ def check_win_horizontally(self):
def check_win_vertically(self):
win = False

for i in range(self.board.cols):
for i in range(self.board.cols):#we must check all the columns
col = i
rows = [0, 1, 2, 3]
while not win:
Expand All @@ -56,7 +56,7 @@ def check_win_vertically(self):
for i in range(len(rows)):
# append current 4 squares to seq list
seq.append(self.board.board[rows[i]][col])
if self.check_equal(seq):
if self.check_equal(seq): #if all 4 are the same then we have a winner
return True
else:
# increment each value in rows, this is how the horizontal
Expand All @@ -70,10 +70,10 @@ def check_win_vertically(self):

return win

def check_win_diagonally_1(self):
def check_win_diagonally_1(self):#this function checks for diagonals from top left toward bottom right
win = False

for i in range(self.board.cols):
for i in range(self.board.cols):
col = i
cols = [col, col+1, col+2, col+3]
rows = [0, 1, 2, 3]
Expand All @@ -84,21 +84,21 @@ def check_win_diagonally_1(self):
for i in range(len(rows)):
# append current 4 squares to seq list
seq.append(self.board.board[rows[i]][cols[i]])
if self.check_equal(seq):
if self.check_equal(seq): #check to see if all the squares match
return True
else:
# increment each value in rows, this is how the diagonal
# win checking progresses from top to bottom
for i in range(len(rows)):
rows[i] += 1
rows[i] += 1 #we must increment all the row values as we move our diagonal toward the bottom of the board
continue
except IndexError:
# we've hit the end of this col, break the loop and move to the next col
break

return win

def check_win_diagonally_2(self):
def check_win_diagonally_2(self): #this function checks for diagonals from bottom left toward top right
win = False

for i in range(self.board.cols):
Expand All @@ -112,19 +112,19 @@ def check_win_diagonally_2(self):
for i in range(len(rows)):
# append current 4 squares to seq list
seq.append(self.board.board[rows[i]][cols[i]])
if self.check_equal(seq):
if self.check_equal(seq): #check to see if all the squares match
return True
else:
# increment each value in rows, this is how the diagonal
# win checking progresses from top to bottom
for i in range(len(rows)):
rows[i] -= 1
rows[i] -= 1 #we must decrement all the row values as we move our diagonal toward the top of the board
continue
except IndexError:
# we've hit the end of this col, break the loop and move to the next col
break

return win

def check_equal(self, lst):
def check_equal(self, lst): #this function checks to see if all the pieces in the array are equal and not None
return lst[1:] == lst[:-1] if lst[0] != self.board.NONE else False
6 changes: 4 additions & 2 deletions connectfour.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from classes import board, game, exceptions

play_again = "yes"
#This file initiates the first game and board
#once the game is done, it will see if the player would like to continue playing

# game loop
while play_again == "yes":
b = board.Board()
#initiate a game with board b
g = game.Game(board=b)
#check to see if the player would like to play again and store answer to play_again
play_again = input("Would you like to play again? Enter yes to replay: ").lower().strip()