在我脑海中:调试和许多错误

时间:2014-03-30 00:30:52

标签: python

我正在尝试为连接4编写一个程序,但是在通过指示时遇到了很多麻烦。评论中的一切," #everything可以在这里发挥作用"有效,但后来爆炸,我甚至不知道从哪里开始修复它。

#connect 4

import random

#define global variables
X = "X"
O = "O"
EMPTY = "_"
TIE = "TIE"
NUM_ROWS = 6
NUM_COLS = 8

def display_instruct():
    """Display game instructions."""  
    print(
    """
    Welcome to the second greatest intellectual challenge of all time: Connect4.  
    This will be a showdown between your human brain and my silicon processor.  

    You will make your move known by entering a column number, 1 - 7.  Your move 
    (if that column isn't already filled) will move to the lowest available position.

    Prepare yourself, human.  May the Schwartz be with you! \n
    """
    )

def ask_yes_no(question):
    """Ask a yes or no question."""
    response = None
    while response not in ("y", "n"):
        response = input(question).lower()
    return response

def ask_number(question,low,high):
    """Ask for a number within range."""
    #using range in Python sense-i.e., to ask for
    #a number between 1 and 7, call ask_number with low=1, high=8
    low=1
    high=NUM_COLS
    response = None
    while response not in range (low,high):
        response=int(input(question))
    return response 

def pieces():
    """Determine if player or computer goes first."""
    go_first = ask_yes_no("Do you require the first move? (y/n): ")
    if go_first == "y":
        print("\nThen take the first move.  You will need it.")
        human = X
        computer = O
    else:
        print("\nYour bravery will be your undoing... I will go first.")
        computer = X
        human = O
    return computer, human

def new_board():
    board = []
    for x in range (NUM_COLS):
        board.append([" "]*NUM_ROWS)
    return board

def display_board(board):
    """Display game board on screen."""
    for r in range(NUM_ROWS):
        print_row(board,r)  
    print("\n")

def print_row(board, num):
    """Print specified row from current board"""
    this_row = board[num]
    print("\n\t| ", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num],"|")
    print("\t", "|---|---|---|---|---|---|---|")

# everything works up to here!

def legal_moves(board):
    """Create list of column numbers where a player can drop piece"""
    legal=True
    while not legal:
        col = input("What column would you like to move into (1-7)?")
        for row in range (6,0,1):
            if (1 <= row <= 6) and (1 <= col <= 7) and (board[row][col]==" "):
                board[row][col] = turn
                legal = True
            else:
                print("Sorry, that is not a legal move.")


def human_move(board,human):
    """Get human move"""
    try:
        legals = legal_moves(board)
        move = None
        while move not in legals:
            move = ask_number("Which column will you move to? (1-7):", 1, NUM_COLS)
            if move not in legals:
                print("\nThat column is already full, nerdling.  Choose another.\n")
        print("Human moving to column", move)
        return move #return the column number chosen by user
    except NameError:
        print ("Only numbers are allowed.")
    except IndexError:
        print ("You can only  select colums from 1-7.")

def get_move_row(turn,move):
    for m in (NUM_COLS):
        place_piece(turn,move)
    display_board()

def computer_move ():
    move= random.choice(legal)
    return move

def place_piece(turn,move):
    if this_row[m[move]]==" ":
        this_row.append[m[move]]=turn

def winner(board):
    # Check rows for winner
    for row in range(6): 
        for col in range(3): 
            if (board[row][col] == board[row][col + 1] == board[row][col + 2] == board[row][col + 3]) and (board[row][col] != " "):
                return [row][col]
    # Check columns for winner
    for col in range(6):
        for row in range(3): 
            if (board[row][col] == board[row + 1][col] == board[row + 2][col] ==board[row + 3][col]) and (board[row][col] != " "):
                return [row][col]
    # Check diagonal (top-left to bottom-right) for winner
    for row in range(3): 
        for col in range (4): 
            if (board[row][col] == board[row + 1][col + 1] == board[row + 2][col + 2] == board[row + 3][col + 3]) and (board[row][col] != " "):
                return true
    # Check diagonal (bottom-left to top-right) for winner
    for row in range (5,2,-1): 
        for col in range (3): 
            if (board[row][col] == board[row - 1][col + 1] == board[row - 2][col + 2] == board[row - 3][col + 3]) and (board[row][col] != " "):
                return [row][col]
    # No winner
    return False 


def main():
    display_instruct()
    computer,human = pieces()
    turn = X
    board = new_board()
    while not winner(board) and (" " not in board):
        display_board(board)
        if turn == human:
            human_move(board,human)
            get_move_row()
            place_piece()
        else:
            computer_move(board,computer)
            place_piece()
        display_board(board)
        turn = next_turn()
    the_winner = winner(board)
    congrat_winner(the_winner, computer, human)
#start the program
main ()                                                        
input ("\nPress the enter key to quit.")

1 个答案:

答案 0 :(得分:-1)

为了好玩,这是一个面向对象的重构。它有点长,但记录良好,应该很容易理解。

我开始使用您的代码并将其拆分为Board,Player和Game类,然后从Player中派生出计算机和人类。

  • 董事会知道机架的形状和大小,哪些动作是合法的,并确认胜利和关系何时发生
  • 玩家有一个名字,知道如何选择(或提示)合法移动
  • 游戏有一个棋盘和两个玩家并控制轮流和输出

我对它并不百分之百满意 - Board有一个.board,它是一个字符串列表列表,但是Game有一个Board作为Board;一点点明智的重命名是一个好主意 - 但是对于一个小时的工作来说,这是非常可靠的。

希望你能找到这种教育:

# Connect-4
from itertools import cycle, groupby
from random import choice
from textwrap import dedent
import sys

# version compatibility shims
if sys.hexversion < 0x3000000:
    # Python 2.x
    inp = raw_input
    rng = xrange
else:
    # Python 3.x
    inp = input
    rng = range

def get_yn(prompt, default=None, truthy={"y", "yes"}, falsy={"n", "no"}):
    """
    Prompt for yes-or-no input

    Return default if answer is blank and default is set
    Return True    if answer is in truthy
    Return False   if answer is in falsy
    """
    while True:
        yn = inp(prompt).strip().lower()
        if not yn and default is not None:
            return default
        elif yn in truthy:
            return True
        elif yn in falsy:
            return False

def get_int(prompt, lo=None, hi=None):
    """
    Prompt for integer input

    If lo is set, result must be >= lo
    If hi is set, result must be <= hi
    """
    while True:
        try:
            value = int(inp(prompt))
            if (lo is None or lo <= value) and (hi is None or value <= hi):
                return value
        except ValueError:
            pass

def four_in_a_row(tokens):
    """
    If there are four identical tokens in a row, return True
    """
    for val,iterable in groupby(tokens):
        if sum(1 for i in iterable) >= 4:
            return True
    return False

class Board:
    class BoardWon (BaseException): pass
    class BoardTied(BaseException): pass

    EMPTY = " . "
    HOR   = "---"
    P1    = " X "
    P2    = " O "
    VER   = "|"

    def __init__(self, width=8, height=6):
        self.width  = width
        self.height = height
        self.board  = [[Board.EMPTY] * width for h in rng(height)]
        self.tokens = cycle([Board.P1, Board.P2])
        self.rowfmt = Board.VER + Board.VER.join("{}"      for col in rng(width)) + Board.VER
        self.rule   = Board.VER + Board.VER.join(Board.HOR for col in rng(width)) + Board.VER

    def __str__(self):
        lines = []
        for row in self.board:
            lines.append(self.rowfmt.format(*row))
            lines.append(self.rule)
        lines.append(self.rowfmt.format(*("{:^3d}".format(i) for i in rng(1, self.width+1))))
        lines.append("")
        return "\n".join(lines)

    def is_board_full(self):
        return not any(cell == Board.EMPTY for cell in self.board[0])

    def is_win_through(self, row, col):
        """
        Check for any winning sequences which pass through self.board[row][col]

        (This is called every time a move is made;
        thus any win must involve the last move,
        and it is faster to check just a few cells
        instead of the entire board each time)
        """
        # check vertical
        down   = min(3, row)
        up     = min(3, self.height - row - 1)
        tokens = [self.board[r][col] for r in rng(row - down, row + up + 1)]
        if four_in_a_row(tokens):
            return True

        # check horizontal
        left   = min(3, col)
        right  = min(3, self.width - col - 1)
        tokens = [self.board[row][c] for c in rng(col - left, col + right + 1)]
        if four_in_a_row(tokens):
            return True

        # check upward diagonal
        down = left  = min(3, row, col)
        up   = right = min(3, self.height - row - 1, self.width - col - 1)
        tokens = [self.board[r][c] for r,c in zip(rng(row - down, row + up + 1), rng(col - left, col + right + 1))]
        if four_in_a_row(tokens):
            return True

        # check downward diagonal
        down = right = min(3, row, self.width - col - 1)
        up   = left  = min(3, self.height - row - 1, col)
        tokens = [self.board[r][c] for r,c in zip(rng(row - down, row + up + 1), rng(col + right, col - left - 1, -1))]
        if four_in_a_row(tokens):
            return True

        # none of the above
        return False

    def legal_moves(self):
        """
        Return a list of columns which are not full
        """
        return [col for col,val in enumerate(self.board[0], 1) if val == Board.EMPTY]

    def do_move(self, column):
        token = next(self.tokens)
        col   = column - 1
        # column is full?
        if self.board[0][col] != Board.EMPTY:
            next(self.move)  # reset player token
            raise ValueError
        # find lowest empty cell (guaranteed to find one)
        for row in rng(self.height-1, -1, -1):        # go from bottom to top
            if self.board[row][col] == Board.EMPTY:   # find first empty cell
                # take cell
                self.board[row][col] = token
                # did that result in a win?
                if self.is_win_through(row, col):
                    raise Board.BoardWon
                # if not, did it result in a full board?
                if self.is_board_full():
                    raise Board.BoardTied
                # done    
                break

class Player:
    def __init__(self, name):
        self.name = name

    def get_move(self, board):
        """
        Given the current board state, return the row to which you want to add a token
        """
        # you should derive from this class instead of using it directly
        raise NotImplemented

class Computer(Player):
    def get_move(self, board):
        return choice(board.legal_moves())

class Human(Player):
    def get_move(self, board):
        legal_moves = board.legal_moves()
        while True:
            move = get_int("Which column? (1-{}) ".format(board.width), lo=1, hi=board.width)
            if move in legal_moves:
                return move
            else:
                print("Please pick a column that is not already full!")

class Game:
    welcome = dedent("""
            Welcome to the second greatest intellectual challenge of all time: Connect4.  
            This will be a showdown between your human brain and my silicon processor.  

            You will make your move known by entering a column number, 1 - 7.  Your move 
            (if that column isn't already filled) will move to the lowest available position.

            Prepare yourself, human.  May the Schwartz be with you!

        """)

    def __init__(self):
        print(Game.welcome)

        # set up new board
        self.board = Board()
        # set up players
        self.players = cycle([Human("Dave"), Computer("HAL")])

        # who moves first?
        if get_yn("Do you want the first move? (Y/n) ", True):
            print("You will need it...\n")
            # default order is correct
        else:
            print("Your rashness will be your downfall...\n")
            next(self.players)

    def play(self):
        for player in self.players:
            print(self.board)
            while True:
                col = player.get_move(self.board)  # get desired column
                try:
                    print("{} picked Column {}".format(player.name, col))
                    self.board.do_move(col)        # make the move
                    break
                except ValueError:
                    print("Bad column choice - you can't move there")
                    # try again
                except Board.BoardWon:
                    print("{} won the game!".format(player.name))
                    return
                except Board.BoardTied:
                    print("The game ended in a stalemate")
                    return

def main():
    while True:
        Game().play()
        if not get_yn("Do you want to play again? (Y/n) ", True):
            break

if __name__=="__main__":
    main()