Please help me with my connect 4 game im beyond despair and I have it due in 4 days - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Homework (https://python-forum.io/forum-9.html) +--- Thread: Please help me with my connect 4 game im beyond despair and I have it due in 4 days (/thread-36151.html) |
Please help me with my connect 4 game im beyond despair and I have it due in 4 days - JuanT05 - Jan-21-2022 THIS IS NOT PART OF THE CODE ONLY SOME GUIDING TOWARDS WHERE MY PROBLEMS ARE The function that checks for diagonal lines wont detect them. ------------------------------------------------------------------------------------------------------------------------ code starts here BLANK = "*" # sets the character for the BLANK positions ################################################################## # DECLARE the variables used in the program as required by CIE ### ################################################################## # Board(0:6, 0:7) : str (but ignore row 0 and column 0) # ThisPlayer : str[1] # GameFinished, WinnerFound : bool # ColumnNumber : int # ValidColumn, ValidRow : int def InitialiseBoard(): global Board Board = [[BLANK] * 7 for x in range(7)] # Creates the array of blank values def SetUpGame(): # Set up the parameters for the beginning of the game global ThisPlayer global GameFinished ThisPlayer = "O" # Player O always starts GameFinished = False def OutputBoard(): print("The board as it currently stands...\n") print("Choose your column") print("1 2 3 4 5 6 7\n") for Row in range(6, 0, -1): for Column in range(7): print(Board[Row][Column], end=" ") print() print() def ColumnNumberValid(): # returns whether or not the column number is valid global ColumnNumber Valid = False if (ColumnNumber >= 0) and (ColumnNumber <= 6): if Board[6][ColumnNumber] == BLANK: # at least 1 empty space in column Valid = True return Valid def ThisPlayerChoosesColumn(): # returns a valid column number global ColumnNumber print("Player ", ThisPlayer, "'s turn.") ColumnNumber = int(input("Enter a valid column number: ")) - 1 while ColumnNumberValid() == False: # check whether the column number is valid ColumnNumber = int(input("Enter a valid column number: ")) - 1 return ColumnNumber def FindNextFreePositionInColumn(): # returns the next free position ThisRow = 1 while Board[ThisRow][ValidColumn] != BLANK: # find first empty cell ThisRow += 1 return ThisRow def ThisPlayerMakesMove(): global Board global ValidColumn global ValidRow ValidColumn = ( ThisPlayerChoosesColumn() ) # use a module to return valid column number ValidRow = FindNextFreePositionInColumn() # use a module to return row number Board[ValidRow][ValidColumn] = ThisPlayer def CheckHorizontalLineInValidRow(): global WinnerFound for i in range(5): if i < 5: if ( (Board[ValidRow][i - 1] == ThisPlayer) and (Board[ValidRow][i] == ThisPlayer) and (Board[ValidRow][i + 1] == ThisPlayer) and (Board[ValidRow][i + 2] == ThisPlayer) ): WinnerFound = True def CheckVerticalLineInValidColumn(): global WinnerFound if (ValidRow == 4) or (ValidRow == 5) or (ValidRow == 6): if ( (Board[ValidRow][ValidColumn] == ThisPlayer) and (Board[ValidRow - 1][ValidColumn] == ThisPlayer) and (Board[ValidRow - 2][ValidColumn] == ThisPlayer) and (Board[ValidRow - 3][ValidColumn] == ThisPlayer) ): WinnerFound = True def CheckDiagonalRight(): global WinnerFound for i in range(5): if ( (Board[ValidRow][i] == ThisPlayer) and (Board[ValidRow + 1][i + 1] == ThisPlayer) and (Board[ValidRow + 2][i + 2] == ThisPlayer) and (Board[ValidRow + 3][i + 3] == ThisPlayer) ): WinnerFound = True def CheckDiagonalLeft(): global WinnerFound for i in range(7): if i > 4: if ( (Board[ValidRow][i] == ThisPlayer) and (Board[ValidRow + 1][i - 1] == ThisPlayer) and (Board[ValidRow + 2][i - 2] == ThisPlayer) and (Board[ValidRow + 3][ValidColumn - 3] == ThisPlayer) ): WinnerFound = True def CheckDiagonalLine(): global WinnerFound if ValidRow < 4: CheckDiagonalRight() elif ValidRow == 4: CheckDiagonalLeft() CheckDiagonalRight() elif ValidRow > 4: CheckDiagonalLeft() def CheckForFullBoard(): global GameFinished BlankFound = False ThisRow = 0 while (ThisRow != 6) and (BlankFound == False): ThisColumn = 0 ThisRow += 1 while (ThisColumn != 7) and (BlankFound == False): ThisColumn += 1 if Board[ThisRow][ThisColumn] == BLANK: BlankFound = True if BlankFound == False: print("It is a draw") GameFinished = True def CheckIfThisPlayerHasWon(): global WinnerFound global GameFinished WinnerFound = False CheckHorizontalLineInValidRow() if WinnerFound == False: CheckVerticalLineInValidColumn() if WinnerFound == False: CheckDiagonalLine() if WinnerFound == True: GameFinished = True print(ThisPlayer, " is the winner") else: CheckForFullBoard() def SwapThisPlayer(): global ThisPlayer if ThisPlayer == "O": ThisPlayer = "X" else: ThisPlayer = "O" # ******************* This is the main program ****************** def main(): InitialiseBoard() # Call board set up routines SetUpGame() OutputBoard() # Below is the loop for players to make moves while GameFinished == False: ThisPlayerMakesMove() OutputBoard() CheckIfThisPlayerHasWon() if GameFinished == False: SwapThisPlayer() # next player takes their turn main() # Call the main program RE: Please help me with my connect 4 game im beyond despair and I have it due in 4 days - deanhystad - Jan-22-2022 I think it is a great idea that you test for the winner based on the last move, but your tests are all wrong. You need to count the number of contiguous markers in a line. You are kind of doing that but forgetting that there might be markers before and after the recently played marker. If the last marker was placed at (2, 2) four consecutive markers could be in (0,2), (1,2), (2,2), (3,2). You look in only one direction. My test for checking if there are 4 markers in a row would look like this: def get(row, column, board): """Return marker in board[row][column] if row and column are valid, else return None""" if 0 <= row < ROWS and 0 <= column <= COLUMNS: return board[row][column] return None def winningRow(row, column, board): """Return True if there are 4 or more matching markers in a row""" marker = get(row, column, board) count = 1 c = column-1 while get(row, c) == marker: count += 1 c -= 1 c = column+1 while get(row, c) == marker: count += 1 c += 1 return count >= 4Using a pattern like this you could write a generic tester that would work for rows, columns and diagonals. A few comments about your code: It is good that you are breaking up your code into functions, but you lose much of the benefits of functions by using global variables to pass information to and from the function. For example: def ColumnNumberValid(): # returns whether or not the column number is valid global ColumnNumber Valid = False if (ColumnNumber >= 0) and (ColumnNumber <= 6): if Board[6][ColumnNumber] == BLANK: # at least 1 empty space in column Valid = True return Validshould look like this: def columnNumberValid(column, board): """"Returns True if the column is in range and has an empty spot""" if 0 <= column < COLUMNS: # Do not sprinkle code with numerical constants like 6. return board[ROWS-1][column] == BLANK return FalseThis might be even better: def columnNumberValid(column, board): try: return board[ROWS-1][column] == BLANK except IndexError: return FalseOther than BLANK (and ROWS and COLUMNS in my example) I don't think any of your variables should be global. Initialize the variables in main() and pass them as arguments to your functions. You should avoid functions that don't provide any real benefit. I would get rid of these functions and move the code back into main. def InitialiseBoard(): global Board Board = [[BLANK] * 7 for x in range(7)] # Creates the array of blank values def SetUpGame(): # Set up the parameters for the beginning of the game global ThisPlayer global GameFinished ThisPlayer = "O" # Player O always starts GameFinished = FalseNone of these functions are used more than once, they don't reduce the length of the code, and I don't think they make your code easier to understand. Do not duplicate code. This loop: print("Player ", ThisPlayer, "'s turn.") ColumnNumber = int(input("Enter a valid column number: ")) - 1 while ColumnNumberValid() == False: # check whether the column number is valid ColumnNumber = int(input("Enter a valid column number: ")) - 1 return ColumnNumberis better written as this: print("Player ", ThisPlayer, "'s turn.") while True: ColumnNumber = int(input("Enter a valid column number: ")) - 1 if ColumnNumberValid(): return ColumnNumberEach duplicate line of code is a potential maintenance nightmare. I don't understand the logic of this function. def CheckForFullBoard(): global GameFinished BlankFound = False ThisRow = 0 while (ThisRow != 6) and (BlankFound == False): ThisColumn = 0 ThisRow += 1 while (ThisColumn != 7) and (BlankFound == False): ThisColumn += 1 if Board[ThisRow][ThisColumn] == BLANK: BlankFound = True if BlankFound == False: print("It is a draw") GameFinished = TrueThe first while loops sets ThisColumn = 0 and ThisRow = 6. Why not just set ThisColumn=0 and thisRow=6 instead of looping. Better yet, you know how many moves it takes to fill the board. Why not get rid of the full board check and do something more like this: for _ in range(ROWS*COLUMNS): ThisPlayerMakesMove() OutputBoard() CheckIfThisPlayerHasWon() SwapThisPlyer() if GameFinished: break;If you have 7 rows and 7 columns, the board is full after players make 49 moves. There is no reason to check the board. |