Connect4 variant in Python

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
12
down vote

favorite












I built a variant of connect4 in Python. The game runs just in the command line.



It is on a 7×7 board and the players take turns putting tokens in a column (the token falls down) OR turn the board by 90° to the left or right and the tokens fall down again, creating a different board setting, but putting in no token this turn.



I would like to have some feedback on the implementation of the game logic and my Python coding style:



from string import ascii_uppercase


class TFBoard():
def __init__(self):
self.width = 7
self.height = 7
self.columns = range(1, self.height + 1)
self.rows = ascii_uppercase[:self.width]
self.matrix = [[0 for h in range(0, self.height)]
for w in range(0, self.width)]
self.endGame = False
self.winner = 0
self.playerTurn = 1
self.turnNumber = 1

def flatMatrix(self):
return [value for array in self.matrix for value in array]

def drawBoard(self):
col = ["33[0m", "33[91m", "33[31m", "33[97m", "33[92m"]

def drawInLoops(i, j):
if i == self.height:
if j == 0:
# bottom left corner
print(" ", end=f"")
else:
# bottom letter row
print(f"col[1]self.columns[j-1]col[0]", end=f" ")
else:
if j == 0:
# left number column
print(f"col[1]self.rows[-i-1]col[0]", end=" ")
else:
# squares
# drawn matrix is 1 higher and wider than self.matrix
print(f"col[2][col[0]", end="")
piece = self.matrix[j - 1][self.height - i - 1]
if piece == 1:
piece = f"col[3]Xcol[0]"
elif piece == 2:
piece = f"col[4]Ocol[0]"
elif piece == 0:
piece = " "
print(f"piece", end="")
print(f"col[2]]col[0]", end="")
for i in range(0, self.height + 1):
for j in range(0, self.width + 1):
drawInLoops(i, j)
print("")
print("") # new line after board for better looks

def putToken(self, player, column):
# find first nonzero entrie in column from top
notification = f"New Player player token in column column+1"
for i in range(self.height - 1, -1, -1):
if i == 0 and board.matrix[column][i] == 0:
self.matrix[column][0] = player
print(f"notification, row self.rows[i]")
return
if board.matrix[column][i] != 0:
if i == self.height - 1:
print(f"COLUMN FULL!nCan't place token in column i.")
else:
self.matrix[column][i + 1] = player
print(f"notification, row self.rows[i+1]")
return

def checkWin(self):
# check for win by column
def checkColumns():
# go through columns
for c in range(7):
column = self.matrix[c]
for r in range(4):
# start points r
start = column[r]
if start != 0 and all(token == start for token in column[r:r + 4]):
print(f"Win by column for player start")
print(f"self.rows[r]c+1-self.rows[r+3]c+1")
self.endGame = True
# check for win by row

def checkRows():
# go through rows
for r in range(self.height - 1, -1, -1):
# write rows as lists
row = [self.matrix[c][r] for c in range(7)]
for c in range(4):
start = row[c]
if start != 0 and all(token == start for token in row[c:c + 4]):
print(f"Win by row for player start")
print(f"self.rows[r]c+1-self.rows[r]c+4")
self.endGame = True

def checkbltrDiagonals():
for c in range(4):
for r in range(4):
diagonal = [self.matrix[c + x][r + x] for x in range(4)]
start = diagonal[0]
if start != 0 and all(token == start for token in diagonal):
print(f"Win by diagonal bltr for player start")
print(f"self.rows[r]c+1-self.rows[r+3]c+4")
self.endGame = True

def checktlbrDiagonals():
for c in range(4):
for r in range(3, 7):
diagonal = [self.matrix[c + x][r - x] for x in range(4)]
start = diagonal[0]
if start != 0 and all(token == start for token in diagonal):
print(f"Win by diagonal tlbr for player start")
print(f"self.rows[r]c+1-self.rows[r-3]c+4")
self.endGame = True

checkColumns()
checkRows()
checktlbrDiagonals()
checkbltrDiagonals()

def checkDraw(self):
if all(x != 0 for x in self.flatMatrix()):
return True

def applyGravity(self):
for i in range(7):
self.matrix[i] = [x for x in self.matrix[i] if x != 0]
self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]

def rotateLeft(self):
self.matrix = list(list(x) for x in zip(*self.matrix))[::-1]

def rotateRight(self):
self.matrix = list(list(x)[::-1] for x in zip(*self.matrix))

def gameLoop(self):
print("---NEW GAME")
self.drawBoard()
while self.endGame is False:
print(f"---Turn self.turnNumber:")
turn = input(f"Player self.playerTurn, make your move.n(1,2,3,4,5,6,7,L,R)n---")
if turn not in ["1", "2", "3", "4", "5", "6", "7", "l", "L", "r", "R"]:
print(f"WRONG INPUT turn!nInput must be L, R or an integer between 1 and 7.")
continue
if turn == "L" or turn == "l":
self.rotateLeft()
self.applyGravity()
elif turn == "R" or turn == "r":
self.rotateRight()
self.applyGravity()
elif int(turn) in [1, 2, 3, 4, 5, 6, 7]:
self.putToken(self.playerTurn, int(turn) - 1)
self.checkWin()
if self.endGame is True:
self.winner = self.playerTurn
break
if self.checkDraw():
break
self.playerTurn = 1 if self.playerTurn == 2 else 2
self.turnNumber += 1
self.drawBoard()
if self.winner == 0:
print(f"DRAW!")
else:
print(f"Player self.winner won in self.turnNumber turns!")
self.drawBoard()
return self.winner


board = TFBoard()
board.gameLoop()






share|improve this question



























    up vote
    12
    down vote

    favorite












    I built a variant of connect4 in Python. The game runs just in the command line.



    It is on a 7×7 board and the players take turns putting tokens in a column (the token falls down) OR turn the board by 90° to the left or right and the tokens fall down again, creating a different board setting, but putting in no token this turn.



    I would like to have some feedback on the implementation of the game logic and my Python coding style:



    from string import ascii_uppercase


    class TFBoard():
    def __init__(self):
    self.width = 7
    self.height = 7
    self.columns = range(1, self.height + 1)
    self.rows = ascii_uppercase[:self.width]
    self.matrix = [[0 for h in range(0, self.height)]
    for w in range(0, self.width)]
    self.endGame = False
    self.winner = 0
    self.playerTurn = 1
    self.turnNumber = 1

    def flatMatrix(self):
    return [value for array in self.matrix for value in array]

    def drawBoard(self):
    col = ["33[0m", "33[91m", "33[31m", "33[97m", "33[92m"]

    def drawInLoops(i, j):
    if i == self.height:
    if j == 0:
    # bottom left corner
    print(" ", end=f"")
    else:
    # bottom letter row
    print(f"col[1]self.columns[j-1]col[0]", end=f" ")
    else:
    if j == 0:
    # left number column
    print(f"col[1]self.rows[-i-1]col[0]", end=" ")
    else:
    # squares
    # drawn matrix is 1 higher and wider than self.matrix
    print(f"col[2][col[0]", end="")
    piece = self.matrix[j - 1][self.height - i - 1]
    if piece == 1:
    piece = f"col[3]Xcol[0]"
    elif piece == 2:
    piece = f"col[4]Ocol[0]"
    elif piece == 0:
    piece = " "
    print(f"piece", end="")
    print(f"col[2]]col[0]", end="")
    for i in range(0, self.height + 1):
    for j in range(0, self.width + 1):
    drawInLoops(i, j)
    print("")
    print("") # new line after board for better looks

    def putToken(self, player, column):
    # find first nonzero entrie in column from top
    notification = f"New Player player token in column column+1"
    for i in range(self.height - 1, -1, -1):
    if i == 0 and board.matrix[column][i] == 0:
    self.matrix[column][0] = player
    print(f"notification, row self.rows[i]")
    return
    if board.matrix[column][i] != 0:
    if i == self.height - 1:
    print(f"COLUMN FULL!nCan't place token in column i.")
    else:
    self.matrix[column][i + 1] = player
    print(f"notification, row self.rows[i+1]")
    return

    def checkWin(self):
    # check for win by column
    def checkColumns():
    # go through columns
    for c in range(7):
    column = self.matrix[c]
    for r in range(4):
    # start points r
    start = column[r]
    if start != 0 and all(token == start for token in column[r:r + 4]):
    print(f"Win by column for player start")
    print(f"self.rows[r]c+1-self.rows[r+3]c+1")
    self.endGame = True
    # check for win by row

    def checkRows():
    # go through rows
    for r in range(self.height - 1, -1, -1):
    # write rows as lists
    row = [self.matrix[c][r] for c in range(7)]
    for c in range(4):
    start = row[c]
    if start != 0 and all(token == start for token in row[c:c + 4]):
    print(f"Win by row for player start")
    print(f"self.rows[r]c+1-self.rows[r]c+4")
    self.endGame = True

    def checkbltrDiagonals():
    for c in range(4):
    for r in range(4):
    diagonal = [self.matrix[c + x][r + x] for x in range(4)]
    start = diagonal[0]
    if start != 0 and all(token == start for token in diagonal):
    print(f"Win by diagonal bltr for player start")
    print(f"self.rows[r]c+1-self.rows[r+3]c+4")
    self.endGame = True

    def checktlbrDiagonals():
    for c in range(4):
    for r in range(3, 7):
    diagonal = [self.matrix[c + x][r - x] for x in range(4)]
    start = diagonal[0]
    if start != 0 and all(token == start for token in diagonal):
    print(f"Win by diagonal tlbr for player start")
    print(f"self.rows[r]c+1-self.rows[r-3]c+4")
    self.endGame = True

    checkColumns()
    checkRows()
    checktlbrDiagonals()
    checkbltrDiagonals()

    def checkDraw(self):
    if all(x != 0 for x in self.flatMatrix()):
    return True

    def applyGravity(self):
    for i in range(7):
    self.matrix[i] = [x for x in self.matrix[i] if x != 0]
    self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]

    def rotateLeft(self):
    self.matrix = list(list(x) for x in zip(*self.matrix))[::-1]

    def rotateRight(self):
    self.matrix = list(list(x)[::-1] for x in zip(*self.matrix))

    def gameLoop(self):
    print("---NEW GAME")
    self.drawBoard()
    while self.endGame is False:
    print(f"---Turn self.turnNumber:")
    turn = input(f"Player self.playerTurn, make your move.n(1,2,3,4,5,6,7,L,R)n---")
    if turn not in ["1", "2", "3", "4", "5", "6", "7", "l", "L", "r", "R"]:
    print(f"WRONG INPUT turn!nInput must be L, R or an integer between 1 and 7.")
    continue
    if turn == "L" or turn == "l":
    self.rotateLeft()
    self.applyGravity()
    elif turn == "R" or turn == "r":
    self.rotateRight()
    self.applyGravity()
    elif int(turn) in [1, 2, 3, 4, 5, 6, 7]:
    self.putToken(self.playerTurn, int(turn) - 1)
    self.checkWin()
    if self.endGame is True:
    self.winner = self.playerTurn
    break
    if self.checkDraw():
    break
    self.playerTurn = 1 if self.playerTurn == 2 else 2
    self.turnNumber += 1
    self.drawBoard()
    if self.winner == 0:
    print(f"DRAW!")
    else:
    print(f"Player self.winner won in self.turnNumber turns!")
    self.drawBoard()
    return self.winner


    board = TFBoard()
    board.gameLoop()






    share|improve this question























      up vote
      12
      down vote

      favorite









      up vote
      12
      down vote

      favorite











      I built a variant of connect4 in Python. The game runs just in the command line.



      It is on a 7×7 board and the players take turns putting tokens in a column (the token falls down) OR turn the board by 90° to the left or right and the tokens fall down again, creating a different board setting, but putting in no token this turn.



      I would like to have some feedback on the implementation of the game logic and my Python coding style:



      from string import ascii_uppercase


      class TFBoard():
      def __init__(self):
      self.width = 7
      self.height = 7
      self.columns = range(1, self.height + 1)
      self.rows = ascii_uppercase[:self.width]
      self.matrix = [[0 for h in range(0, self.height)]
      for w in range(0, self.width)]
      self.endGame = False
      self.winner = 0
      self.playerTurn = 1
      self.turnNumber = 1

      def flatMatrix(self):
      return [value for array in self.matrix for value in array]

      def drawBoard(self):
      col = ["33[0m", "33[91m", "33[31m", "33[97m", "33[92m"]

      def drawInLoops(i, j):
      if i == self.height:
      if j == 0:
      # bottom left corner
      print(" ", end=f"")
      else:
      # bottom letter row
      print(f"col[1]self.columns[j-1]col[0]", end=f" ")
      else:
      if j == 0:
      # left number column
      print(f"col[1]self.rows[-i-1]col[0]", end=" ")
      else:
      # squares
      # drawn matrix is 1 higher and wider than self.matrix
      print(f"col[2][col[0]", end="")
      piece = self.matrix[j - 1][self.height - i - 1]
      if piece == 1:
      piece = f"col[3]Xcol[0]"
      elif piece == 2:
      piece = f"col[4]Ocol[0]"
      elif piece == 0:
      piece = " "
      print(f"piece", end="")
      print(f"col[2]]col[0]", end="")
      for i in range(0, self.height + 1):
      for j in range(0, self.width + 1):
      drawInLoops(i, j)
      print("")
      print("") # new line after board for better looks

      def putToken(self, player, column):
      # find first nonzero entrie in column from top
      notification = f"New Player player token in column column+1"
      for i in range(self.height - 1, -1, -1):
      if i == 0 and board.matrix[column][i] == 0:
      self.matrix[column][0] = player
      print(f"notification, row self.rows[i]")
      return
      if board.matrix[column][i] != 0:
      if i == self.height - 1:
      print(f"COLUMN FULL!nCan't place token in column i.")
      else:
      self.matrix[column][i + 1] = player
      print(f"notification, row self.rows[i+1]")
      return

      def checkWin(self):
      # check for win by column
      def checkColumns():
      # go through columns
      for c in range(7):
      column = self.matrix[c]
      for r in range(4):
      # start points r
      start = column[r]
      if start != 0 and all(token == start for token in column[r:r + 4]):
      print(f"Win by column for player start")
      print(f"self.rows[r]c+1-self.rows[r+3]c+1")
      self.endGame = True
      # check for win by row

      def checkRows():
      # go through rows
      for r in range(self.height - 1, -1, -1):
      # write rows as lists
      row = [self.matrix[c][r] for c in range(7)]
      for c in range(4):
      start = row[c]
      if start != 0 and all(token == start for token in row[c:c + 4]):
      print(f"Win by row for player start")
      print(f"self.rows[r]c+1-self.rows[r]c+4")
      self.endGame = True

      def checkbltrDiagonals():
      for c in range(4):
      for r in range(4):
      diagonal = [self.matrix[c + x][r + x] for x in range(4)]
      start = diagonal[0]
      if start != 0 and all(token == start for token in diagonal):
      print(f"Win by diagonal bltr for player start")
      print(f"self.rows[r]c+1-self.rows[r+3]c+4")
      self.endGame = True

      def checktlbrDiagonals():
      for c in range(4):
      for r in range(3, 7):
      diagonal = [self.matrix[c + x][r - x] for x in range(4)]
      start = diagonal[0]
      if start != 0 and all(token == start for token in diagonal):
      print(f"Win by diagonal tlbr for player start")
      print(f"self.rows[r]c+1-self.rows[r-3]c+4")
      self.endGame = True

      checkColumns()
      checkRows()
      checktlbrDiagonals()
      checkbltrDiagonals()

      def checkDraw(self):
      if all(x != 0 for x in self.flatMatrix()):
      return True

      def applyGravity(self):
      for i in range(7):
      self.matrix[i] = [x for x in self.matrix[i] if x != 0]
      self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]

      def rotateLeft(self):
      self.matrix = list(list(x) for x in zip(*self.matrix))[::-1]

      def rotateRight(self):
      self.matrix = list(list(x)[::-1] for x in zip(*self.matrix))

      def gameLoop(self):
      print("---NEW GAME")
      self.drawBoard()
      while self.endGame is False:
      print(f"---Turn self.turnNumber:")
      turn = input(f"Player self.playerTurn, make your move.n(1,2,3,4,5,6,7,L,R)n---")
      if turn not in ["1", "2", "3", "4", "5", "6", "7", "l", "L", "r", "R"]:
      print(f"WRONG INPUT turn!nInput must be L, R or an integer between 1 and 7.")
      continue
      if turn == "L" or turn == "l":
      self.rotateLeft()
      self.applyGravity()
      elif turn == "R" or turn == "r":
      self.rotateRight()
      self.applyGravity()
      elif int(turn) in [1, 2, 3, 4, 5, 6, 7]:
      self.putToken(self.playerTurn, int(turn) - 1)
      self.checkWin()
      if self.endGame is True:
      self.winner = self.playerTurn
      break
      if self.checkDraw():
      break
      self.playerTurn = 1 if self.playerTurn == 2 else 2
      self.turnNumber += 1
      self.drawBoard()
      if self.winner == 0:
      print(f"DRAW!")
      else:
      print(f"Player self.winner won in self.turnNumber turns!")
      self.drawBoard()
      return self.winner


      board = TFBoard()
      board.gameLoop()






      share|improve this question













      I built a variant of connect4 in Python. The game runs just in the command line.



      It is on a 7×7 board and the players take turns putting tokens in a column (the token falls down) OR turn the board by 90° to the left or right and the tokens fall down again, creating a different board setting, but putting in no token this turn.



      I would like to have some feedback on the implementation of the game logic and my Python coding style:



      from string import ascii_uppercase


      class TFBoard():
      def __init__(self):
      self.width = 7
      self.height = 7
      self.columns = range(1, self.height + 1)
      self.rows = ascii_uppercase[:self.width]
      self.matrix = [[0 for h in range(0, self.height)]
      for w in range(0, self.width)]
      self.endGame = False
      self.winner = 0
      self.playerTurn = 1
      self.turnNumber = 1

      def flatMatrix(self):
      return [value for array in self.matrix for value in array]

      def drawBoard(self):
      col = ["33[0m", "33[91m", "33[31m", "33[97m", "33[92m"]

      def drawInLoops(i, j):
      if i == self.height:
      if j == 0:
      # bottom left corner
      print(" ", end=f"")
      else:
      # bottom letter row
      print(f"col[1]self.columns[j-1]col[0]", end=f" ")
      else:
      if j == 0:
      # left number column
      print(f"col[1]self.rows[-i-1]col[0]", end=" ")
      else:
      # squares
      # drawn matrix is 1 higher and wider than self.matrix
      print(f"col[2][col[0]", end="")
      piece = self.matrix[j - 1][self.height - i - 1]
      if piece == 1:
      piece = f"col[3]Xcol[0]"
      elif piece == 2:
      piece = f"col[4]Ocol[0]"
      elif piece == 0:
      piece = " "
      print(f"piece", end="")
      print(f"col[2]]col[0]", end="")
      for i in range(0, self.height + 1):
      for j in range(0, self.width + 1):
      drawInLoops(i, j)
      print("")
      print("") # new line after board for better looks

      def putToken(self, player, column):
      # find first nonzero entrie in column from top
      notification = f"New Player player token in column column+1"
      for i in range(self.height - 1, -1, -1):
      if i == 0 and board.matrix[column][i] == 0:
      self.matrix[column][0] = player
      print(f"notification, row self.rows[i]")
      return
      if board.matrix[column][i] != 0:
      if i == self.height - 1:
      print(f"COLUMN FULL!nCan't place token in column i.")
      else:
      self.matrix[column][i + 1] = player
      print(f"notification, row self.rows[i+1]")
      return

      def checkWin(self):
      # check for win by column
      def checkColumns():
      # go through columns
      for c in range(7):
      column = self.matrix[c]
      for r in range(4):
      # start points r
      start = column[r]
      if start != 0 and all(token == start for token in column[r:r + 4]):
      print(f"Win by column for player start")
      print(f"self.rows[r]c+1-self.rows[r+3]c+1")
      self.endGame = True
      # check for win by row

      def checkRows():
      # go through rows
      for r in range(self.height - 1, -1, -1):
      # write rows as lists
      row = [self.matrix[c][r] for c in range(7)]
      for c in range(4):
      start = row[c]
      if start != 0 and all(token == start for token in row[c:c + 4]):
      print(f"Win by row for player start")
      print(f"self.rows[r]c+1-self.rows[r]c+4")
      self.endGame = True

      def checkbltrDiagonals():
      for c in range(4):
      for r in range(4):
      diagonal = [self.matrix[c + x][r + x] for x in range(4)]
      start = diagonal[0]
      if start != 0 and all(token == start for token in diagonal):
      print(f"Win by diagonal bltr for player start")
      print(f"self.rows[r]c+1-self.rows[r+3]c+4")
      self.endGame = True

      def checktlbrDiagonals():
      for c in range(4):
      for r in range(3, 7):
      diagonal = [self.matrix[c + x][r - x] for x in range(4)]
      start = diagonal[0]
      if start != 0 and all(token == start for token in diagonal):
      print(f"Win by diagonal tlbr for player start")
      print(f"self.rows[r]c+1-self.rows[r-3]c+4")
      self.endGame = True

      checkColumns()
      checkRows()
      checktlbrDiagonals()
      checkbltrDiagonals()

      def checkDraw(self):
      if all(x != 0 for x in self.flatMatrix()):
      return True

      def applyGravity(self):
      for i in range(7):
      self.matrix[i] = [x for x in self.matrix[i] if x != 0]
      self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]

      def rotateLeft(self):
      self.matrix = list(list(x) for x in zip(*self.matrix))[::-1]

      def rotateRight(self):
      self.matrix = list(list(x)[::-1] for x in zip(*self.matrix))

      def gameLoop(self):
      print("---NEW GAME")
      self.drawBoard()
      while self.endGame is False:
      print(f"---Turn self.turnNumber:")
      turn = input(f"Player self.playerTurn, make your move.n(1,2,3,4,5,6,7,L,R)n---")
      if turn not in ["1", "2", "3", "4", "5", "6", "7", "l", "L", "r", "R"]:
      print(f"WRONG INPUT turn!nInput must be L, R or an integer between 1 and 7.")
      continue
      if turn == "L" or turn == "l":
      self.rotateLeft()
      self.applyGravity()
      elif turn == "R" or turn == "r":
      self.rotateRight()
      self.applyGravity()
      elif int(turn) in [1, 2, 3, 4, 5, 6, 7]:
      self.putToken(self.playerTurn, int(turn) - 1)
      self.checkWin()
      if self.endGame is True:
      self.winner = self.playerTurn
      break
      if self.checkDraw():
      break
      self.playerTurn = 1 if self.playerTurn == 2 else 2
      self.turnNumber += 1
      self.drawBoard()
      if self.winner == 0:
      print(f"DRAW!")
      else:
      print(f"Player self.winner won in self.turnNumber turns!")
      self.drawBoard()
      return self.winner


      board = TFBoard()
      board.gameLoop()








      share|improve this question












      share|improve this question




      share|improve this question








      edited Feb 11 at 6:24
























      asked Feb 6 at 17:24









      Tweakimp

      2621212




      2621212




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          As there is no answer yet - some observations in no specific order



          you miss the top level main guard which allows the module to be imported



          if __name__ == '__main__':
          board = TFBoard()
          board.gameLoop()


          your class is not really a class



          It is not intended to be copied, compared, it does not communicate with other program parts. It even has a blocking loop. It is just a namespace like container. however modules do already fulfill the namespace. you could safely remove all class and self stuff and run the application like



          if __name__ == '__main__':
          init()
          gameLoop()


          If you want to design a class you have to remove the gameLoop from it. then you notice there is a little problem with the rotate which forces you to expose internal implementation details to the main loop by requiring a call to applyGravity as well. by the way putToken does the job correctly, one input resulting in one call to the board.



          ensure functions/methods do what the name promises



          rotate does not rotate the board, but a matrix only. it would make a perfect name for a method of a matrix class. a board method should do the complete job and apply the gravity as well.



          reuse what you have



          you could insert tokens on the top only and use applyGravity to let it fall down. not only this resembles physics, but also there is less code to test. putToken shows high complexity and repeated code.



          handle errors



          your putToken does detect an error if a column is full. however it does not forward this to the loop, so the player is turned over.



          separate I/O from core



          do not do I/O from core functions, but from main loop only. this requires providing state and error information to the loop by return values or raising exceptions. or by providing getters for state. this will immediately lead to better design and testable functions.



          there shall be no magic numbers in the code, define constants



          when you decide to go for a 9x9 instead of a 7x7 board, there shall be only two edits. you make it worse by having those numbers as attributes, but you do use them only for drawing. when checking for wins, applying gravity or handling input you have raw numbers in the code. this is the worst possible combination, pretend to handle your constants properly in the __init__ but ignoring these later on. seriously, this is an absolute fail. also have a definition for 4 and write correct expressions for all the dependent values subtracting it from height or width.



          some python sugar



          self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]


          may be written shorter (and more readable)



          self.matrix[i] += [0] * (7 - len(self.matrix[i]))


          learn to write unit tests



          python provides built-in unit test support. it is really easy to use and of great use. what you invest in unit testing you get returned in better design, less errors, better maintainability and probably you even save time you use for debugging otherwise. again seriously, you will be a much better programmer when you have done your first little project with unit testing.



          finally



          my answer is intended to help you, not to intimidate you. try to understand and get better. if you have questions regarding my points, please feel free to ask.






          share|improve this answer





















          • Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
            – Tweakimp
            Feb 16 at 19:49










          • I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
            – stefan
            Feb 16 at 20:04










          • I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
            – Tweakimp
            Feb 16 at 20:33










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186932%2fconnect4-variant-in-python%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          As there is no answer yet - some observations in no specific order



          you miss the top level main guard which allows the module to be imported



          if __name__ == '__main__':
          board = TFBoard()
          board.gameLoop()


          your class is not really a class



          It is not intended to be copied, compared, it does not communicate with other program parts. It even has a blocking loop. It is just a namespace like container. however modules do already fulfill the namespace. you could safely remove all class and self stuff and run the application like



          if __name__ == '__main__':
          init()
          gameLoop()


          If you want to design a class you have to remove the gameLoop from it. then you notice there is a little problem with the rotate which forces you to expose internal implementation details to the main loop by requiring a call to applyGravity as well. by the way putToken does the job correctly, one input resulting in one call to the board.



          ensure functions/methods do what the name promises



          rotate does not rotate the board, but a matrix only. it would make a perfect name for a method of a matrix class. a board method should do the complete job and apply the gravity as well.



          reuse what you have



          you could insert tokens on the top only and use applyGravity to let it fall down. not only this resembles physics, but also there is less code to test. putToken shows high complexity and repeated code.



          handle errors



          your putToken does detect an error if a column is full. however it does not forward this to the loop, so the player is turned over.



          separate I/O from core



          do not do I/O from core functions, but from main loop only. this requires providing state and error information to the loop by return values or raising exceptions. or by providing getters for state. this will immediately lead to better design and testable functions.



          there shall be no magic numbers in the code, define constants



          when you decide to go for a 9x9 instead of a 7x7 board, there shall be only two edits. you make it worse by having those numbers as attributes, but you do use them only for drawing. when checking for wins, applying gravity or handling input you have raw numbers in the code. this is the worst possible combination, pretend to handle your constants properly in the __init__ but ignoring these later on. seriously, this is an absolute fail. also have a definition for 4 and write correct expressions for all the dependent values subtracting it from height or width.



          some python sugar



          self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]


          may be written shorter (and more readable)



          self.matrix[i] += [0] * (7 - len(self.matrix[i]))


          learn to write unit tests



          python provides built-in unit test support. it is really easy to use and of great use. what you invest in unit testing you get returned in better design, less errors, better maintainability and probably you even save time you use for debugging otherwise. again seriously, you will be a much better programmer when you have done your first little project with unit testing.



          finally



          my answer is intended to help you, not to intimidate you. try to understand and get better. if you have questions regarding my points, please feel free to ask.






          share|improve this answer





















          • Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
            – Tweakimp
            Feb 16 at 19:49










          • I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
            – stefan
            Feb 16 at 20:04










          • I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
            – Tweakimp
            Feb 16 at 20:33














          up vote
          2
          down vote



          accepted










          As there is no answer yet - some observations in no specific order



          you miss the top level main guard which allows the module to be imported



          if __name__ == '__main__':
          board = TFBoard()
          board.gameLoop()


          your class is not really a class



          It is not intended to be copied, compared, it does not communicate with other program parts. It even has a blocking loop. It is just a namespace like container. however modules do already fulfill the namespace. you could safely remove all class and self stuff and run the application like



          if __name__ == '__main__':
          init()
          gameLoop()


          If you want to design a class you have to remove the gameLoop from it. then you notice there is a little problem with the rotate which forces you to expose internal implementation details to the main loop by requiring a call to applyGravity as well. by the way putToken does the job correctly, one input resulting in one call to the board.



          ensure functions/methods do what the name promises



          rotate does not rotate the board, but a matrix only. it would make a perfect name for a method of a matrix class. a board method should do the complete job and apply the gravity as well.



          reuse what you have



          you could insert tokens on the top only and use applyGravity to let it fall down. not only this resembles physics, but also there is less code to test. putToken shows high complexity and repeated code.



          handle errors



          your putToken does detect an error if a column is full. however it does not forward this to the loop, so the player is turned over.



          separate I/O from core



          do not do I/O from core functions, but from main loop only. this requires providing state and error information to the loop by return values or raising exceptions. or by providing getters for state. this will immediately lead to better design and testable functions.



          there shall be no magic numbers in the code, define constants



          when you decide to go for a 9x9 instead of a 7x7 board, there shall be only two edits. you make it worse by having those numbers as attributes, but you do use them only for drawing. when checking for wins, applying gravity or handling input you have raw numbers in the code. this is the worst possible combination, pretend to handle your constants properly in the __init__ but ignoring these later on. seriously, this is an absolute fail. also have a definition for 4 and write correct expressions for all the dependent values subtracting it from height or width.



          some python sugar



          self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]


          may be written shorter (and more readable)



          self.matrix[i] += [0] * (7 - len(self.matrix[i]))


          learn to write unit tests



          python provides built-in unit test support. it is really easy to use and of great use. what you invest in unit testing you get returned in better design, less errors, better maintainability and probably you even save time you use for debugging otherwise. again seriously, you will be a much better programmer when you have done your first little project with unit testing.



          finally



          my answer is intended to help you, not to intimidate you. try to understand and get better. if you have questions regarding my points, please feel free to ask.






          share|improve this answer





















          • Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
            – Tweakimp
            Feb 16 at 19:49










          • I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
            – stefan
            Feb 16 at 20:04










          • I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
            – Tweakimp
            Feb 16 at 20:33












          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          As there is no answer yet - some observations in no specific order



          you miss the top level main guard which allows the module to be imported



          if __name__ == '__main__':
          board = TFBoard()
          board.gameLoop()


          your class is not really a class



          It is not intended to be copied, compared, it does not communicate with other program parts. It even has a blocking loop. It is just a namespace like container. however modules do already fulfill the namespace. you could safely remove all class and self stuff and run the application like



          if __name__ == '__main__':
          init()
          gameLoop()


          If you want to design a class you have to remove the gameLoop from it. then you notice there is a little problem with the rotate which forces you to expose internal implementation details to the main loop by requiring a call to applyGravity as well. by the way putToken does the job correctly, one input resulting in one call to the board.



          ensure functions/methods do what the name promises



          rotate does not rotate the board, but a matrix only. it would make a perfect name for a method of a matrix class. a board method should do the complete job and apply the gravity as well.



          reuse what you have



          you could insert tokens on the top only and use applyGravity to let it fall down. not only this resembles physics, but also there is less code to test. putToken shows high complexity and repeated code.



          handle errors



          your putToken does detect an error if a column is full. however it does not forward this to the loop, so the player is turned over.



          separate I/O from core



          do not do I/O from core functions, but from main loop only. this requires providing state and error information to the loop by return values or raising exceptions. or by providing getters for state. this will immediately lead to better design and testable functions.



          there shall be no magic numbers in the code, define constants



          when you decide to go for a 9x9 instead of a 7x7 board, there shall be only two edits. you make it worse by having those numbers as attributes, but you do use them only for drawing. when checking for wins, applying gravity or handling input you have raw numbers in the code. this is the worst possible combination, pretend to handle your constants properly in the __init__ but ignoring these later on. seriously, this is an absolute fail. also have a definition for 4 and write correct expressions for all the dependent values subtracting it from height or width.



          some python sugar



          self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]


          may be written shorter (and more readable)



          self.matrix[i] += [0] * (7 - len(self.matrix[i]))


          learn to write unit tests



          python provides built-in unit test support. it is really easy to use and of great use. what you invest in unit testing you get returned in better design, less errors, better maintainability and probably you even save time you use for debugging otherwise. again seriously, you will be a much better programmer when you have done your first little project with unit testing.



          finally



          my answer is intended to help you, not to intimidate you. try to understand and get better. if you have questions regarding my points, please feel free to ask.






          share|improve this answer













          As there is no answer yet - some observations in no specific order



          you miss the top level main guard which allows the module to be imported



          if __name__ == '__main__':
          board = TFBoard()
          board.gameLoop()


          your class is not really a class



          It is not intended to be copied, compared, it does not communicate with other program parts. It even has a blocking loop. It is just a namespace like container. however modules do already fulfill the namespace. you could safely remove all class and self stuff and run the application like



          if __name__ == '__main__':
          init()
          gameLoop()


          If you want to design a class you have to remove the gameLoop from it. then you notice there is a little problem with the rotate which forces you to expose internal implementation details to the main loop by requiring a call to applyGravity as well. by the way putToken does the job correctly, one input resulting in one call to the board.



          ensure functions/methods do what the name promises



          rotate does not rotate the board, but a matrix only. it would make a perfect name for a method of a matrix class. a board method should do the complete job and apply the gravity as well.



          reuse what you have



          you could insert tokens on the top only and use applyGravity to let it fall down. not only this resembles physics, but also there is less code to test. putToken shows high complexity and repeated code.



          handle errors



          your putToken does detect an error if a column is full. however it does not forward this to the loop, so the player is turned over.



          separate I/O from core



          do not do I/O from core functions, but from main loop only. this requires providing state and error information to the loop by return values or raising exceptions. or by providing getters for state. this will immediately lead to better design and testable functions.



          there shall be no magic numbers in the code, define constants



          when you decide to go for a 9x9 instead of a 7x7 board, there shall be only two edits. you make it worse by having those numbers as attributes, but you do use them only for drawing. when checking for wins, applying gravity or handling input you have raw numbers in the code. this is the worst possible combination, pretend to handle your constants properly in the __init__ but ignoring these later on. seriously, this is an absolute fail. also have a definition for 4 and write correct expressions for all the dependent values subtracting it from height or width.



          some python sugar



          self.matrix[i] += [0 for _ in range(7 - len(self.matrix[i]))]


          may be written shorter (and more readable)



          self.matrix[i] += [0] * (7 - len(self.matrix[i]))


          learn to write unit tests



          python provides built-in unit test support. it is really easy to use and of great use. what you invest in unit testing you get returned in better design, less errors, better maintainability and probably you even save time you use for debugging otherwise. again seriously, you will be a much better programmer when you have done your first little project with unit testing.



          finally



          my answer is intended to help you, not to intimidate you. try to understand and get better. if you have questions regarding my points, please feel free to ask.







          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered Feb 16 at 19:13









          stefan

          1,201110




          1,201110











          • Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
            – Tweakimp
            Feb 16 at 19:49










          • I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
            – stefan
            Feb 16 at 20:04










          • I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
            – Tweakimp
            Feb 16 at 20:33
















          • Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
            – Tweakimp
            Feb 16 at 19:49










          • I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
            – stefan
            Feb 16 at 20:04










          • I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
            – Tweakimp
            Feb 16 at 20:33















          Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
          – Tweakimp
          Feb 16 at 19:49




          Thank you for your answer. I made it a class to call it multiple times by another module, for example when I let random players play against each other multiple times. The matrix is the list of lists that stores the game data, the board is the thing that is drawn into the console. The code reuse is totally true, this is something I just dont see in my own code. In case of a full coloumn, the player is not turned over because the player number does not change. There is a continue statement for that case. i would like to go throught a different file if you are up for it. We could use the SO chat
          – Tweakimp
          Feb 16 at 19:49












          I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
          – stefan
          Feb 16 at 20:04




          I'm off in a minute. Feel free to start a chat, I definitely will answer, but unfortunately not now.
          – stefan
          Feb 16 at 20:04












          I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
          – Tweakimp
          Feb 16 at 20:33




          I dont know id this works... chat.stackexchange.com/rooms/73272/tweakimp
          – Tweakimp
          Feb 16 at 20:33












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186932%2fconnect4-variant-in-python%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          Will my employers contract hold up in court?