Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Python variable problem 1

Status
Not open for further replies.

JoeUser11

Programmer
Dec 11, 2004
5
US
I'm new to python. I'm making a simple text-based chess program, and everything works fine except for one function. Whenever I copy array 'p' into array 'lb', if I modify 'p', 'lb' changes with it. I'm not really familiar with python variable properties, and it just mistifies me why array 'lb' would follow 'p'.
Code:
#white's move; sets the last board (lb) to position before it changes
#then it modifies the board position (p) to the moves
#only this instance requires a 2nd user input (hence wMove2=raw_input...)
            elif wMove1 != "o-o" and wMove1 != "o-o-o":
                    lb = p
                    wMove2 = raw_input("Move to where: ")
                    p[wMove2] = p[wMove1]
                    p[wMove1] = "  "
#board(x) is just a method that changes an array into a
#chessboard and prints it onto the screen
            board(p)

That's the part of the program that isn't working.
board(lb) and board(p) are the same even though array "p" was modified after it was copied onto "lg".

The whole code is here, sorry it looks messy, I have some long lines of code.
Code:
def newGame():
    p = {'a1':"wR",'b1':"wN",'c1':"wB",'d1':"wQ",'e1':"wK",'f1':"wB",'g1':"wN",'h1':"wR",
        'a2':"wP",'b2':"wP",'c2':"wP",'d2':"wP",'e2':"wP",'f2':"wP",'g2':"wP",'h2':"wP",
        'a3':"  ",'b3':"  ",'c3':"  ",'d3':"  ",'e3':"  ",'f3':"  ",'g3':"  ",'h3':"  ",
        'a4':"  ",'b4':"  ",'c4':"  ",'d4':"  ",'e4':"  ",'f4':"  ",'g4':"  ",'h4':"  ",
        'a5':"  ",'b5':"  ",'c5':"  ",'d5':"  ",'e5':"  ",'f5':"  ",'g5':"  ",'h5':"  ",
        'a6':"  ",'b6':"  ",'c6':"  ",'d6':"  ",'e6':"  ",'f6':"  ",'g6':"  ",'h6':"  ",
        'a7':"bP",'b7':"bP",'c7':"bP",'d7':"bP",'e7':"bP",'f7':"bP",'g7':"bP",'h7':"bP",
        'a8':"bR",'b8':"bN",'c8':"bB",'d8':"bQ",'e8':"bK",'f8':"bB",'g8':"bN",'h8':"bR"}
    board(p)
    play(p)

#prints the board to the screen
def board(p):
        horizLine = "    ----------------------------------------"
	print ""
	print horizLine,"        JoeUser's 2 Player Chess!"
	print "  8|",p['a8'],"|",p['b8'],"|",p['c8'],"|",p['d8'],"|",p['e8'],"|",p['f8'],"|",p['g8'],"|",p['h8'],"|"
	print horizLine,"        Use the grid notation"
	print "  7|",p['a7'],"|",p['b7'],"|",p['c7'],"|",p['d7'],"|",p['e7'],"|",p['f7'],"|",p['g7'],"|",p['h7'],"|","        to move pieces."
	print horizLine
	print "  6|",p['a6'],"|",p['b6'],"|",p['c6'],"|",p['d6'],"|",p['e6'],"|",p['f6'],"|",p['g6'],"|",p['h6'],"|"
	print horizLine
	print "  5|",p['a5'],"|",p['b5'],"|",p['c5'],"|",p['d5'],"|",p['e5'],"|",p['f5'],"|",p['g5'],"|",p['h5'],"|"
	print horizLine,"              Commands"
	print "  4|",p['a4'],"|",p['b4'],"|",p['c4'],"|",p['d4'],"|",p['e4'],"|",p['f4'],"|",p['g4'],"|",p['h4'],"|"
	print horizLine,"     'new'    -New Game"
	print "  3|",p['a3'],"|",p['b3'],"|",p['c3'],"|",p['d3'],"|",p['e3'],"|",p['f3'],"|",p['g3'],"|",p['h3'],"|","     'undo'   -Undo Previous Move"
	print horizLine
	print "  2|",p['a2'],"|",p['b2'],"|",p['c2'],"|",p['d2'],"|",p['e2'],"|",p['f2'],"|",p['g2'],"|",p['h2'],"|"
	print horizLine
	print "  1|",p['a1'],"|",p['b1'],"|",p['c1'],"|",p['d1'],"|",p['e1'],"|",p['f1'],"|",p['g1'],"|",p['h1'],"|"
	print horizLine
	print "      a    b    c    d    e    f    g    h "
	print ""
	print ""
	print ""
	print ""


#play
def play(p):
    while 1:
#white's move
            print "White's move..."
            wMove1 = raw_input("Move from: ")
#new game
            if wMove1 == "new":
                    newGame()
#undoes by changing the board position (p) to the last board postition (p)
            elif wMove1 == "undo":
                p = lb
#handles castling, also assigns last board (lb) before it changes
            elif wMove1 == "o-o" or wMove1 == "o-o-o":
                    lb = p
                    if wMove1 == "o-o":		
                            p['e1'],p['f1'],p['g1'],p['h1'] = "  ", "wR","wK","  "
                    if wMove1 == "o-o-o":
                            p['e1'],p['d1'],p['c1'],p['b1'],p['a1'] = "  ","wR","wK","  ","  "
#white's move; sets the last board (lb) to position before it changes
#then it modifies the board position (p) to the moves
#only this instance requires a 2nd user input (hence wMove2=raw_input...)
            elif wMove1 != "o-o" and wMove1 != "o-o-o":
                    lb = p
                    wMove2 = raw_input("       To: ")
                    p[wMove2] = p[wMove1]
                    p[wMove1] = "  "
            board(p)
            board(lb)

#black's move; repeat above code with black
            print "Black's move..."
            bMove1 = raw_input("Move from: ")
            if bMove1 == "new":
                    newGame()
            elif bMove1 == "undo":
                p = lb
            elif bMove1 != "o-o" and bMove1 !="o-o-o":
                    lb = p
                    bMove2 = raw_input("       To: ")
                    p[bMove2] = p[bMove1]
                    p[bMove1] = "  "
            elif bMove1 == "o-o" or bMove1 == "o-o-o":
                    lb = p
                    if bMove1 == "o-o":
                            p['e8'],p['f8'],p['g8'],p['h8'] = "  ", "bR","bK","  "
                    if bMove1 == "o-o-o":
                            p['e8'],p['d8'],p['c8'],p['b8'],p['a8'] = "  ","bR","bK","  ","  "
            board(p)
            board(lb)


#initializes board and play, starts game
newGame()
 
The following is from "An Easy Tutorial To Python," section "More On Lists," which comes with the ActivePython 2.3.2. documentation. I think this explains your problem.
The next feature of lists is copying them. If you try something simple like:

>>> a = [1,2,3]
>>> b = a
>>> print b
[1, 2, 3]
>>> b[1] = 10
>>> print b
[1, 10, 3]
>>> print a
[1, 10, 3]

This probably looks surprising since a modification to b resulted in a being changed as well. What happened is that the statement b = a makes b a reference to a. This means that b can be thought of as another name for a. Hence any modification to b changes a as well. However some assignments don't create two names for one list:
>>> a = [1,2,3]
>>> b = a*2
>>> print a
[1, 2, 3]
>>> print b
[1, 2, 3, 1, 2, 3]
>>> a[1] = 10
>>> print a
[1, 10, 3]
>>> print b
[1, 2, 3, 1, 2, 3]

In this case b is not a reference to a since the expression a*2 creates a new list. Then the statement b = a*2 gives b a reference to a*2 rather than a reference to a. All assignment operations create a reference. When you pass a list as a argument to a function you create a reference as well. Most of the time you don't have to worry about creating references rather than copies. However when you need to make modifications to one list without changing another name of the list you have to make sure that you have actually created a copy.

There are several ways to make a copy of a list. The simplest that works most of the time is the slice operator since it always makes a new list even if it is a slice of a whole list:

>>> a = [1,2,3]
>>> b = a[:]
>>> b[1] = 10
>>> print a
[1, 2, 3]
>>> print b
[1, 10, 3]

Taking the slice [:] creates a new copy of the list. However it only copies the outer list. Any sublist inside is still a references to the sublist in the original list. Therefore, when the list contains lists the inner lists have to be copied as well. You could do that manually but Python already contains a module to do it. You use the deepcopy function of the copy module:

>>> import copy
>>> a = [[1,2,3],[4,5,6]]
>>> b = a[:]
>>> c = copy.deepcopy(a)
>>> b[0][1] = 10
>>> c[1][1] = 12
>>> print a
[[1, 10, 3], [4, 5, 6]]
>>> print b
[[1, 10, 3], [4, 5, 6]]
>>> print c
[[1, 2, 3], [4, 12, 6]]

First of all notice that a is an array of arrays. Then notice that when b[0][1] = 10 is run both a and b are changed, but c is not. This happens because the inner arrays are still references when the slice operator is used. However with deepcopy c was fully copied.
So, should I worry about references every time I use a function or =? The good news is that you only have to worry about references when using dictionaries and lists. Numbers and strings create references when assigned but every operation on numbers and strings that modifies them creates a new copy so you can never modify them unexpectedly. You do have to think about references when you are modifying a list or a dictionary.

By now you are probably wondering why are references used at all? The basic reason is speed. It is much faster to make a reference to a thousand element list than to copy all the elements. The other reason is that it allows you to have a function to modify the inputed list or dictionary. Just remember about references if you ever have some weird problem with data being changed when it shouldn't be.
HTH


 
Thanks! That really helped me understand why it isn't working. One problem though, I don't know if things work diffrently with definition arrays, but I'm getting an error:
Code:
>>> a = {'a':1,'b':2,'c':3}
>>> b = a[:]
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in ?
    b = a[:]
TypeError: unhashable type
Is there some other operation to copy these types of arrays?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top