Глобальные переменные против параметров - консольная игра Python - PullRequest
0 голосов
/ 30 сентября 2019

Я только что просмотрел код, который написал некоторое время назад, и заметил нечто странное с глобальными переменными. Например, в update_board я передаю board в качестве параметра и обновляю его внутри функции, но не возвращаю обновленную доску, но она все еще обновляется. Похоже, что я в основном использую глобальное значение для board.

Чтобы быть последовательным, следует ли мне избегать передачи параметра board и использовать вместо него global board? Я знаю, что глобалы не одобряются, но, возможно, по крайней мере, лучше быть откровенными о них. Или было бы лучше заменить экземпляры update_board(board, row, col) на board = update_board(board, row, col) и вернуть взамен board из update_board?

Или я, возможно, случайно наткнулся на действительный подход при наличии кода?

"""
Chomp - a strategy game
"""

import random
import time

NUM_ROWS = 5
NUM_COLS = 6

FILLED_SPOT = "#"
POISON_SPOT = "P"
EMPTY_SPOT = " "


def print_title():
    print(r"""
 ______     __  __     ______     __    __     ______  
/\  ___\   /\ \_\ \   /\  __ \   /\ "-./  \   /\  == \ 
\ \ \____  \ \  __ \  \ \ \/\ \  \ \ \-./\ \  \ \  _-/ 
 \ \_____\  \ \_\ \_\  \ \_____\  \ \_\ \ \_\  \ \_\   
  \/_____/   \/_/\/_/   \/_____/   \/_/  \/_/   \/_/   
""")


def print_instructions():
    print("Welcome to Chomp. Choose a square. All squares to the right")
    print("and downwards will be eaten. The computer will do the same.")
    print("The one to eat the poison square loses. Good luck!")
    print()


def who_goes_first():
    return random.choice(("computer", "human"))


def play_again():
    print("Would you like to play again (yes or no)?")
    return input().lower().startswith("y")


def print_matrix(matrix):
    for row in matrix:
        for elem in row:
            print(elem, end=EMPTY_SPOT)
        print()


def validate_user_input(player_choice, board):
    try:
        row, col = player_choice.split()
    except ValueError:
        print("Bad input: The input should be exactly two numbers separated by a space.")
        return False
    try:
        row = int(row)
        col = int(col)
    except ValueError:
        print("Input must be two numbers, however non-digit characters were received.")
        return False

    if row < 0 or row > NUM_ROWS - 1:
        print(f"The first number must be between 0 and {NUM_ROWS - 1} but {row} was passed.")
        return False
    if col < 0 or col > NUM_COLS - 1:
        print(f"The second number must be between 0 and {NUM_COLS - 1} but {col} was passed.")
        return False
    if board[row][col] == EMPTY_SPOT:
        print("That square has already been eaten!")
        return False
    return True


def update_board(board, row, col):
    for i in range(row, len(board)):
        for j in range(col, len(board[i])):
            board[i][j] = EMPTY_SPOT


def get_human_move(board):
    valid_input = False
    while not valid_input:
        player_choice = input("Enter the row and column number (counting from 0) of your choice,\
        \nseparated by a space: ")
        valid_input = validate_user_input(player_choice, board)
    row, col = player_choice.split()
    return int(row), int(col)


def get_computer_move(board):
    valid_move = False
    while not valid_move:
        row = random.randint(0, NUM_ROWS - 1)
        col = random.randint(0, NUM_COLS - 1)
        if board[row][col] == EMPTY_SPOT:
            continue
        else:
            valid_move = True
    return row, col


def main():
    game_over = False
    while not game_over:
        board = []
        for i in range(NUM_ROWS):
            row = []
            for j in range(NUM_COLS):
                row.append(FILLED_SPOT)
            board.append(row)

        board[0][0] = POISON_SPOT
        game_is_playing = True
        turn = who_goes_first()

        print_title()
        print_instructions()
        print_matrix(board)
        print()

        while game_is_playing:
            if turn == "human":
                # Human turn
                print("Human turn.")
                row, col = get_human_move(board)
                if board[row][col] == POISON_SPOT:
                    print()
                    print("Too bad, the computer wins!")
                    game_is_playing = False
                else:
                    update_board(board, row, col)
                    print()
                    print_matrix(board)
                    print()
                    turn = "computer"
                    time.sleep(1)
            else:
                # Computer turn
                row, col = get_computer_move(board)
                print(f"Computer turn. The computer chooses ({row}, {col})")
                print()
                if board[row][col] == POISON_SPOT:
                    print()
                    print("Yay, you win!")
                    game_is_playing = False
                else:
                    update_board(board, row, col)
                    print_matrix(board)
                    print()
                    turn = "human"

        if play_again():
            main()
        else:
            print("Goodbye!")
            game_over = True

main()

1 Ответ

0 голосов
/ 30 сентября 2019

У вас нет глобальной переменной. Вместо этого у вас есть локальная переменная, которую вы передаете своей функции.

Когда вы создаете переменную, вы просто создаете псевдоним, указывающий на местоположение объекта в памяти. В приведенном ниже коде мы создаем список, который является объектом и имеет строковый объект внутри него. Затем мы создаем имя mylist и указываем на место в памяти объекта списка.

mylist = [1]

Когда вы затем передаете mylist в функцию, происходит то, что функция получает копию ячейки памяти, на которую указывает mylist, и функция устанавливает свою локальную переменную, чтобы указывать на эту ячейку памяти.

Таким образом, когда вы выполняете действие, которое изменяет объект в этой ячейке памяти, это обновление будет также видно по имени переменной вне функции, поскольку обе они указывают на одну и ту же ячейку памяти.

Если, однако, вы должны переназначить что-либо на эту переменную в функции, например, создать новый список, то это не будет отражаться в переменной вне функции. Поскольку то, что на самом деле происходит, - это создание нового объекта и на него будет указана локальная переменная области видимостиэто не изменило бы адрес памяти переменной вне функции, которая все еще указала бы на исходное местоположение.

def first():
    mylist = [1]
    print("mylist:", mylist)
    print("mylist id:", id(mylist))
    second(mylist)
    third(mylist)
    print("mylist:", mylist)
    print("mylist id:", id(mylist))

def second(second_list):
    #here the local function variable second_list points to the same memory location as mylist
    print("second id:", id(second_list))
    #Here we change the values in this memory location. So second list is still pointing to and change the data that my list points to
    #this is why mylist can see the change even though its not a global variable
    second_list.append(2)
    print("Second_list:", second_list)
    print("second id:", id(second_list))

def third(third_list):
    #here the local function variable third_list points to the same mermoy location as mylist
    print("third list:", third_list)
    print("third id:", id(third_list))
    #here we create a new object which will have a new memory lcaotion then we point the local variable third_list at it.
    #now third_list points to new memory location and not the same memory location as mylist.
    third_list=[3]
    print("third list:", third_list)
    print("third id:", id(third_list))

first()

ниже - вывод, где вы можете видеть идентификатор памяти каждого из объектов, которые вы увидитекак они указывают на один и тот же объект, а затем в третьей функции его переназначают на новый объект в памяти.

mylist: [1]
mylist id: 2636457271880
second id: 2636457271880
Second_list: [1, 2]
second id: 2636457271880
third list: [1, 2]
third id: 2636457271880
third list: [3]
third id: 2636457271944
mylist: [1, 2]
mylist id: 2636457271880
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...