class Game: def __init__(self): self.finish_marking_character = "-" self.rules = {} # board setting self.max_number_of_players = 2 # maximum number of players playing self.distance_between_starts = 10 # distance between start tiles self.max_tiles = 20 # game variables self.players = [] self.dice = Dice() self.player_index = 0 self.playing = True self.repeating = False # repeating game with the same settings self.current_fig = None self.current_player = Player(0) def main(self): self.game_presetting() self.game_loop() # ending game settings.translate_slow_print("game_ended") return self.results() # game preparation def game_presetting(self): if not self.repeating: self.getting_variables_from_preparation() self.setting_variables_from_preparation() settings.translate_slow_print("character_means_home", (self.finish_marking_character, ), no_record=self.rules["no_record"]) self.presetting_players_and_figures() return def getting_variables_from_preparation(self): self.max_number_of_players, self.distance_between_starts, self.players, self.rules, \ self.dice = Preparation().main() def setting_variables_from_preparation(self): self.max_tiles = self.max_number_of_players * self.distance_between_starts if self.rules["rnd_tcs"]: self.random_ai_tactics_choosing() def random_ai_tactics_choosing(self): for player in self.players: player.tactic = choice(tactics) return def presetting_players_and_figures(self): for player in self.players: if player.playing: for figure in player.figures: figure.start.position = figure.start.position * self.distance_between_starts + 1 if player.figures[0].start.position > self.max_tiles: player.playing = False # main game def game_loop(self): while self.playing: self.choosing_playing_player() self.choosing_number_of_rolls() self.game_status() self.finding_if_player_should_move_again() sleep(settings.turn_pause) def choosing_playing_player(self): self.changing_player_index() self.current_player = self.players[self.player_index] # skipping inactive players if not self.current_player.playing: return self.choosing_playing_player() if not self.rules["no_record"]: self.outputting_choosing_playing_player_message() return def changing_player_index(self): if (self.dice.dice_roll < self.dice.min_deploy_roll or not self.current_player.playing) and \ (self.players[0].turns != 0 or not self.players[0].playing): self.player_index += 1 self.checking_for_player_index_overflowing() def checking_for_player_index_overflowing(self): if self.player_index == len(self.players): self.player_index = 0 def outputting_choosing_playing_player_message(self): print("========================================") settings.translate_slow_print("player_is_playing", (self.current_player.number, self.current_player.color.translation)) def choosing_number_of_rolls(self): self.dice.dice_rolling(self.current_player) # player has no figures in the field or in finish if self.current_player.undeployed: self.all_player_figures_home() if self.current_player.ai: return self.ai_moving() else: return self.player_moving() def all_player_figures_home(self): # player can deploy instantly if self.dice.dice_roll >= self.dice.min_deploy_roll: settings.translate_slow_print("rolled_st", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) # player has no more rolls in this turn thanks to rules elif self.rules[ "thr_rls_onl_first"] and self.current_player.has_deployed: settings.translate_slow_print("rolled_st", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) settings.translate_slow_print("no_moves", no_record=self.rules["no_record"]) # player has two more rolls else: self.player_rolling_two_more_times() def player_rolling_two_more_times(self): settings.translate_slow_print("rolled_st_more_chances", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) for j in range(0, 2): self.dice.dice_rolling(self.current_player) if self.dice.dice_roll >= self.dice.min_deploy_roll: settings.translate_slow_print( "rolled_st", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) return self.deploying_first_figure_in_three_rolls() else: settings.translate_slow_print( "rolled_st", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) return def deploying_first_figure_in_three_rolls(self): self.dice.dice_rolling(self.current_player) self.current_fig = self.current_player.figures[0] return self.figure_deploying() def player_moving(self): self.movement_string_compilation() exists_movable_figure = self.finding_if_exists_movable_figure() while exists_movable_figure: return self.player_choosing_move() # no figures can move else: return self.player_has_no_moves() def player_choosing_move(self): settings.translate_slow_print("rolled_st", (self.dice.dice_roll, )) player_option = settings.base_options( self.compiling_movement_message(), translate=False) for figure in self.current_player.figures: if player_option == str(figure.number) and figure.movable: self.current_fig = figure return self.choosing_how_should_figure_move() self.checking_if_player_changed_settings(player_option) def movement_string_compilation(self): self.finding_possible_move() for figure in self.current_player.figures: if figure.movable and not self.rules["no_record"]: self.compiling_movement_string_if_figure_movable(figure) else: figure.move_mess = "" return def finding_possible_move(self): for figure in self.current_player.figures: new_tile = self.finding_figures_new_coordinates( figure.tile.position, figure.tile.finishing) figure.movable = False if figure.tile.position == 0: self.finding_move_if_figure_at_home(figure) elif not new_tile.finish and figure.tile.finish: figure.move = "illegal" elif self.figure_blocked_checking(new_tile): figure.move = "blocked" elif not new_tile.finish and self.dice.dice_roll > self.finding_minimal_roll_to_get_to_finish( figure): figure.move = "illegal" else: self.finding_move_if_figure_in_field(figure) return def finding_move_if_figure_at_home(self, figure): if self.dice.dice_roll >= self.dice.min_deploy_roll and not self.figure_blocked_checking( figure.start): figure.movable, figure.move = True, "deploy" else: figure.move = "undeployable" def figure_blocked_checking(self, new_tile): for figure in self.current_player.figures: if figure.tile.position == new_tile.position and figure.tile.color.name == new_tile.color.name: return True return False def finding_minimal_roll_to_get_to_finish(self, figure): if figure.start.position > figure.tile.position: return figure.start.position - figure.tile.position else: return figure.start.position + self.max_tiles - figure.tile.position def finding_move_if_figure_in_field(self, figure): # player can only move if he has no figures at home due to rules if self.dice.dice_roll >= self.dice.min_deploy_roll and self.rules[ "no_mv_whl_dp"]: if self.finding_if_player_has_figures_at_home(): figure.move = "illegal" else: figure.movable, figure.move = True, "reposition" # player can normally move else: figure.movable, figure.move = True, "reposition" def finding_if_player_has_figures_at_home(self): for figure in self.current_player.figures: if figure.tile.home: return True else: return False @staticmethod def compiling_movement_string_if_figure_movable(figure): figure.move_mess = ", " if figure.move == "deploy": figure.move_mess += settings.translation("deploy") else: figure.move_mess += settings.translation("reposition") figure.move_mess += settings.translation("figure").format( figure.number) return def finding_if_exists_movable_figure(self): for figure in self.current_player.figures: if figure.movable: return True else: return False def compiling_movement_message(self): message = settings.translation("moving_figure_choosing") for figure in self.current_player.figures: if figure.movable: message += figure.move_mess return message def checking_if_player_changed_settings(self, player_option): if player_option != "skip": settings.translate_slow_print("input_error") else: self.movement_string_compilation() return def player_has_no_moves(self): if not self.current_player.undeployed: settings.translate_slow_print("rolled_st", (self.dice.dice_roll, ), no_record=self.rules["no_record"]) settings.translate_slow_print("no_moves") self.current_player.inactive_turns += 1 return def ai_moving(self): for figure in self.current_player.figures: # checking if figure can move if figure.movable: figure.weight = 1 # figure is in home if figure.tile.position == 0: figure.weight += 10 * self.current_player.tactic.deploy # figure is in finish elif figure.tile.finish: figure.weight *= 0.1 # figure is in field else: # searching for figures distance to the finish target = figure.start.position if figure.tile.position >= target: target += self.max_tiles finnish_distance = target - figure.tile.position if finnish_distance != 0: figure.weight += round( self.current_player.tactic.finnish_distance / finnish_distance * 200, 2) # looking if figure isn't blocking her start tile if figure.tile.position == figure.start.position and \ figure.tile.color.name == figure.start.color.name: figure.weight += 10 * self.current_player.tactic.clearing_start # looking if figure isn't standing on others start tiles for pl in self.players: if pl.playing and pl.number != self.current_player.number: if figure.tile.position == pl.figures[ 0].start.position: figure.weight += 12 * self.current_player.tactic.opponent_start # looking if figure can kick other figures with her move new_tile = self.finding_figures_new_coordinates( figure.tile.position, figure.tile.finishing) for player in self.players: if player.playing: for fig in player.figures: if new_tile.color.name == fig.tile.color.name and new_tile.position == fig.tile.position: figure.weight += 10 * self.current_player.tactic.kicking_out # looking if figure can be kicked if not figure.tile.finish: for pos in range(1, 7): tile_behind = self.finding_figures_new_coordinates( figure.tile.position, False, -pos) for player in self.players: if player.playing and player.number != self.current_player.number: for fig in player.figures: if fig.tile.position == tile_behind.position and \ fig.tile.color.name == tile_behind.color.name: figure.weight += pos * 5 * self.current_player.tactic.running_away if figure.weight <= 0: figure.weight = 0.01 else: figure.weight = 0 # debug # print(figure.weight) if self.current_player.figures[0].weight >= self.current_player.figures[1].weight and \ self.current_player.figures[0].weight >= self.current_player.figures[2].weight and \ self.current_player.figures[0].weight >= self.current_player.figures[3].weight: self.current_fig = self.current_player.figures[0] elif self.current_player.figures[1].weight >= self.current_player.figures[0].weight and \ self.current_player.figures[1].weight >= self.current_player.figures[2].weight and \ self.current_player.figures[1].weight >= self.current_player.figures[3].weight: self.current_fig = self.current_player.figures[1] elif self.current_player.figures[2].weight >= self.current_player.figures[0].weight and \ self.current_player.figures[2].weight >= self.current_player.figures[1].weight and \ self.current_player.figures[2].weight >= self.current_player.figures[3].weight: self.current_fig = self.current_player.figures[2] else: self.current_fig = self.current_player.figures[3] if self.current_fig.move == "deploy": self.figure_deploying() elif self.current_fig.move == "reposition": self.figure_repositioning() else: self.current_player.inactive_turns += 1 return def choosing_how_should_figure_move(self): # deploying selected figure if self.current_fig.tile.position == 0: self.figure_deploying() # repositioning selected figure else: self.figure_repositioning() def figure_deploying(self): self.current_fig.tile = self.current_fig.start settings.translate_slow_print( "deploying_figure", (self.current_fig.number, self.current_fig.start.position), no_record=self.rules["no_record"]) if not self.current_player.has_deployed: self.current_player.has_deployed = True return self.figure_kicking() def figure_repositioning(self): self.current_fig.tile = self.finding_figures_new_coordinates( self.current_fig.tile.position, self.current_fig.tile.finishing) settings.translate_slow_print( "figure_moved", (self.current_fig.number, self.current_fig.tile.position), no_record=self.rules["no_record"]) if self.current_fig.tile.finish: settings.translate_slow_print("figure_at_home", no_record=self.rules["no_record"]) return self.figure_kicking() def finding_figures_new_coordinates(self, current_position, finishing, num=0): new_position = self.finding_new_position_value(current_position, num) if current_position == 0: return self.current_player.figures[0].start elif self.current_player.figures[0].start.position <= new_position <= \ self.current_player.figures[0].start.position + len(self.current_player.figures) - 1: if finishing: return Tile(new_position, color=self.current_player.color, finish=True) elif abs(new_position % self.distance_between_starts) == len( self.current_player.figures): return Tile(new_position) else: return Tile(new_position, finishing=False) else: return Tile(new_position) def finding_new_position_value(self, current_position, num): if num == 0: num = self.dice.dice_roll new_position = current_position + num if new_position < 1 and num < 1: new_position += self.max_tiles if new_position > self.max_tiles: new_position -= self.max_tiles return new_position def figure_kicking(self): for player in self.players: if player.playing and player.color.name != self.current_player.color.name: for figure in player.figures: if figure.tile.position == self.current_fig.tile.position and \ figure.tile.color.name == self.current_fig.tile.color.name and \ figure.color.name != self.current_fig.color.name: figure.tile = figure.home settings.translate_slow_print( "figure_kicked", (figure.number, player.number, figure.color.translation), no_record=self.rules["no_record"]) player.own_figures_kicked += 1 self.current_player.others_figures_kicked += 1 def game_status(self): if not self.rules["no_record"]: print("----------------------------------------") for player in self.players: if player.playing: self.finding_player_status(player) return def finding_player_status(self, player): message = self.setting_status_message() figure_not_in_finish = False figures_on_board = False for figure in player.figures: message = self.updating_status_message(figure, message) if not figure.tile.finish and not figure_not_in_finish: figure_not_in_finish = True if figure.tile.position != 0 and not figures_on_board: figures_on_board = True if not figure_not_in_finish: return self.setting_player_placing(player) if figures_on_board: self.player_has_figures_on_board(player, message) else: self.player_has_all_figures_at_home(player) def setting_status_message(self): if not self.rules["no_record"]: message = settings.translation("figures_are_on_tiles") else: message = "" return message def updating_status_message(self, figure, message): if not self.rules["no_record"]: if figure.tile.finish is False: message += " {};".format(figure.tile.position) else: message += " {}{}{};".format(self.finish_marking_character, figure.tile.position, self.finish_marking_character) return message def setting_player_placing(self, player, last=False): player.playing = False results = [] for pl in self.players: results.append(pl.result) for i in range(1, len(self.players) + 1): if i not in results: player.result = i break if not last: return self.checking_for_last_player() return def checking_for_last_player(self): number_of_playing_players = 0 last_playing_player = None for player in self.players: if player.playing: number_of_playing_players += 1 last_playing_player = player # last player in game if number_of_playing_players == 1: self.playing = False return self.setting_player_placing(last_playing_player, True) return def player_has_figures_on_board(self, player, message): player.undeployed = False if not self.rules["no_record"]: message = message[:-1] settings.slow_print( message.format(player.number, player.color.translation)) def player_has_all_figures_at_home(self, player): player.undeployed = True if not self.rules["no_record"]: settings.translate_slow_print( "player_no_figure", (player.number, player.color.translation)) def finding_if_player_should_move_again(self): if self.dice.dice_roll < self.dice.min_deploy_roll and not self.rules[ "no_rpt_whl_six"]: self.current_player.turns += 1 # end of the game def results(self): # printing results to the player message = "" for player in self.players: if player.result != 0: avr = 0 for num in player.rolls: avr += num else: if len(player.rolls) != 0: avr /= len(player.rolls) message += settings.translation("player_placing").format( player.figures[0].color.translation, player.result) message += " - " + str(round(avr, 4)) + " " + str(player.rolls) + " " + str(player.turns) + " " + \ str(player.inactive_turns) + " " + str(player.others_figures_kicked) + " " + \ str(player.own_figures_kicked) + "\n" if player.ai: message += settings.translation("his_tactic").format( player.tactic.name, "\r\n") message += "\r\n" print(message) # saving results to results.txt in data folder file = open(Path(__file__).parent.parent / "data/results.txt", "a+") file.write(str(message)) file.close() while True: option = settings.base_options("end_message") if option == "s": return self.restarting() elif option == "r": return self.restarting(True) elif option != "skip": exit() def restarting(self, repeat=False): # resetting game variables self.playing = True self.repeating = False self.player_index = 0 # resetting player variables for player in self.players: player.playing = False if player.result != 0: if repeat: self.repeating = True player.playing = True player.turns = 0 player.rolls = [] player.result = 0 for figure in player.figures: figure.tile = figure.home figure.start.position = int((figure.start.position - 1) / self.distance_between_starts) return self.main()