0

i have a problem with creating a dict in python. In my mainloop i call function 1 which should creat an empty dict. function 1 calls function 2. function 2 calls itself (loop through a game tree) but i can not use the dict i created in f1. and it is not possible to pass it as agrument. i would like to have the dict globaly accessible

def f1(): # function 1
    #test_dict = {} # this needs to be global scope

    #test_dict["key"] = "value"
    test_dict["key2"] = "value2"
    print (test_dict)
    f2()

def f2(): # function 2
    # here starts a loop that calls f2 again and again -> global dict is needed
    # dict needs to be created 

    print (test_dict)


test_dict = {} # only works without errors when i create it before calling f1
test_dict["key"] = "value"
f1()

Here is my "real" Code :) The >>MinMaxComputerMove<< need to edit the dict. but at the end of a nood i cant pass it because the for loop just goes on.

# [] [] []
# [] [] []
# [] [] []

#Input Layer:
#9 Punkte mit -1 (geg.) 0 (leer) 1 (eig.)

from time import sleep
from random import randint
from random import choice
from IPython.display import clear_output

def clearBoard():
    board = [0] * 10
    return (board)

def drawBoard(board, PlayerSymbol, ComputerSymbol, turn):
    turn += 1
    #clear_output()
    Symbolboard = []
    for index, value in enumerate(board):
        if value == 1:
            Symbolboard.append(PlayerSymbol)
        elif value == -1:
            Symbolboard.append(ComputerSymbol)
        else:
            Symbolboard.append(" ")
    print ("Turn: " +  str(turn))
    print ("")        
    print (str(Symbolboard[7]) + " - " + str(Symbolboard[8]) + " - " + str(Symbolboard[9]))
    print ("| \ | / |")
    print (str(Symbolboard[4]) + " - " + str(Symbolboard[5]) + " - " + str(Symbolboard[6]))
    print ("| / | \ |")
    print (str(Symbolboard[1]) + " - " + str(Symbolboard[2]) + " - " + str(Symbolboard[3]))
    return (validMoves(board), turn)

def validMoves(board):
    #return list with valid indices
    validMoveList = []
    for index, value in enumerate(board):
        if index > 0 and value == 0:
            validMoveList.append(index)
    return (validMoveList)    

def Symbol():
    #X always goes first
    if randint(0, 1) == 0:
        print ("X: YOU")
        print ("O: COMPUTER")
        return ("X"), ("O")
    else:
        print ("X: COMPUTER")
        print ("O: YOU")
        return ("O"), ("X")

def PlayerMove(validMoveList, PlayerSymbol):
    PlayerInput = input("Welches Feld? (1-9):")  
    if int(PlayerInput) in validMoveList:
        return (PlayerInput, PlayerSymbol)
    else:
        print("Falsche Eingabe." + PlayerInput + " kein möglicher Zug")

def ComputerMove(validMoveList, board, PlayerSymbol, ComputerSymbol, AI):
    print("ComputerMove")
    if AI == 1:
        return RandomComputerMove(validMoveList, ComputerSymbol)
    elif AI == 2:
        path_dict = {}
        return MinMaxComputerMove(validMoveList, board, PlayerSymbol, ComputerSymbol, depth = 1, firstrun = 1)
    # more AIs
    # ...

def ComputerThinking():
    print("Computer is thinking", end = "")
    sleep(0.5)
    print(".", end = "")
    sleep(0.5)
    print(".", end = "")
    sleep(0.5)
    print(".")
    sleep(1)
    return

def RandomComputerMove(validMoveList, ComputerSymbol):
    ComputerChoice = choice(validMoveList)
    ComputerThinking()
    print("ComputerChoice: " + str(ComputerChoice))
    sleep(1.5)
    print("RandomComputerMove Output: " + str((ComputerChoice, ComputerSymbol)))
    return (ComputerChoice, ComputerSymbol)

def MinMaxComputerMove(validMoveList, board, PlayerSymbol, ComputerSymbol, depth, firstrun = 0, start_path = -1):

    initial_validMoveList = validMoveList.copy()
    initial_board = board.copy()
    turns_left = len(initial_validMoveList)

    #debug
    print("firstrun: " + str(firstrun))
    print("depth: " + str(depth))

    if firstrun == 1: #first run of function
        path_dict = {}
        for path, field in enumerate(initial_validMoveList):
            path_dict[path] = {}
            for extent in range(3):
                path_dict[path][extent+1] = 5

    #debug
    print("---MinMaxComputerMove---")
    print("Start MinMaxComputerMove with depth: " + str(depth))
    print("validMoveList: " + str(validMoveList) + str(id(validMoveList)))
    print("board: " + str(board) + str(id(board)))
    print("ComputerSymbol: " + str(ComputerSymbol))
    print("start_path: " + str(start_path))

    for path, field in enumerate(initial_validMoveList): #(2, 6, 8):

        if firstrun == 1:
            start_path = path
            print("start_path: " + str(start_path))

        # for every path in tree diagram create a key in dict with empty list
        # goal: dict("path": [field, depth_1_(max)value, depth_2_(min)value, depth_3_(max)value])

        #debug
        print("depth: " + str(depth))

        if depth % 2 == 1: # Computer:
            ChoosenIndex = (str(field), ComputerSymbol)
        else: # Player
            ChoosenIndex = (str(field), PlayerSymbol)

        new_board = updateBoard(initial_board.copy(), ChoosenIndex, PlayerSymbol) # copy() or initial_board would change
        new_validMoveList = validMoves(new_board)

        #debug
        print("---For Loop---")
        print("ChoosenIndex: " + str(ChoosenIndex) + str(id(ChoosenIndex)))
        print("new_validMoveList: " + str(new_validMoveList) + str(id(new_validMoveList)))
        print("new_board: " + str(new_board) + str(id(new_board)))
        print("path_dict: " + str(path_dict))
        print("depth: " + str(depth))

        if checkWinner(new_board) == 0 and depth != 3 and turns_left >= 1: # no winner yet and game not over
            print ("no winner yet and game not over")
            # go deeper
            path_dict[start_path][depth] = 0
            MinMaxComputerMove(new_validMoveList, new_board, PlayerSymbol, ComputerSymbol, depth + 1, 0, start_path)

        elif checkWinner(new_board) == 0 and depth == 3 and turns_left >= 1: # no winner yet and game not over and minmax ends (depth = 3)
            print ("checkWinner(new_board) == 0 and depth == 3 and turns_left >= 1")
            path_dict[start_path][depth] = 0

        elif checkWinner(new_board) == -1: # computer wins
            print ("elif checkWinner(new_board) == -1")

            if depth % 2 == 1: # Computer -> MIN:
                path_dict[start_path][depth] <= -1
            else: # Player -> MAX
                if path_dict[start_path][depth] > -1:
                    path_dict[start_path][depth] = -1

        elif checkWinner(new_board) == 1: # player wins
            print ("elif checkWinner(new_board) == 1")
            path_dict[start_path][depth] = 1

        elif depth >= 3 or turns_left < 1: # reached depth 3 or no more turns
            print ("elif depth >= 3 or turns_left < 1:")

        else:
            print ("else")

        print("--- END FOR PATH ---")
    print("--- END FOR LOOP ---")

    print(path_dict)
    # return choise

    return (2, ComputerSymbol)


def updateBoard(board, ChoosenIndex, PlayerSymbol): #[0, 1, -1, 0, ...],[5, "X"], "X"
    if PlayerSymbol == ChoosenIndex[1]:
        board[int(ChoosenIndex[0])] = 1
        return (board)
    else:
        board[int(ChoosenIndex[0])] = -1
        return (board)

def checkWinner(board):
    if (board[7] == board[8] == board[9]) and 0 != board[7]: # top row
        return board[7]
    elif (board[4] == board[5] == board[6]) and 0 != board[4]: # mid row
        return board[4]
    elif (board[1] == board[2] == board[3]) and 0 != board[1]: # bot row
        return board[1]
    elif (board[7] == board[4] == board[1]) and 0 != board[7]: # left column
        return board[7]
    elif (board[8] == board[5] == board[2]) and 0 != board[8]: # mid row
        return board[8]
    elif (board[9] == board[6] == board[3]) and 0 != board[9]: # right row
        return board[9]
    elif (board[7] == board[5] == board[3]) and 0 != board[7]: # diagonal \
        return board[7]
    elif(board[1] == board[5] == board[9]) and 0 != board[1]: # diagonal /
        return board[1]
    else: 
        return 0

def GameLoop(AI, turn = 0, winner = 0):

    #choose AI difficulty
    #...
    #...    

    #set first player (X)
    PlayerSymbol, ComputerSymbol = Symbol()
    sleep(3)

    #init board with list 10 * 0
    board = clearBoard()

    #debug
    board = [0, 1, 0, 1, -1, -1, 0, 1, 0, -1]
    PlayerSymbol, ComputerSymbol = ("O", "X") # computer first

    #draw current board
    validMoveList, turn = drawBoard(board, PlayerSymbol, ComputerSymbol, turn)

    while winner == 0 and turn <=9:
        sleep(1.5)
        if turn % 2 == 1: # "X" player move
            if PlayerSymbol == "X":
                #player move
                ChoosenIndex = PlayerMove(validMoveList, PlayerSymbol)

                #update current board
                board = updateBoard(board, ChoosenIndex, PlayerSymbol)

                #draw current board
                validMoveList, turn = drawBoard(board, PlayerSymbol, ComputerSymbol, turn)

                #check for winner
                winner = checkWinner(board)
            else:
                #computer move
                ChoosenIndex = ComputerMove(validMoveList, board, PlayerSymbol, ComputerSymbol, AI)

                #update current board
                board = updateBoard(board,ChoosenIndex, PlayerSymbol)

                #draw current board
                validMoveList, turn = drawBoard(board, PlayerSymbol, ComputerSymbol, turn)

                #check for winner
                winner = checkWinner(board)
        else: # "O" player move
            if PlayerSymbol == "O":
                #player move
                ChoosenIndex = PlayerMove(validMoveList, PlayerSymbol)

                #update current board
                board = updateBoard(board,ChoosenIndex, PlayerSymbol)

                #draw current board
                validMoveList, turn = drawBoard(board, PlayerSymbol, ComputerSymbol, turn)

                #check for winner
                winner = checkWinner(board)            

            else:
                #computer move
                ChoosenIndex = ComputerMove(validMoveList, board, PlayerSymbol, ComputerSymbol, AI)

                #update current board            
                board = updateBoard(board,ChoosenIndex, PlayerSymbol)

                #draw current board
                validMoveList, turn = drawBoard(board, PlayerSymbol, ComputerSymbol, turn)

                #check for winner
                winner = checkWinner(board)
    else:
        if winner == 1:
            print ("YOU WON!")
        elif winner == -1:
            print ("COMPUTER WON!")
        else:
            print ("DRAW!")


GameLoop(AI = 2)
David
  • 3
  • 2
  • Why can't you pass it as an argument? Globals can cause you all sorts of problems, so you might be better off avoiding this and finding a different solution. – doctorlove Jun 07 '19 at 11:50
  • 1
    You have to make use of function arguments and return values. – Klaus D. Jun 07 '19 at 11:50
  • Cool. Why does this mean you can't pass arguments to functions? – doctorlove Jun 07 '19 at 11:57
  • @doctorlove I edited the question with my "real" Code. i think that this is more easy to explain – David Jun 07 '19 at 12:03
  • That's a lot of code! Which is `f1` and which is `f2` in the real code? Is one `MinMaxComputerMove` and the other `ComputerMove`? You could pass it in as a parameter. – doctorlove Jun 07 '19 at 12:20
  • exactly :) ComputerMove calls MinMaxComputerMove (when AI = 2) but here the FIRST loop starts checking each path. it goes through the first path ... the dict changes and then the second path of the FIRST loop. But here the dict is not changed right? because all the changes were made in the first branch. and i cant pass this into an existing loop that is going on all the time (the FIRST loop) or do i miss something? – David Jun 07 '19 at 12:27

2 Answers2

0

The "return value" answer is:

def f1(test_dict): # function 1
    #test_dict = {} # this needs to be global scope

    #test_dict["key"] = "value"
    test_dict["key2"] = "value2"
    print ('In f1 {}'.format(test_dict))
    f2(test_dict)

    return test_dict

def f2(test_dict): # function 2
    # here starts a loop that calls f2 again and again -> global dict is needed
    # dict needs to be created 

    print ('In f2 {}'.format(test_dict))

    return test_dict

test_dict = {} # only works without errors when i create it before calling f1
test_dict["key"] = "value"
test_dict = f1(test_dict)

which gives output of:

In f1 {'key2': 'value2', 'key': 'value'}
In f2 {'key2': 'value2', 'key': 'value'}

But at some level, you probably want to put some of this into a class and then have test_dict as a variable within the class. That allows f1 and f2 (assuming they are class methods) to access the class variable without passing it as a parameter to the two methods.

class Example:

    def __init__(self):
        self._test_dict = {}
        self._test_dict["key"] = "value"


    def f1(self): # function 1
        self._test_dict["key2"] = "value2"
        print ('In f1 {}'.format(self._test_dict))
        self.f2()

    def f2(self): # function 2
        print ('In f2 {}'.format(self._test_dict))

example = Example()
example.f1()
brechmos
  • 1,278
  • 1
  • 11
  • 22
0

Below is a very simply version of what your script is attempting. You need to consider what your function parameters should be (what is passed to the function), as well as what your function should be providing at the end of its execution (given to you with the return statement). This way you can manipulate objects without having to keep everything in global scope, and you can avoid having to initialize every conceivable variable at the start of the routine.

  • Python Functions
  • Return Statement

    def f1():
        f1_dict = {}
        f1_dict = f2(f1_dict)
    
        return f1_dict
    
    def f2(dict_arg):
        f2_dict = {}
        for i in range(0,5):
            f2_dict[str(i)] = i**i
    
        return f2_dict
    
    dictionary = f1()
    print(dictionary)
    
Torc
  • 1,148
  • 6
  • 20
  • 43