In over my head: Debugging and many errors
Question: I am trying to write a program for connect 4 but am having a lot of trouble
getting past the directions. Everything under the comment, "#everything works
up to here" works but then it all explodes and I have no idea even where to
start to fix it.

    
    
    #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.")
    


Answer: For fun, here's an object-oriented refactorization. It's a bit long, but well
documented and should be easy to understand.

I started with your code and split it into Board, Player, and Game classes,
then derived Computer and Human classes from Player.

  * Board knows the shape and size of the rack, what moves are legal, and recognizes when wins and ties occur
  * Player has a name and knows how to choose (or prompt for) a legal move
  * Game has a Board and two Players and controls turn-taking and output

I'm not 100% happy with it - Board has a .board that is a list of list of
string, but Game has a .board that is a Board; a bit of judicious renaming
would be a good idea - but for an hour's work it's pretty solid.

Hope you find this educational:

    
    
    # 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()
    

