text: """Four in a Row, by Al Sweigart al@inventwithpython.com
  A tile-dropping game to get four in a row, similar to Connect Four.
  This code is available at https://nostarch.com/big-book-small-python-programming
  Tags: large, game, board game, two-player"""
  __version__ = 0
  import sys
  
  # Constants used for displaying the board:
  EMPTY_SPACE = '.'  # A period is easier to count than a space.
  PLAYER_X = 'X'
  PLAYER_O = 'O'
  
  # Note: Update displayBoard() & COLUMN_LABELS if BOARD_WIDTH is changed.
  BOARD_WIDTH = 7
  BOARD_HEIGHT = 6
  COLUMN_LABELS = ('1', '2', '3', '4', '5', '6', '7')
  assert len(COLUMN_LABELS) == BOARD_WIDTH
  
  
  def main():
      print("""Four in a Row, by Al Sweigart al@inventwithpython.com
  
  Two players take turns dropping tiles into one of seven columns, trying
  to make four in a row horizontally, vertically, or diagonally.
  """)
  
      # Set up a new game:
      gameBoard = getNewBoard()
      playerTurn = PLAYER_X
  
      while True:  # Run a player's turn.
          # Display the board and get player's move:
          displayBoard(gameBoard)
          playerMove = askForPlayerMove(playerTurn, gameBoard)
          gameBoard[playerMove] = playerTurn
  
          # Check for a win or tie:
          if isWinner(playerTurn, gameBoard):
              displayBoard(gameBoard)  # Display the board one last time.
              print('Player ' + playerTurn + ' has won!')
              sys.exit()
          elif isFull(gameBoard):
              displayBoard(gameBoard)  # Display the board one last time.
              print('There is a tie!')
              sys.exit()
  
          # Switch turns to other player:
          if playerTurn == PLAYER_X:
              playerTurn = PLAYER_O
          elif playerTurn == PLAYER_O:
              playerTurn = PLAYER_X
  
  
  def getNewBoard():
      """Returns a dictionary that represents a Four in a Row board.
  
      The keys are (columnIndex, rowIndex) tuples of two integers, and the
      values are one of the 'X', 'O' or '.' (empty space) strings."""
      board = {}
      for columnIndex in range(BOARD_WIDTH):
          for rowIndex in range(BOARD_HEIGHT):
              board[(columnIndex, rowIndex)] = EMPTY_SPACE
      return board
  
  
  def displayBoard(board):
      """Display the board and its tiles on the screen."""
  
      '''Prepare a list to pass to the format() string method for the
      board template. The list holds all of the board's tiles (and empty
      spaces) going left to right, top to bottom:'''
      tileChars = []
      for rowIndex in range(BOARD_HEIGHT):
          for columnIndex in range(BOARD_WIDTH):
              tileChars.append(board[(columnIndex, rowIndex)])
  
      # Display the board:
      print("""
       1234567
      +-------+
      |{}{}{}{}{}{}{}|
      |{}{}{}{}{}{}{}|
      |{}{}{}{}{}{}{}|
      |{}{}{}{}{}{}{}|
      |{}{}{}{}{}{}{}|
      |{}{}{}{}{}{}{}|
      +-------+""".format(*tileChars))
  
  
  def askForPlayerMove(playerTile, board):
      """Let a player select a column on the board to drop a tile into.
  
      Returns a tuple of the (column, row) that the tile falls into."""
      while True:  # Keep asking player until they enter a valid move.
          print('Player {}, enter a column or QUIT:'.format(playerTile))
          response = input('> ').upper().strip()
  
          if response == 'QUIT':
              print('Thanks for playing!')
              sys.exit()
  
          if response not in COLUMN_LABELS:
              print('Enter a number from 1 to {}.'.format(BOARD_WIDTH))
              continue  # Ask player again for their move.
  
          columnIndex = int(response) - 1  # -1 for 0-based the index.
  
          # If the column is full, ask for a move again:
          if board[(columnIndex, 0)] != EMPTY_SPACE:
              print('That column is full, select another one.')
              continue  # Ask player again for their move.
  
          # Starting from the bottom, find the first empty space.
          for rowIndex in range(BOARD_HEIGHT - 1, -1, -1):
              if board[(columnIndex, rowIndex)] == EMPTY_SPACE:
                  return (columnIndex, rowIndex)
  
  
  def isFull(board):
      """Returns True if the `board` has no empty spaces, otherwise
      returns False."""
      for rowIndex in range(BOARD_HEIGHT):
          for columnIndex in range(BOARD_WIDTH):
              if board[(columnIndex, rowIndex)] == EMPTY_SPACE:
                  return False  # Found an empty space, so return False.
      return True  # All spaces are full.
  
  
  def isWinner(playerTile, board):
      """Returns True if `playerTile` has four tiles in a row on `board`,
      otherwise returns False."""
  
      # Go through the entire board, checking for four-in-a-row:
      for columnIndex in range(BOARD_WIDTH - 3):
          for rowIndex in range(BOARD_HEIGHT):
              # Check for horizontal four-in-a-row going right:
              tile1 = board[(columnIndex, rowIndex)]
              tile2 = board[(columnIndex + 1, rowIndex)]
              tile3 = board[(columnIndex + 2, rowIndex)]
              tile4 = board[(columnIndex + 3, rowIndex)]
              if tile1 == tile2 == tile3 == tile4 == playerTile:
                  return True
  
      for columnIndex in range(BOARD_WIDTH):
          for rowIndex in range(BOARD_HEIGHT - 3):
              # Check for vertical four-in-a-row going down:
              tile1 = board[(columnIndex, rowIndex)]
              tile2 = board[(columnIndex, rowIndex + 1)]
              tile3 = board[(columnIndex, rowIndex + 2)]
              tile4 = board[(columnIndex, rowIndex + 3)]
              if tile1 == tile2 == tile3 == tile4 == playerTile:
                  return True
  
      for columnIndex in range(BOARD_WIDTH - 3):
          for rowIndex in range(BOARD_HEIGHT - 3):
              # Check for four-in-a-row going right-down diagonal:
              tile1 = board[(columnIndex, rowIndex)]
              tile2 = board[(columnIndex + 1, rowIndex + 1)]
              tile3 = board[(columnIndex + 2, rowIndex + 2)]
              tile4 = board[(columnIndex + 3, rowIndex + 3)]
              if tile1 == tile2 == tile3 == tile4 == playerTile:
                  return True
  
              # Check for four-in-a-row going left-down diagonal:
              tile1 = board[(columnIndex + 3, rowIndex)]
              tile2 = board[(columnIndex + 2, rowIndex + 1)]
              tile3 = board[(columnIndex + 1, rowIndex + 2)]
              tile4 = board[(columnIndex, rowIndex + 3)]
              if tile1 == tile2 == tile3 == tile4 == playerTile:
                  return True
      return False
  
  
  # If the program is run (instead of imported), run the game:
  if __name__ == '__main__':
      main()
  