Schlangen- und Leiterproblem oops Anwendung
Ich lerne und versuche, die besten Praktiken für Schlangen- und Leiterspiele umzusetzen.
Spielregeln
- Die Karte hat 100 Zellen, die von 1 bis 100 nummeriert sind.
- Das Spiel hat sechsseitige Würfel von 1 bis 6 und gibt beim Würfeln immer eine Zufallszahl.
- Jeder Spieler hat eine Figur, die anfänglich außerhalb des Bretts gehalten wird (dh auf Position 0).
- Jeder Spieler würfelt, wenn er an der Reihe ist. Basierend auf dem Würfelwert bewegt der Spieler seine Figur um diese Anzahl von Zellen vorwärts. Beispiel: Wenn der Würfelwert 5 ist und sich die Figur auf Position 21 befindet, legt der Spieler seine Figur jetzt auf Position 26 (21 + 5).
- Ein Spieler gewinnt, wenn er genau die Position 100 erreicht und das Spiel dort endet.
- Wenn sich ein Stück nach dem Würfelwurf außerhalb der Position 100 bewegen soll, bewegt es sich nicht.
- Das Brett enthält auch einige Schlangen und Leitern. Jede Schlange hat ihren Kopf bei einer bestimmten Anzahl und ihren Schwanz bei einer kleineren Anzahl. Immer wenn ein Stück an einer Position mit dem Kopf der Schlange landet, sollte das Stück in die Position des Schwanzes dieser Schlange abfallen.
- Jede Leiter hat ihre Startposition bei einer bestimmten Nummer und ihre Endposition bei einer größeren Nummer. Immer wenn ein Stück an einer Position mit dem Anfang der Leiter landet, sollte das Stück bis zur Position des Endes dieser Leiter gehen.
- Es könnte sich eine andere Schlange / Leiter am Schwanz der Schlange oder an der Endposition der Leiter befinden und das Stück sollte entsprechend auf / ab gehen.
Annahmen
- Bei 100 wird es keine Schlange geben.
- Es werden nicht mehrere Schlangen / Leitern am selben Start- / Kopfpunkt sein.
- Es ist möglich, 100 zu erreichen, dh es ist möglich, das Spiel zu gewinnen.
- Schlangen und Leitern bilden keine Endlosschleife.
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()
Bitte schlagen Sie hier Verbesserungen und Korrekturen vor.
Antworten
Unnötige Klassen
Die Schlangen-, Leiter- und Würfelklassen sind überhaupt nicht nützlich. Sie können einfach durch ein Namedtuple oder eine Datenklasse ersetzt werden.
Ebenso sollten Spieler und Spielerposition ein einzelnes Klassenelement sein. Ein Spielerobjekt sollte dafür verantwortlich sein, seine Position zu verfolgen.
Ausführlichkeit
s1, s2, ... s8 und ähnliche l1, l2, ... l8 werden nicht wirklich verwendet. Behalten Sie ein Tupel von Positionen bei und wiederholen Sie diese, indem Sie entweder add_ladderoder add_snakeentsprechend aufrufen .
Kontrollfluss
Die Positionsaktualisierungen sollten am Ende des Spielers und nicht im Spiel erfolgen. Die Druckanweisung für die Aktualisierung der Spielerposition erfolgt innerhalb der Spielerklasse. Das Ziel des Spiels ist nur die Steuerung und Validierung von Zügen.
Es gibt keine Aussagen darüber, wann ein Spieler auf eine Leiter oder eine Schlange trifft. Nur ihre Position ändert sich in diesem ausführlichen Druckanweisungsnetz.
Doppelte Ausführung
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
Sie haben dieselbe Funktion, die zweimal, zweimal aufgerufen wird. Für einen größeren Satz der Brettzellen gibt es weder eine Schlange noch eine Leiter. Sie rufen jedoch weiterhin beide Funktionen auf.
Alternativen
Würfelwurf
sum(random.choices(range(1, 7), k=dice_count))
Gewinnbedingung
def check_win_condition(self, position):
return position == self.board.size
Schlangenkopf- oder Leiterbasisprüfung
Führen Sie ein Konto mit einem setoder tuplefür das Hinzufügen von Schlangen und Leitern. Das Board sollte überprüfen, ob eine Position dort entweder den Kopf einer Schlange oder die Basis einer Leiter hat. Sie durchlaufen derzeit alle Schlangen und Leitern (zweimal, wie oben erwähnt) für jede Position, während eine Suche \ wäre$ O(1) \$.