from .board import Board from .tile import Tile from .point import Point from .tile_type import TileType from .harbor import Harbor, HarborType import math import random # The default, tileagonal board filled with random tiles and tokens class DefaultBoard(Board): def __init__(self, game): super(DefaultBoard, self).__init__(game) # Set tiles tile_deck = Board.get_shuffled_tile_deck() token_deck = Board.get_shuffled_tile_nums() temp_tiles = [] for r in range(5): temp_tiles.append([]) for i in range([3, 4, 5, 4, 3][r]): # Add a tile new_tile = Tile(type=tile_deck.pop(), token_num=None, position=[r, i], points=[]) temp_tiles[-1].append(new_tile) # Remove the token if it is the desert if new_tile.type == TileType.Desert: self.robber = [r, i] else: new_tile.token_num = token_deck.pop() self.tiles = tuple(map(lambda x: tuple(x), temp_tiles)) # Add points temp_points = [] for r in range(6): temp_points.append([]) for i in range([7, 9, 11, 11, 9, 7][r]): point = Point(tiles=[], position=[r, i]) temp_points[-1].append(point) # Set point/tile relations for pos in DefaultBoard.get_tile_indexes_for_point(r, i): point.tiles.append(self.tiles[pos[0]][pos[1]]) self.tiles[pos[0]][pos[1]].points.append(point) self.points = tuple(map(lambda x: tuple(x), temp_points)) # Set the connected points for each point # Must be done after initializing each point so that the point object exists for r in self.points: for p in r: p.connected_points = self.get_connected_points(p.position[0], p.position[1]) # adds a harbor for each points in the pattern 2 3 2 2 3 2 etc outside_points = DefaultBoard.get_outside_points() # the pattern of spaces between harbors pattern = [1, 2, 1] # the current index of pattern index = 0 # the different types of harbors harbor_types = [ HarborType.Wood, HarborType.Brick, HarborType.Ore, HarborType.Wheat, HarborType.Sheep, HarborType.Any, HarborType.Any, HarborType.Any, HarborType.Any ] # Shuffles the harbors random.shuffle(harbor_types) # Run loop until harbor_types is empty while harbor_types: # Create a new harbor p_one = outside_points.pop() p_two = outside_points.pop() harbor = Harbor( point_one = self.points[p_one[0]][p_one[1]], point_two = self.points[p_two[0]][p_two[1]], type = harbor_types.pop()) # Add it to harbors self.harbors.append(harbor) # Remove the unused points from outside_points for _ in range(pattern[index % len(pattern)]): outside_points.pop() # Use next pattern value for number of points inbetween next time index += 1 # puts the robber on the desert tile to start for r in range(len(temp_tiles)): # checks if this row has the desert if temp_tiles[r].count(TileType.Desert) > 0: # places the robber self.robber = [r, temp_tiles[r].index(TileType.Desert)] # Returns the indexes of the tiles connected to a certain points # on the default, tileagonal Catan board @staticmethod def get_tile_indexes_for_point(r, i): # the indexes of the tiles tile_indexes = [] # Points on a tileagonal board points = [ [None] * 7, [None] * 9, [None] * 11, [None] * 11, [None] * 9, [None] * 7 ] # gets the adjacent tiles differently depending on whether the point is in the top or the bottom if r < len(points) / 2: # gets the tiles below the point ------------------ # adds the tiles to the right if i < len(points[r]) - 1: tile_indexes.append([r, math.floor(i / 2)]) # if the index is even, the number is between two tiles if i % 2 == 0 and i > 0: tile_indexes.append([r, math.floor(i / 2) - 1]) # gets the tiles above the point ------------------ if r > 0: # gets the tile to the right if i > 0 and i < len(points[r]) - 2: tile_indexes.append([r - 1, math.floor((i - 1) / 2)]) # gets the tile to the left if i % 2 == 1 and i < len(points[r]) - 1 and i > 1: tile_indexes.append([r - 1, math.floor((i - 1) / 2) - 1]) else: # adds the below ------------- if r < len(points) - 1: # gets the tile to the right or directly below if i < len(points[r]) - 2 and i > 0: tile_indexes.append([r, math.floor((i - 1) / 2)]) # gets the tile to the left if i % 2 == 1 and i > 1 and i < len(points[r]): tile_indexes.append([r, math.floor((i - 1) / 2 - 1)]) # gets the tiles above ------------ # gets the tile above and to the right or directly above if i < len(points[r]) - 1: tile_indexes.append([r - 1, math.floor(i / 2)]) # gets the tile to the left if i > 1 and i % 2 == 0: tile_indexes.append([r - 1, math.floor((i - 1) / 2)]) return tile_indexes # gets the points that are connected to the point given def get_connected_points(self, r, i): to_return = [] # Get the point to the left and the right if i > 0: to_return.append(self.points[r][i - 1]) if i < len(self.points[r]) - 1: to_return.append(self.points[r][i + 1]) # Get the point above and below # First, if the point is in the center two rows, the connected point # is either directly above/below this point if r == 2 and i % 2 == 0: to_return.append(self.points[r + 1][i]) elif r == 3 and i % 2 == 0: to_return.append(self.points[r - 1][i]) # If the point is not in the 2 center rows, the point will have an offset elif r < len(self.points) / 2: if i % 2 == 0: to_return.append(self.points[r + 1][i + 1]) elif r > 0 and i > 0: to_return.append(self.points[r - 1][i - 1]) else: if i % 2 == 0: to_return.append(self.points[r - 1][i + 1]) elif r < len(self.points) - 1 and i > 0: to_return.append(self.points[r + 1][i - 1]) return to_return # Get the points along the outside of the board, in clockwise order @staticmethod def get_outside_points(): # The lengths of each row of points on the board row_lengths = [ 7, 9, 11, 11, 9, 7 ] # The points on the bottom bottom = list(map(lambda x: [len(row_lengths) - 1, x], range(row_lengths[-1]))) # The points on the top top = list(map(lambda x: [0, x], range(row_lengths[0]))) # adds all the points on the right and left right = [] left = [] for r in range(1, len(row_lengths) - 1): # Get the last two and first two points on this row last_two = list(map(lambda x: [r, x], range(row_lengths[r])[-2:])) first_two = list(map(lambda x: [r, x], reversed(range(2)))) # If the points are one the bottom half of the board, reverse them if r > (len(row_lengths) - 1) / 2: last_two = list(reversed(last_two)) first_two = list(reversed(first_two)) # Add points to right and left right.extend(last_two) left.extend(first_two) # Put different sides of points in order # bottom and left are reversed since we want to count those points in reverse order # to make sure we go in clockwise order outside_points = [] outside_points.extend(top) outside_points.extend(right) outside_points.extend(reversed(bottom)) outside_points.extend(reversed(left)) # Return them return outside_points