Application de problème de serpent et d'échelle
J'apprends et j'essaie de mettre en œuvre les meilleures pratiques pour le jeu de serpent et d'échelle.
Règles du jeu
- La carte aura 100 cellules numérotées de 1 à 100.
- Le jeu aura un dé à six faces numéroté de 1 à 6 et donnera toujours un nombre aléatoire en le roulant.
- Chaque joueur a une pièce qui est initialement conservée à l'extérieur du plateau (c'est-à-dire à la position 0).
- Chaque joueur lance les dés à son tour. En fonction de la valeur des dés, le joueur avance sa pièce de ce nombre de cellules. Ex: Si la valeur des dés est de 5 et que la pièce est à la position 21, le joueur mettra sa pièce à la position 26 maintenant (21 + 5).
- Un joueur gagne s'il atteint exactement la position 100 et que le jeu se termine là.
- Après le jet de dés, si une pièce est censée se déplacer hors de la position 100, elle ne bouge pas.
- Le plateau contient également des serpents et des échelles. Chaque serpent aura sa tête à un certain nombre et sa queue à un plus petit nombre. Chaque fois qu'une pièce se retrouve à une position avec la tête du serpent, la pièce doit descendre à la position de la queue de ce serpent.
- Chaque échelle aura sa position de départ à un certain nombre et sa position finale à un plus grand nombre. Chaque fois qu'une pièce se termine à une position avec le début de l'échelle, la pièce doit monter à la position de l'extrémité de cette échelle.
- Il pourrait y avoir un autre serpent / échelle à la queue du serpent ou à la position finale de l'échelle et la pièce devrait monter / descendre en conséquence.
Hypothèses
- Il n'y aura pas de serpent à 100 ans.
- Il n'y aura pas plusieurs serpents / échelles au même point de départ / tête.
- Il est possible d'atteindre 100, c'est-à-dire qu'il est possible de gagner la partie.
- Les serpents et les échelles ne forment pas une boucle infinie.
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()
Veuillez suggérer des améliorations et des corrections à ce sujet.
Réponses
Cours inutiles
Les classes serpent, échelle et dés ne sont pas du tout utiles. Ils peuvent simplement être remplacés par un namedtuple ou une dataclass.
De même, le joueur et la position du joueur doivent tous deux être un élément de classe unique. Un objet joueur doit être responsable du suivi de sa position.
Verbosité
s1, s2, ... s8 et similaires l1, l2, ... l8 ne sont pas vraiment utilisés. Conservez un tuple de positions et parcourez-les en appelant l'une add_ladderou l' autre ou en add_snakeconséquence.
Contrôle du flux
Les mises à jour de position doivent avoir lieu à la fin du joueur et non à la partie. L'instruction d'impression pour la mise à jour de la position du joueur se produirait dans la classe du joueur. Le but du jeu est uniquement de contrôler et de valider les coups.
Il n'y a aucune déclaration montrant quand un joueur rencontre une échelle ou un serpent. juste leur position change dans ce maillage détaillé de déclaration d'impression.
Double exécution
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
Vous avez la même fonction appelée deux fois, deux fois. Pour un ensemble majeur de cellules du tableau, il n'y a ni serpent, ni échelle. Pourtant, vous continuez d'appeler les deux fonctions.
Alternatives
Lancer de dés
sum(random.choices(range(1, 7), k=dice_count))
Condition de victoire
def check_win_condition(self, position):
return position == self.board.size
Vérification de la tête de serpent ou de la base de l'échelle
Gardez un compte en utilisant un setou tuplepour les serpents du tableau et l'échelle ajoutée. Le conseil doit valider si une position a soit une tête de serpent, soit une base d'échelle. Vous itérez actuellement sur tous les serpents et échelles (deux fois, comme mentionné ci-dessus) pour chaque position, alors qu'une recherche serait \$ O(1) \$.