connect_four

mail@pastecode.io avatar
unknown
python
3 years ago
6.4 kB
2
Indexable
Never
class Connect_N_State:
  # Define all the required attributes to be private
  def __init__(self,wid,hei, target, players):
    self.__width = wid
    self.__height = hei
    self.__target = target 
    self.__players = players 
    self.__board = [["." for _ in range(self.__width)] for _ in range(self.__height)]
    self.__player_char = dict(zip(list(map(lambda x:x[0],self.__players)),self.__players))
    self.__current_player_idx = 0
    
  # define the methods
  def get_size(self):
    return (self.__width,self.__height)

  def get_target(self):
    return self.__target  

  def get_player_list(self):
    return self.__players.copy()
  # helper methods for simplifing the code in the required methods
  def get_player_idx(self,char):
    idxs = [(rowIdx,colIdx) for rowIdx,row in enumerate(self.__board) for colIdx,column in enumerate(row) if column == char]
    return idxs
    
  def is_game_over(self):
    for player_char,player in self.__player_char.items():
      # Check if current player has acheived the target
      player_idx = self.get_player_idx(player_char)
      target = self.__target
      for y,x in player_idx:
        # Check across rows and columns if there are any matches for the palyer
        if x+self.__target < self.__width:
          check_win = set(self.__board[y][x:x+target]) == set(player_char)
          if check_win:
            return True 
        if y+self.__target < self.__height:
    # zip(*self.__board) iterates along columns
    # so mapping to list gives us transposed version of board
          transpose_board = list(map(list, zip(*self.__board)))
          check_win = set(transpose_board[x][y:y+target]) == set(player_char) 
          if check_win:
            return True
        if x-self.__target>=0:
          check_win = set(self.__board[y][x:x-target]) == set(player_char)
          if check_win:
            return True 
        if y-self.__target >= 0:
          transpose_board = list(map(list, zip(*self.__board)))
          check_win = set(transpose_board[x][y:y-target]) == set(player_char) 
          if check_win:
            return True
      # check along diagnols
        diag_steps = [[(1,1),(-1,-1)],[(-1,1),(1,-1)]]
        for diagnol in diag_steps:
          current_x = x
          current_y = y
          seen = []
          for step_x,step_y in diagnol:
            diag_seen = []
            while current_x>=0 and current_x<self.__width and current_y>=0 and current_y<self.__height and self.__board[current_y][current_x] == player_char:
              if self.__board[current_y][current_x] == player_char:
                diag_seen.append(self.__board[current_y][current_x])
                current_x+=step_x
                current_y+=step_y
              else:
                  break
            seen=diag_seen+seen

          if all(set(seen[i:i+target]) == set(player_char ) for i in range(len(seen)-target)) and len(seen) >= target:
            # print("From here")
            return True
    # check is board is full
    return self.is_board_full()

  def get_winner(self):
    for player_char,player in self.__player_char.items():
      # Check if current player has acheived the target
      player_idx = self.get_player_idx(player_char)
      target = self.__target
      for y,x in player_idx:
        # Check across rows and columns if there are any matches for the palyer
        if x+self.__target < self.__width:
          check_win = set(self.__board[y][x:x+target]) == set(player_char)
          if check_win:
            return player
        if y+self.__target < self.__height:
          transpose_board = list(map(list, zip(*self.__board)))
          check_win = set(transpose_board[x][y:y+target]) == set(player_char) 
          if check_win:
            return player
        if x-self.__target>=0:
          check_win = set(self.__board[y][x:x-target]) == set(player_char)
          if check_win:
            return player 
        if y-self.__target >= 0:
          transpose_board = list(map(list, zip(*self.__board)))
          check_win = set(transpose_board[x][y:y-target]) == set(player_char) 
          if check_win:
            return player
      # check across diagnols 
        diag_steps = [[(1,1),(-1,-1)],[(-1,1),(1,-1)]]
        for diagnol in diag_steps:
          current_x = x
          current_y = y
          seen = []
          for step_x,step_y in diagnol:
            diag_seen = []
            while current_x>=0 and current_x<self.__width and current_y>=0 and current_y<self.__height and self.__board[current_y][current_x] == player_char:
              diag_seen.append(self.__board[current_y][current_x])
              current_x+=step_x
              current_y+=step_y
            seen=diag_seen+seen

          if all(seen[i:i+target] == player_char for i in range(len(seen)-target)):
            return player
    # return None in case of no winner
    return None
  # Check board is full
  def is_board_full(self):
    return not any(column == "." for row in self.__board for column in row)
  # Check column is full
  def is_column_full(self,col):
    # *self.__board iterates along columns
    # so mapping to list gives us transposed version of board
    transposed_board = list(map(list, zip(*self.__board)))
    return all(value!="." for value in transposed_board[col])
  # Get the current cell player character
  def get_cell(self, x,y):
    return self.__player_char[self.__board[y][x]] if self.__board[y][x] != "." else None
  # return the current player index
  def get_cur_player(self):
    if not self.is_game_over() :
      return self.__players[self.__current_player_idx]
  
  def move(self,col):
    # check column is full
    if not self.is_column_full(col):
      # Get the current player
      player_char = self.get_cur_player()[0]
      transposed_board = list(map(list, zip(*self.__board)))
      # Place the player char as per the move
      col_data = reversed(transposed_board[col])
      for idx,col_value in enumerate(col_data):
        if col_value == ".":
        #   print(idx)
          self.__board[self.__height-idx-1][col] = player_char
          self.__current_player_idx = ((self.__current_player_idx+1)%len(self.get_player_list()))
          return True    
    return False
# Print the board as stated in requirements
  def print(self):
    for row in self.__board:
      for column in row:
        print(column,end="")
      print("")