Mz. Creep
Mz. Creep

Reputation: 31

Python: Connect Four Alternating turns

I've been working on a program that implements the game of connect 4 and I've hit a snag. Here's my output:

>>> ================================ RESTART ================================
>>> 
Player 1 please pick a column: 5
-----------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
-----------------------------
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   | x |   |
-----------------------------
Player 2 please pick a column: 6
-----------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
-----------------------------
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   | o |
-----------------------------

So basically the board isn't "updating" when alternating turns Essentially my code should end up looking like this:

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

I'm not too sure what I have to do to get the board to update properly. I've tried messing around with the print functions but the output ends up getting worse than before. Here is my code:

from player import *

def play_game(board, player1,player2):
    b = ConnectFour()
    f = Human(1)
    g = Human(2)
    while True:
        f.play_turn(1)
        if b.is_game_over() == None:
            g.play_turn(2)
            if b.is_game_over() == None:
                pass
            else:
                print "Player 2 wins"
                break
        else:
            print "Player 1 wins"
            break

Basically: Player 1 plays, then we check if there's a winner if not player two plays, and so on. And this calls a separate class:

class Human(Player):
    def play_turn(self,board):
        super(Human, self).play_turn(board)
        b = ConnectFour()   
        x = raw_input("Player %s please pick a column: " % self.playernum)
        b.play_turn(self.playernum, int(x))
        b.print_board()

Any ideas, input or advice would be greatly appreciated!

Upvotes: 2

Views: 2898

Answers (1)

abarnert
abarnert

Reputation: 365807

The problem is that, although you're passing board objects around, you ignore them and just create new ones everywhere.

First, look at Human.play_turn:

def play_turn(self,board):
    super(Human, self).play_turn(board)
    b = ConnectFour()   
    x = raw_input("Player %s please pick a column: " % self.playernum)
    b.play_turn(self.playernum, int(x))
    b.print_board()

This passes board to the super method Player.play_turn, but then it creates a new board b = ConnectFour(), and everything it does is to that board, not the original one.

Likewise, in play_game, you take a board, and a player1 and a player2, but do nothing with them, and instead create new ones called b, f, and g.

So, what you want is something like this:

def play_game(board, player1,player2):
    while True:
        player1.play_turn(board)
        if board.is_game_over() == None:
            player2.play_turn(board)
            if board.is_game_over() == None:
                pass
            else:
                print "Player 2 wins"
                break
        else:
            print "Player 1 wins"
            break

class Human(Player):
    def play_turn(self,board):
        super(Human, self).play_turn(board)
        x = raw_input("Player %s please pick a column: " % self.playernum)
        board.play_turn(self.playernum, int(x))
        board.print_board()

That should fix your immediate problems—but I'm guessing you have very similar problems in all of your other functions.

Meanwhile, there are some odd things about your design.

For example, why are you checking if b.is_game_over() == None:? A function called is_game_over should probably be returning something truthy if the game is over, and something falsey if it's not. While None is a reasonable "something falsey", False is even more reasonable—and, either way, it's hard to imagine why you'd want to check for it explicitly, instead of just checking that it's falsey. (Plus, even if you do need to check specifically for None for some reason, there's almost never a good reason to use == None instead of is None.)

Second, why do you need to create board, player1, and player2 outside of the play_game function? It doesn't seem like they'd be all that useful outside this function.

Finally, even with just two players, I think your code would be simpler if you refactored the common parts:

def play_game(board, player1,player2):
    while True:
        for player in player1, player2:
            player.play_turn(board)
            if board.is_game_over():
                print "Player {} wins".format(player.playernum)
                break

One last thing: Your logic doesn't seem to account for the possibility that the game might be over because the current player has no move to make. I'm not sure if that's a tie or a loss in Connect 4, but I'm pretty sure it's not a win, is it?

Upvotes: 1

Related Questions