Hello.

This time it might be a bit more complicated.

def start_game():
        global no_winner
        no_winner = True
        rows_cols()
        global board
        board = make_board()
        print_board()
        player_select()

def rows_cols():
        global rows
        global columns
        rows = int(raw_input('Height: '))
        columns = int(raw_input('Width: '))
        if rows < 4:
                rows = 4
        if columns < 4:
                columns = 4

def make_board():
        fielda = []
        fieldb = []
        for i in range(columns):
                fieldb.append('.')
        for i in range(rows):
                fielda.append(fieldb)
        return fielda

def print_board():
        global row
        global dot
        for row in board:
                for dot in row:
                        print dot,
                print
        for i in range(columns):
                print i,
        print

def player_select():
        select = int(raw_input('Human enemy(1) or Computer enemy(2)?: '))
        if select == 1:
                select_1()
        elif select == 2:
                select_2()
        else:
                player_select()

def select_1():
        print 'Player 1 = X'
        print 'Player 2 = O'
        while no_winner == True:
                turn_player1()
                turn_player2()

def select_2():
        print 'Player  = X'
        print 'Computer = O'
        while no_winner == True:
                turn_player1()
                turn_comp()

def turn_player1():
        print 'Turn Player 1'
        playchip = int(raw_input('Throw a coin in column: '))
        board[0][playchip] = 'X'
        print_board()

def turn_player2():
        print 'Turn Player 2'
        playchip = int(raw_input('Throw a coin in column: '))
        board[0][playchip] = 'O'
        print_board()

def turn_comp():
        import random
        print 'Turn Computer'
        playchip = random.randint(0, columns - 1)
        board[0][playchip] = 'O'
        print_board()

def dot_blank():
        for i in range(columns):
                for i in range(rows):
                        if board[0][playchip] == '.':
                                return True
                return False
start_game()

. . . .
. . . .
. . . .
. . . .
0 1 2 3

When I insert a Coin at Position 0 the whole column is getting filled with the coin instead of a single 'dot' in the column.
It looks like this:

X . . .
X . . .
X . . .
X . . .
0 1 2 3

Any ideas to fix this?

Thanks in advance

Recommended Answers

All 15 Replies

Dont use global variables.
Any name (variable) defined inside a function is local to that function,and should always stay that way.
If you need access to a function's local variables outside that function use argument and return variables out off function.

No are pollutioning the global namespace and you get problem like you have now
And finding problem it`s must hardere now that you use global variabls.

I really think you should redesign your code without global variabels(never ever use global variables is a god rule)

And import <module> is always first never inside a function.
Use 4 space for indent(never 2 or 8)

I really think you should redesign your code without global variabels(never ever use global variables is a god rule)

No, please don't tell me that :-(.
Isn't there any other solution? Just this time...

Do you have something against functions that take arguments? You have a lot of functions that could be many into one or two functions with an argument or two. Even if you don't use OOP, getting rid of global variables and putting some functions with arguments into place can't hurt you too much.

Anyway you should test if there's something in the column from the bottom up. Use something like:

rowPos = LAST_ROW
while rowPos <= 0:
        if theBoard[rowPos][theColumn] != '.':
                theBoard[rowPos][theColumn] = 'X' # or O
                return True
        rowPos -= 1
return False

This code will return True if it's able to put an X or O in the column, and False if the column is full.

There is no point in just get it to work,what to learn by that?
That bad design is ok.

here you make board global.
global board

This wont draw 1 X as you want,you known why?
board[0][playchip] = 'X'

So board is global then the for loop for board get run every time.
And make many X and O.

def dot_blank():
        for i in range(columns):
            for i in range(rows):
                if board[0][playchip] == '.':
                    return True
                return False

Do you have something against functions that take arguments?

No, I don't have anything against them. I'm just not familiar with them and I don't know about their advantages.

There is no point in just get it to work,what to learn by that?

You're certainly right but to be honest I got to get this finished until tuesday evening and that's why I just want to make this work.
I'll try to be more accurate in style in my next project ;)

And ignore the dot_blank function. It was just a prototype for checking if a column is free - it did not work.

How about this:

rows = int(raw_input('Hoehe des Spielfelds (Zeilen) (mind. 4): '))
columns = int(raw_input('Breite des Spielfelds (Spalten) (mind. 4): '))

board = []

def make_board(rows, columns):
        fielda = []
        fieldb = []
        for i in range(columns):
                fieldb.append('.')
        for i in range(rows):
                fielda.append(fieldb)
        return fielda

def print_board():
        for row in board:
                for dot in row:
                        print dot,
                print
        for i in range(columns):
                print i,
        print

board = make_board(rows, columns)
print_board()
board[0][1] = 'x'
print_board()

Prints out the following for a "clean" board:

. . . .
. . . .
. . . .
. . . .
0 1 2 3

Looks good!

And when the 'x' is put in:

. x . .
. x . .
. x . .
. x . .
0 1 2 3

Doesn't look too good.

I want it to look more like this:

. . . .
. . . .
. . . .
. X . .
0 1 2 3

Why does it fill every spot instead of only one?

Thanks in advance and sorry for getting on your nerves that much ;)

Why does it fill every spot instead of only one?

Because every row is the same block of memory = fieldb

for i in range(columns):
    fieldb.append('.')
for i in range(rows):
    fielda.append(fieldb)
#
# These will all be the same because they all point to the same memory location
for row in fielda:
    print id(row)
#
# You want to use (I think, you'll have to print the id() to be sure)
fielda = []
for x in range(rows):
    fieldb = []  ## should be a new block of memory each time
    for y in range(columns):
        fieldb.append(".")
    fielda.append(fieldb)

And you should not use "i", "l", or "o" as single digit variable names because they can look like numbers
x = 1
x = l
x = I

Member Avatar for masterofpuppets

How about this:

rows = int(raw_input('Hoehe des Spielfelds (Zeilen) (mind. 4): '))
columns = int(raw_input('Breite des Spielfelds (Spalten) (mind. 4): '))

board = []

def make_board(rows, columns):
        fielda = []
        fieldb = []
        for i in range(columns):
                fieldb.append('.')
        for i in range(rows):
                fielda.append(fieldb)
        return fielda

def print_board():
        for row in board:
                for dot in row:
                        print dot,
                print
        for i in range(columns):
                print i,
        print

board = make_board(rows, columns)
print_board()
board[0][1] = 'x'
print_board()

Prints out the following for a "clean" board:


Looks good!

And when the 'x' is put in:


Doesn't look too good.

I want it to look more like this:


Why does it fill every spot instead of only one?

Thanks in advance and sorry for getting on your nerves that much ;)

hi,
the problem is that all rows are pointing to the same memory location fieldb so if you change one row - you change them all. I suggest using deepcopy, like this:

from copy import deepcopy

rows = int(raw_input('Hoehe des Spielfelds (Zeilen) (mind. 4): '))
columns = int(raw_input('Breite des Spielfelds (Spalten) (mind. 4): '))
 
board = []
 
def make_board(rows, columns):
    fielda = []
    fieldb = []
    for i in range(columns):
        fieldb.append('.')
    for i in range(rows):
        fielda.append( deepcopy( fieldb ) )
    return fielda
 
def print_board():
    for row in board:
        for dot in row:
            print dot,
        print
    for i in range(columns):
        print i,
    print
 
board = make_board(rows, columns)
print_board()
board[ 3 ][1] = 'x'
print_board()

>>> 
Hoehe des Spielfelds (Zeilen) (mind. 4): 4
Breite des Spielfelds (Spalten) (mind. 4): 4
. . . .
. . . .
. . . .
. . . .
0 1 2 3

. . . .
. . . .
. . . .
. x . .
0 1 2 3
>>>

hope this helps :) Note that the first row here is board[ 3 ]

Thanks masterofpuppets, I did not know about the copy module.

Got another question:

. . . . 0
. . . . 1
. . . . 2
. . . . 3
0 1 2 3

If Player 1 puts in a chip into column 0 I want the chip to take position in row 3:

. . . . 0
. . . . 1
. . . . 2
X . . . 3
0 1 2 3

I tried it like this

def turn_player1():
        print 'Turn Player 1!'
        columnchip = int(raw_input('Which column?: '))
        rowchip = -1
        while True:
                if board[rowchip][columnchip] == '.' and board[rowchip][columnchip] != 'X' and board[rowchip][columnchip] != 'O':
                        rowchip = rowchip + 1
                else:
                        break # or return False ??
        board[rowchip][columnchip] = 'X'
        print_board()

Unfortunately Python answers 'IndexError: list index out of range'.
I'm about to get desperate. :-(

Member Avatar for masterofpuppets

hi again :)
here's a slightly modified version of your code.

board = [ [ ".", ".", ".", "." ],
          [ ".", ".", ".", "." ],
          [ ".", ".", ".", "." ],
          [ ".", ".", ".", "." ] ]

def turn_player1():
    print 'Turn Player 1!'
    columnchip = int( raw_input( 'Which column?: ' ) )
    rowchip = -1
    maxHeight = 4 # 4x4 field
    placed = False
    # The loop checks if the absolute value of rowchip, which in negative is
    # not equal to the height + 1, that allows to place an element at the top row
    while abs( rowchip ) != maxHeight + 1:
        if board[ rowchip ][ columnchip ] == '.': #if a free space if found place element and break
            board[ rowchip ][ columnchip ] = 'X'
            placed = True
            break
        else:
           rowchip = rowchip - 1 #else go one row up
    if not placed:
        print "No more rows available!\n"
    else:
        for i in board:
            print i

for e in range( 10 ):
    turn_player1()

instead of adding to rowchip, subtract 1 to get, e.g. -2 the first time. board[ -2 ] gives the second last row of the board. You have to keep checking the rows intill you find a free "." space, i.e. keep going to maxHeight + 1, allowing you to check the last row as well, which in this case is board[ 0 ]. Hope this helps you :)
I'll try to explain it further if you need anything :)

Member Avatar for masterofpuppets

P.S here's a sample of my output running the code:

>>> 
Turn Player 1!
Which column?: 0
['.', '.', '.', '.']
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', '.', '.']
Turn Player 1!
Which column?: 0
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', '.', '.']
['X', '.', '.', '.']
Turn Player 1!
Which column?: 1
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', '.', '.']
['X', 'X', '.', '.']
Turn Player 1!
Which column?: 2
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', '.', '.']
['X', 'X', 'X', '.']
Turn Player 1!
Which column?: 2
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', 'X', '.']
['X', 'X', 'X', '.']
Turn Player 1!
Which column?: 3
['.', '.', '.', '.']
['.', '.', '.', '.']
['X', '.', 'X', '.']
['X', 'X', 'X', 'X']
....
....

hi, thanks master, I used a bit of your code :)

Now I'm trying to avoid Exceptions / Errors

def turn_player1():
        print 'Turn Player 1'
        try:
                columnchip = int(raw_input('Column: '))
        except:
                print 'Error! Please type a number between 0 and', columns - 1
                turn_player1()
        if board[0][columnchip] != '.':
                print 'Column is full!'
                turn_player1()
        else:
                rowchip = -1
                while rowchip != columns +1:
                        if board[rowchip][columnchip] == '.':
                                board[rowchip][columnchip] = 'X'
                                break
                        else:
                                rowchip = rowchip - 1

If the user types in a number directly everything works.

If the user types in something else but a number python answers with the phrase in the except part but if the user types in a number afterwards python answers: 'local variable 'columnchip' referenced before assignment' even though columnchip is defined as the input of the user.

If I direct the except-block to other functions everything works but If I direct the block to the turn_player1() function there is this abnormal behaviour.

Does anyone know why?

Member Avatar for masterofpuppets

hi,
why don't you try to put your computation in the try block as well like this:

def turn_player1():
    print 'Turn Player 1'
    try:
        columnchip = input( 'Column: ' )
        if board[0][columnchip] == 'X' or board[0][columnchip] == 'O':
            print 'Column is full!'
            turn_player1()
        else:
            rowchip = -1
            while rowchip != columns +1:
                if board[rowchip][columnchip] == '.':
                    board[rowchip][columnchip] = 'X'
                    break
                else:
                    rowchip = rowchip - 1
        
    except:
        print 'Error! Please type a number between 0 and', columns - 1
        turn_player1()
    
turn_player1()

I haven't actually tested it but I think it should work...oh yes you can use the input function instead of raw_input(). input expects an int so if the input is not an int an exception is thrown :)
hope this helps :)

hi masterofpuppets,

you're my hero :)

it's almost done :D

Hi guys,

the last thing I need is a function that checks whether or not the game ended in a draw.

my try:

def check_draw():
        if board[0][0:columns] != '.':
                print 'Draw :-|'
                no_winner = False

I guess the best way is to check the first row of the grid and if every spot is already taken the function should print 'Draw', except when someone won with the last free spot (the second part I can do myself i hope).

Thanks in advance.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.