Problema de cobra e escada oops, aplicativo
Estou aprendendo e tentando implementar as melhores práticas para jogos de cobra e escada.
Regras do jogo
- O tabuleiro terá 100 células numeradas de 1 a 100.
- O jogo terá um dado de seis lados numerado de 1 a 6 e sempre dará um número aleatório ao rolar.
- Cada jogador tem uma peça que inicialmente é mantida fora do tabuleiro (ou seja, na posição 0).
- Cada jogador lança os dados quando chega sua vez. Com base no valor do dado, o jogador move sua peça para frente naquele número de células. Ex: Se o valor do dado for 5 e a peça estiver na posição 21, o jogador colocará sua peça na posição 26 agora (21 + 5).
- Um jogador ganha se atingir exatamente a posição 100 e o jogo terminar aí.
- Após o lançamento dos dados, se uma peça deve se mover para fora da posição 100, ela não se move.
- O tabuleiro também contém algumas cobras e escadas. Cada cobra terá sua cabeça em algum número e sua cauda em um número menor. Sempre que uma peça acabar em uma posição com a cabeça da cobra, a peça deve descer para a posição da cauda dessa cobra.
- Cada escada terá sua posição inicial em algum número e a posição final em um número maior. Sempre que uma peça acabar em uma posição com o início da escada, a peça deve subir até a posição do final dessa escada.
- Pode haver outra cobra / escada na cauda da cobra ou na posição final da escada e a peça deve subir / descer de acordo.
Suposições
- Não haverá uma cobra em 100.
- Não haverá várias cobras / escadas no mesmo ponto inicial / inicial.
- É possível chegar a 100, ou seja, é possível ganhar o jogo.
- Snakes and Ladders não formam um loop infinito.
class Snake:
def __init__(self, start, end):
self.start = start
self.end = end
class Ladder:
def __init__(self, start, end):
self.start = start
self.end = end
class Board:
def __init__(self, size = 100):
self.size = size
self.snake_list = []
self.ladder_list = []
def add_snake(self, snake):
self.snake_list.append(snake)
def add_ladder(self, ladder):
self.snake_list.append(ladder)
class Dice:
dice_count = 1
@staticmethod
def roll():
return random.randint(1 * Dice.dice_count, 6 * Dice.dice_count)
class Player:
def __init__(self, name):
self.name = name
class PlayerPosition:
def __init__(self, player, position):
self.player = player
self.position = position
def update_position(self, new_position):
self.position = new_position
class Game:
def __init__(self, board):
self.board = board
self.players_position = []
def add_players(self, player, position=0):
player_position = PlayerPosition(player, position)
self.players_position.append(player_position)
def check_win_condition(self, position):
if position == self.board.size:
return True
return False
def check_for_snake(self, new_position):
for snake in self.board.snake_list:
start, end = snake.start, snake.end
if start == new_position:
return end
def check_for_ladder(self, new_position):
for ladder in self.board.ladder_list:
start, end = ladder.start, ladder.end
if start == new_position:
return end
def find_new_position(self, new_position):
if self.check_for_snake(new_position):
return self.check_for_snake(new_position)
elif self.check_for_ladder(new_position):
return self.check_for_ladder(new_position)
else:
return new_position
def start(self):
still_playing = len(self.players_position)
while(still_playing):
for player_position in self.players_position:
dice_value = Dice.roll()
current_position = player_position.position
new_position = current_position + dice_value
if new_position < self.board.size:
new_position = self.find_new_position(new_position)
player_position.update_position(new_position)
print(player_position.player.name, 'moved from', current_position, 'to', new_position)
if self.check_win_condition(new_position):
print("player", player_position.player.name, "wins!")
player_position.update_position(new_position + 1)
still_playing -= 1
class GameRunner:
@classmethod
def run_game(cls):
board = Board()
s1 = Snake(62, 5)
s2 = Snake(33, 6)
s3 = Snake(49, 9)
s4 = Snake(56, 53)
s5 = Snake(98, 64)
s6 = Snake(88, 16)
s7 = Snake(93, 73)
s8 = Snake(95, 75)
l1 = Ladder(2,37)
l2 = Ladder(27, 46)
l3 = Ladder(10, 32)
l4 = Ladder(51, 68)
l5 = Ladder(61, 79)
l6 = Ladder(65, 84)
l7 = Ladder(71, 91)
l8 = Ladder(81, 100)
board = Board()
board.add_ladder(l1)
board.add_ladder(l2)
board.add_ladder(l3)
board.add_ladder(l4)
board.add_ladder(l5)
board.add_ladder(l6)
board.add_ladder(l7)
board.add_ladder(l8)
board.add_snake(s1)
board.add_snake(s2)
board.add_snake(s3)
board.add_snake(s4)
board.add_snake(s5)
board.add_snake(s6)
board.add_snake(s7)
board.add_snake(s8)
player1 = Player("python")
player2 = Player("java")
player3 = Player("go")
game = Game(board)
game.add_players(player1)
game.add_players(player2)
game.add_players(player3)
game.start()
GameRunner.run_game()
Por favor, sugira locais de melhorias e correções sobre isso.
Respostas
Aulas desnecessárias
As classes cobra, escada e dados não são úteis. Eles podem ser simplesmente substituídos por um namedtuple ou uma classe de dados.
Da mesma forma, jogador e posição do jogador devem ser um único elemento de classe. Um objeto jogador deve ser responsável por manter o controle de sua posição.
Verbosidade
s1, s2, ... s8 e similarmente l1, l2, ... l8 não são realmente usados. Mantenha uma tupla de posições e itere sobre elas, chamando uma delas add_ladderou de add_snakeacordo.
Controle de fluxo
As atualizações de posição devem acontecer no final do jogador, e não no jogo. A instrução de impressão para quando a posição do jogador é atualizada aconteceria dentro da classe do jogador. O objetivo do jogo é apenas controlar e validar movimentos.
Não há declarações mostrando quando um jogador encontra uma escada ou uma cobra. apenas suas mudanças de posição naquela malha de declaração de impressão detalhada.
Execução dupla
if self.check_for_snake(new_position):
return self.check_for_snake(new_position)
elif self.check_for_ladder(new_position):
return self.check_for_ladder(new_position)
else:
return new_position
Você tem a mesma função sendo chamada duas vezes. Para um grande conjunto de células do tabuleiro, não há cobra nem escada. Ainda assim, você continua chamando ambas as funções.
Alternativas
Rolar os dados
sum(random.choices(range(1, 7), k=dice_count))
Condição de vitória
def check_win_condition(self, position):
return position == self.board.size
Verificação da cabeça da cobra ou da base da escada
Mantenha uma conta usando um setou tuplepara as cobras e escada do tabuleiro sendo adicionadas. A placa deve validar se uma posição tem cabeça de cobra ou base de escada ali. Você está atualmente iterando sobre todas as cobras e escadas (duas vezes, conforme mencionado acima) para cada posição, enquanto uma pesquisa seria \$ O(1) \$.