예제 #1
0
class SackAllTestCase(unittest.TestCase):
    """Comprehensive tests of (non-empty) Sack."""

    def setUp(self):
        """Set up an empty Sack."""
        self.Sack = Sack()

    def tearDown(self):
        """Clean up."""
        self.Sack = None

    def testAll(self):
        """Test adding and removeping multiple elements."""
        number_set = set(range(20))

        for item in number_set:
            self.Sack.add(item)
            assert not self.Sack.is_empty(), \
                'is_empty() returned True on a non-empty Sack!'

        while not self.Sack.is_empty():
            element = self.Sack.remove()
            assert element in number_set, \
                'Something wrong on top of the Sack!'
            number_set -= {element}
예제 #2
0
    def static_init(cls):
        cls.filenames = [
            "trios.txt", "quads.txt", "fives.txt", "sixes.txt", "sevens.txt",
            "eights.txt"
        ]
        cls.directory = "text_files/"
        cls.dictionary = prepare_data(words_reader('words.txt'))

        if not os.path.isdir(cls.directory):
            os.mkdir(cls.directory)

        cls.letters = set(Sack.values_without_blank())
        cls.vowels = {'a', 'e', 'i', 'o', 'u', 'y', 'ó', 'ą', 'ę'}
        cls.consonants = {
            letter
            for letter in cls.letters if letter not in cls.vowels
        }
        cls.invalid_letters = {'q', 'x', 'v'}

        cls.trios = cls.load_groups(3)
        cls.quads = cls.load_groups(4)
        cls.fives = cls.load_groups(5)
        cls.sixes = cls.load_groups(6)
        cls.sevens = cls.load_groups(7)
        cls.eights = cls.load_groups(8)

        cls.groups = [
            cls.trios, cls.quads, cls.fives, cls.sixes, cls.sevens, cls.eights
        ]
예제 #3
0
파일: ai.py 프로젝트: Kacpri/Scrabble
    def __init__(self, tiles_from_player: Dict[Coords, Tile],
                 sack: Sack) -> None:
        super().__init__()
        self.tiles_from_player = tiles_from_player
        self.sack = sack
        self.letters_remaining = Sack.get_all_letters()
        self.tiles_on_board = {}
        self.new_tiles = []

        self.word = None
        self.words_by_points = {}
        self.rack = self.sack.draw()

        for letter in self.rack:
            self.letters_remaining.remove(letter)

        self.horizontal_neighbours = {}
        self.vertical_neighbours = {}
        self.neighbours = {
            UP: self.horizontal_neighbours,
            DOWN: self.horizontal_neighbours,
            LEFT: self.vertical_neighbours,
            RIGHT: self.vertical_neighbours
        }

        self.neighbourhoods = {}
        for direction in DIRECTIONS:
            self.neighbourhoods[direction] = {}

        self.turn_processes = []
        self.no_turn_processes = []

        self.is_turn = False
        self.current_turn = 0
예제 #4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--folder_with_files",
                        type=str,
                        default="../data/rozszerzone/v1/train/",
                        help="path to folder with images and labels")
    parser.add_argument("--out_file",
                        type=str,
                        default="out.txt",
                        help="file with paths selected by the program")
    parser.add_argument("--n_images",
                        type=int,
                        default=10,
                        help="quantity of images to select")
    parser.add_argument("--class_id",
                        type=int,
                        default=3,
                        help="class id to search images for")
    parser.add_argument("--n_classes",
                        type=int,
                        default=14,
                        help="quantity of classes in dataset")
    parser.add_argument("--out_folder_with_selected_images",
                        type=str,
                        default="out",
                        help="file with paths selected by the program")

    opt = parser.parse_args()
    print(opt)

    mypath = opt.folder_with_files
    if mypath[-1] != "/":
        mypath.append('/')

    # all images
    imageDataList = getValidImageDatas(mypath)
    sack = Sack(imageDataList)

    # filter images for only opt.class_id
    #selected_type = sack.getOnlyLabeled(opt.class_id) # max 573 for stop sign
    selected_type = sack.getLabeled(opt.class_id)  # max 1215 for stop sign
    # order images to the biggest images of element
    selected_type.sort(reverse=True,
                       key=lambda imageData: imageData.getMaxSize())
    print("n = ", len(selected_type))

    topN = selected_type[0:opt.n_images]
    s1 = Sack(topN)

    s1.copyImagesToFolder(opt.out_folder_with_selected_images)
    s1.saveToFile(opt.out_file, True)
예제 #5
0
 def blank_entered(self):
     tile = self._blanks[-1]
     new_letter = self.text_field.text()
     if new_letter.lower() in Sack.values_without_blank():
         tile.change_to_blank(new_letter)
         self.stop_waiting_for_blank()
         self.end_turn()
     else:
         self.add_info('Podaj poprawną literę')
         self.text_field.clear()
         return
예제 #6
0
    def player_ends(self):
        self.player_clock.stop()
        points = 0
        letters = ' '
        for letter in self.ai.rack:
            points += Sack.get_value(letter)
            letters += f'{letter}, '

        self.score.add_points('AI', f'(Zostały {letters[:-2]})', -points)
        self.score.add_points('Gracz', '', points)
        self.end_game()
예제 #7
0
class SackEmptyTestCase(unittest.TestCase):
    """Test behaviour of an empty Sack."""

    def setUp(self):
        """Set up an empty Sack."""
        self.Sack = Sack()

    def tearDown(self):
        """Clean up."""
        self.Sack = None

    def testIsEmpty(self):
        """Test is_empty() on empty Sack."""
        # it's hard to avoid \ continuation here.
        assert self.Sack.is_empty(), \
            'is_empty returned False on an empty Sack!'

    def testadd(self):
        """Test add to empty Sack."""

        self.Sack.add("foo")
        assert self.Sack.remove() == "foo", \
            'Wrong item on top of the Sack! Expected "foo" here.'
예제 #8
0
    def add_letter(self,
                   letter: str,
                   coords: Coords,
                   extra_points: Optional[int] = 0,
                   is_from_rack: Optional[bool] = False,
                   is_blank: Optional[bool] = False):
        if not self._start:
            self._start = coords
            self._end = coords
            self._word = letter

        elif coords < self._start:
            self._start = coords
            self._word = letter + self._word
            self.check_beginning()
        else:
            self._end = coords
            self._word = self._word + letter
            self.check_end()

        if not self.is_valid:
            return

        letter_points = Sack.get_value(letter) if not is_blank else 0

        if is_from_rack:
            self._added_letters[coords] = letter, letter_points
            self._rack.remove(letter if letter_points else BLANK)

            if coords in double_letter_bonuses:
                letter_points *= 2
            elif coords in triple_letter_bonuses:
                letter_points *= 3
            elif coords in double_word_bonuses:
                self._multiplier *= 2
            elif coords in triple_word_bonuses:
                self._multiplier *= 3

        if extra_points:
            extra_points += letter_points
            if coords in double_word_bonuses:
                extra_points *= 2
            elif coords in triple_word_bonuses:
                extra_points *= 3
            self._bonus += extra_points

        self._points += letter_points

        if len(self._added_letters) == MAX_RACK_SIZE:
            self._bonus += 50
예제 #9
0
    def add_letters_to_rack(self, letters=None):
        if not letters:
            letters = self.sack.draw(MAX_RACK_SIZE - len(self._tiles_in_rack) - len(self._tiles_to_exchange))

        for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1):
            if not letters:
                return
            coords = Coords(column, RACK_ROW)
            if not self.get_tile(coords) and len(self._tiles_in_rack) + len(self._tiles_to_exchange) < MAX_RACK_SIZE:
                letter = letters.pop()

                coords = Coords(column, RACK_ROW)
                points = Sack.get_value(letter)
                tile = Tile(letter, points, coords, self.scale, self.on_tile_move, self.move_to_rack)
                self.scene.addItem(tile)
                self._tiles_in_rack.add(coords)
                self._tiles[coords] = tile
예제 #10
0
 def prepare_game(self):
     self.sack = Sack(self.sack_counter)
     self.ai = AI(self.tiles_for_ai, self.sack)
예제 #11
0
class Board(QGraphicsView):
    def __init__(self, score, player_clock, ai_clock, add_comment, text_field, set_prompt, confirm_button,
                 disable_buttons, sack_counter):
        QGraphicsView.__init__(self)

        self.scale = 1

        self._board_squares = {}
        self._other_squares = {}
        self._bonus_fields = []
        self._labels = {}

        self.scene = QGraphicsScene()
        self.build_board_scene()
        self.prepare_board()
        self.setScene(self.scene)

        self.player_clock = player_clock
        self.ai_clock = ai_clock
        self.add_info = add_comment
        self.set_prompt = set_prompt
        self.disable_buttons = disable_buttons
        self.confirm_button = confirm_button
        self.text_field = text_field

        self.is_game_started = False

        # parameters visible for AI
        self.tiles_for_ai = {}
        # sack represents sack
        self.sack = None

        self.sack_counter = sack_counter
        # score represents total score of both players
        self.score = score
        # tiles represent all tiles on board
        self._tiles = {}
        # latest tiles represent tiles added in last turn
        self.new_tiles = []
        self._latest_tiles = set()
        self._tiles_in_rack = set()
        self._tiles_to_exchange = set()
        self._blanks = []
        self._points = 0
        self._words = []
        self._is_connected = False
        self.ai = None

    def auto_resize(self):
        if self.height() / self.width() < DEFAULT_HEIGHT / DEFAULT_WIDTH:
            scale = round(self.height() / DEFAULT_HEIGHT, 1)
        else:
            scale = round(self.width() / DEFAULT_WIDTH, 1)

        if abs(scale - self.scale) < 0.0001:
            return
        self.scale = scale

        self.scene.setSceneRect(-SQUARE_SIZE / 2, -SQUARE_SIZE / 2, SQUARE_SIZE * 16 * self.scale,
                                SQUARE_SIZE * 19 * self.scale)
        for tile in self._tiles.values():
            tile.resize(self.scale)
        for square in self._board_squares.values():
            square.setScale(self.scale)
        for square in self._other_squares.values():
            square.setScale(self.scale)
        for x, y in self._labels:
            label = self._labels.get((x, y))
            label.setScale(self.scale)
            label.setPos(x * self.scale, y * self.scale)

    def prepare_game(self):
        self.sack = Sack(self.sack_counter)
        self.ai = AI(self.tiles_for_ai, self.sack)

    def reset_game(self):
        self.is_game_started = False
        self.ai.stop()

        for tile in self._tiles.values():
            self.scene.removeItem(tile)

        self.tiles_for_ai.clear()
        self._tiles.clear()
        self._latest_tiles.clear()
        self._tiles_in_rack.clear()
        self._tiles_to_exchange.clear()
        self._blanks.clear()
        self._words.clear()
        self._points = 0
        self._is_connected = False
        self.prepare_game()

    def start_game(self):
        if self.is_game_started:
            self.reset_game()
        self.prepare_game()
        self.is_game_started = True
        self.ai.is_turn = bool(getrandbits(1))
        self.add_letters_to_rack()
        self.ai.finished.connect(self.end_ai_turn)
        self.ai.start()
        if self.ai.is_turn:
            self.add_info('Przeciwnik zaczyna')
            self.start_ai_turn()
        else:
            self.add_info('Zaczynasz')
            self.player_clock.start()

    def move_to_rack(self, tile):
        old_coords = tile.coords
        if old_coords in self._tiles_in_rack:
            return

        coords = Coords(LEFT_RACK_BOUND, RACK_ROW)
        while coords in self._tiles_in_rack:
            coords = coords.move(RIGHT)

        if old_coords in self._tiles_to_exchange:
            self._tiles_to_exchange.remove(old_coords)
        else:
            self._latest_tiles.remove(old_coords)

        del self._tiles[old_coords]
        self._tiles[coords] = tile
        self._tiles_in_rack.add(coords)
        tile.move_to_coords(coords)

    def collect_tiles(self):
        for coords in set.union(self._latest_tiles, self._tiles_to_exchange):
            tile = self.get_tile(coords)
            self.move_to_rack(tile)

    def skip_turn(self):
        self.collect_tiles()
        self.score.add_points('Gracz', '(Pominięcie ruchu)', 0)
        self.start_ai_turn()

    def player_ends(self):
        self.player_clock.stop()
        points = 0
        letters = ' '
        for letter in self.ai.rack:
            points += Sack.get_value(letter)
            letters += f'{letter}, '

        self.score.add_points('AI', f'(Zostały {letters[:-2]})', -points)
        self.score.add_points('Gracz', '', points)
        self.end_game()

    def ai_ends(self):
        points = 0
        letters = ' '
        for coords in self._tiles_in_rack:
            tile = self.get_tile(coords)
            points += tile.points
            letters += f'{tile.letter}, '
        for coords in self._tiles_to_exchange:
            tile = self.get_tile(coords)
            points += tile.points
            letters += f'{tile.letter}, '

        self.score.add_points('Gracz', f'(Zostały {letters[:-2]})', -points)
        self.score.add_points('AI', '', points)
        self.end_game()

    def end_game(self):
        self.disable_buttons(True)
        player_score = self.score.get_score('Gracz')
        ai_score = self.score.get_score('AI')
        if player_score > ai_score:
            self.add_info('Gratulacje! Udało Ci się pokonać algorytm!')
        elif player_score < ai_score:
            self.add_info('Tym razem się nie udało. Próbuj dalej :)')
        else:
            self.add_info('Dobry remis nie jest zły ;)')

    def add_letters_to_rack(self, letters=None):
        if not letters:
            letters = self.sack.draw(MAX_RACK_SIZE - len(self._tiles_in_rack) - len(self._tiles_to_exchange))

        for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1):
            if not letters:
                return
            coords = Coords(column, RACK_ROW)
            if not self.get_tile(coords) and len(self._tiles_in_rack) + len(self._tiles_to_exchange) < MAX_RACK_SIZE:
                letter = letters.pop()

                coords = Coords(column, RACK_ROW)
                points = Sack.get_value(letter)
                tile = Tile(letter, points, coords, self.scale, self.on_tile_move, self.move_to_rack)
                self.scene.addItem(tile)
                self._tiles_in_rack.add(coords)
                self._tiles[coords] = tile

    def exchange_letters(self):
        if self.ai.is_turn:
            self.add_info('Ruch przeciwnika')
            return

        if not self._tiles_to_exchange:
            self.add_info('Brak liter do wymiany')
            return

        letters_to_exchange = []
        for coords in self._tiles_to_exchange:
            tile = self.get_tile(coords)
            letters_to_exchange.append(tile.letter)
            del self._tiles[tile.coords]
            self.scene.removeItem(tile)

        letters_on_board = []
        for coords in self._latest_tiles:
            tile = self.get_tile(coords)
            letters_on_board.append(tile.letter)
            del self._tiles[tile.coords]
            self.scene.removeItem(tile)

        self._tiles_to_exchange.clear()
        self._latest_tiles.clear()

        new_letters = self.sack.exchange(letters_to_exchange)
        self.score.add_points('Gracz', '(wymiana liter)', 0)

        if not new_letters:
            self.add_info('Za mało płytek w worku')
            self.add_letters_to_rack(letters_to_exchange + letters_on_board)
            return

        self.add_info('Wymieniłeś/aś litery')
        self.add_letters_to_rack(new_letters + letters_on_board)

        self.start_ai_turn()

    def start_ai_turn(self):
        self.player_clock.stop()
        self.tiles_for_ai.clear()
        for coords in self._latest_tiles:
            self.tiles_for_ai[coords] = self.get_tile(coords)

        for tile in self.new_tiles:
            tile.remove_highlight()
        self.new_tiles.clear()

        self.ai.is_turn = True
        self.ai_clock.start()
        self.disable_buttons(True)

    def end_ai_turn(self):
        if not self.is_game_started:
            return

        self.ai_clock.stop()
        self.disable_buttons(False)

        word = self.ai.word
        words = [word]

        for coords in self._latest_tiles:
            tile = self.get_tile(coords)
            tile.remove_highlight()

        self._latest_tiles.clear()

        if word:
            for coords in word.added_letters:
                letter, points = word.added_letters.get(coords)
                tile = Tile(letter, points, coords, self.scale)
                tile.place()
                self._tiles[coords] = tile
                self.scene.addItem(tile)
                self.new_tiles.append(tile)
                perpendicular_word = self.find_word(coords, ~word.direction(), False)
                if perpendicular_word:
                    words.append(perpendicular_word)

            self.score.add_points('AI', words, word.sum_up())

        else:
            self.add_info(f'Komputer wymienił litery')
            self.score.add_points('AI', '(wymiana liter)', 0)

        if not self.ai.rack:
            self.ai_ends()
            return

        self.player_clock.start()

    def wait_for_blank(self, blank):
        self._blanks.append(blank)
        self.set_prompt("Jaką literą ma być blank?")
        self.text_field.setDisabled(False)
        self.confirm_button.setDisabled(False)
        self.disable_buttons(True)

    def stop_waiting_for_blank(self):
        self.set_prompt('')
        self.text_field.setDisabled(True)
        self.text_field.clear()
        self.confirm_button.setDisabled(True)
        self.disable_buttons(False)

    def revert_blanks(self):
        for blank in self._blanks:
            blank.change_back()
        self._blanks.clear()
        self.stop_waiting_for_blank()

    def blank_entered(self):
        tile = self._blanks[-1]
        new_letter = self.text_field.text()
        if new_letter.lower() in Sack.values_without_blank():
            tile.change_to_blank(new_letter)
            self.stop_waiting_for_blank()
            self.end_turn()
        else:
            self.add_info('Podaj poprawną literę')
            self.text_field.clear()
            return

    def end_turn(self):
        if self.ai.is_turn:
            self.add_info('Ruch przeciwnika')
            return

        self._is_connected = False

        if not self._latest_tiles:
            self.add_info('Musisz najpierw wykonać ruch')
            return

        if not self.get_tile(Coords.central()):
            self.add_info('Pierwszy wyraz musi przechodzić przez środek')
            return

        if Coords.central() in self._latest_tiles:
            self._is_connected = True
            if len(self._latest_tiles) == 1:
                self.add_info('Wyraz musi zawierać przynajmniej dwie litery')
                return

        first_tile_coords = min(self._latest_tiles)
        last_tile_coords = max(self._latest_tiles)

        if first_tile_coords.is_same_column(last_tile_coords):
            direction = DOWN
        else:
            direction = RIGHT

        if len(self._latest_tiles) == 1 and (self.get_tile(first_tile_coords.move(RIGHT)) or self.get_tile(
                first_tile_coords.move(RIGHT))):
            self._is_connected = True

        columns = set()
        rows = set()
        for tile in self._latest_tiles:
            columns.add(tile.x)
            rows.add(tile.y)

        if len(rows) > 1 and len(columns) > 1:
            self.add_info('Litery muszą być ułożone w jednej linii')
            return

        while self.get_tile(first_tile_coords.move(-direction)):
            first_tile_coords = first_tile_coords.move(-direction)

        while self.get_tile(last_tile_coords.move(direction)):
            last_tile_coords = last_tile_coords.move(direction)

        current_coords = first_tile_coords

        while current_coords <= last_tile_coords:
            tile = self.get_tile(current_coords)
            if not tile:
                self.add_info("Litery muszą należeć do tego samego wyrazu")
                return

            if tile.is_placed or self.get_tile(
                    current_coords.move(~direction)) or self.get_tile(
                    current_coords.move(-~direction)):
                self._is_connected = True

            if tile.letter == BLANK:
                self.wait_for_blank(tile)
                return

            current_coords = current_coords.move(direction)

        if not self._is_connected:
            self.add_info('Wyraz musi się stykać z występującymi już na planszy')
            return

        self._words.clear()
        self._points = 0

        self.find_word(first_tile_coords, direction)

        if len(columns) > 1:
            for column in columns:
                self.find_word(Coords(column, first_tile_coords.y), ~direction)

        else:
            for row in rows:
                self.find_word(Coords(first_tile_coords.x, row), ~direction)

        for word in self._words:
            if not Dictionary.is_word_in_dictionary(word):
                self.add_info(f'słowo "{word}" nie występuje w słowniku')
                if self._blanks:
                    self.revert_blanks()
                return

        for coords in self._latest_tiles:
            tile = self.get_tile(coords)
            tile.place()

        self._blanks.clear()

        if len(self._latest_tiles) == MAX_RACK_SIZE:
            self._points += 50

        self.score.add_points('Gracz', self._words, self._points)
        self.add_letters_to_rack()

        if not self._tiles_in_rack and not self._tiles_to_exchange and not self.sack.how_many_remain():
            self.player_ends()
            return

        self.start_ai_turn()

    def find_word(self, coords, direction, is_players_turn=True):
        word = ''
        word_points = 0
        word_multiplier = 1
        direction = abs(direction)

        first_tile = coords
        while self.get_tile(first_tile.move(-direction)):
            first_tile = first_tile.move(-direction)

        last_tile = coords
        while self.get_tile(last_tile.move(direction)):
            last_tile = last_tile.move(direction)

        if first_tile == last_tile:
            return

        current_tile = first_tile
        while current_tile <= last_tile:
            tile = self.get_tile(current_tile)
            points = tile.points

            if not tile.is_placed:
                if current_tile in double_letter_bonuses:
                    points *= 2
                elif current_tile in triple_letter_bonuses:
                    points *= 3
                elif current_tile in double_word_bonuses:
                    word_multiplier *= 2
                elif current_tile in triple_word_bonuses:
                    word_multiplier *= 3

            word_points += points
            word += tile.letter

            current_tile = current_tile.move(direction)

        if is_players_turn:
            self._words.append(word)
            self._points += word_points * word_multiplier
        else:
            return word

    def swap_tiles(self, tile, other_tile):
        tile.swap_with_other(other_tile)
        self._tiles[tile.coords] = tile
        self._tiles[other_tile.coords] = other_tile

    def on_tile_move(self, tile):
        if not tile.coords.is_valid():
            tile.undo_move()
            return
        if tile.coords.is_on_board() and self.ai.is_turn:
            self.add_info('Ruch przeciwnika')
            tile.undo_move()
            return

        other_tile = None
        if tile.coords in set.union(self._latest_tiles, self._tiles_in_rack, self._tiles_to_exchange):
            other_tile = self.get_tile(tile.coords)

        if other_tile:
            self.swap_tiles(tile, other_tile)

        elif self.get_tile(tile.coords):
            tile.undo_move()
            return

        else:
            del self._tiles[tile.old_coords]
            if tile.old_coords.is_in_rack():
                self._tiles_in_rack.remove(tile.old_coords)

            elif tile.old_coords.is_in_exchange_zone():
                self._tiles_to_exchange.remove(tile.old_coords)
            else:
                self._latest_tiles.remove(tile.old_coords)

            self._tiles[tile.coords] = tile
            if tile.coords.is_in_rack():
                self._tiles_in_rack.add(tile.coords)
            elif tile.coords.is_in_exchange_zone():
                self._tiles_to_exchange.add(tile.coords)
            else:
                self._latest_tiles.add(tile.coords)

    def get_tile(self, coords: Coords) -> Tile:
        return self._tiles.get(coords)

    def build_board_scene(self):
        self.build_squares()
        self.prepare_bonus_fields()
        self.build_bonus_fields()
        self.build_rack()
        self.build_exchange_zone()
        self.build_labels()

    def build_squares(self):
        brush = QBrush(LIGHT_SEA_GREEN)
        pen = QPen(DARK_SEA_GREEN, 1, Qt.SolidLine)

        for row in range(LAST_ROW + 1):
            for column in range(LAST_COLUMN + 1):
                square = self.add_square(row, column, pen, brush)
                self._board_squares[Coords(row, column)] = square

    def build_bonus_fields(self):
        for bonus_field in self._bonus_fields:
            brush = bonus_field["Brush"]
            pen = bonus_field["Pen"]
            bonus_fields = []

            for coords in bonus_field["Coords"]:
                label = bonus_field["Name"]
                if coords == Coords.central():
                    label = '✸'
                square = self._board_squares[coords]
                square.setZValue(2)
                bonus_fields.append(square)
                field_name = QGraphicsSimpleTextItem(label)
                font = field_name.font()
                font.setPointSize(10)
                if coords == Coords.central():
                    font.setPointSize(20)
                fm = QFontMetrics(font)
                field_name.setZValue(2.1)
                field_name.setFont(font)
                x = coords.x * SQUARE_SIZE + (SQUARE_SIZE - fm.width(label)) / 2
                y = coords.y * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2
                field_name.setPos(x, y)
                field_name.setBrush(bonus_field["Label brush"])

                self._labels[(x, y)] = field_name
                self.scene.addItem(field_name)

            paint_graphic_items(bonus_fields, pen, brush)

    def build_rack(self):
        brush = QBrush(LIGHT_BROWN)
        pen = QPen(BROWN, 1, Qt.SolidLine)
        for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1):
            square = self.add_square(RACK_ROW, column, pen, brush)
            self._other_squares[Coords(column, RACK_ROW)] = square

    def build_exchange_zone(self):
        brush = QBrush(LIGHT_BROWN)
        pen = QPen(BROWN, 1, Qt.SolidLine)
        for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1):
            square = self.add_square(EXCHANGE_ROW, column, pen, brush)
            self._other_squares[Coords(column, EXCHANGE_ROW)] = square

        text = 'Litery do wymiany →     '
        font = QFont('Verdana', 10)
        fm = QFontMetrics(font)
        x = SQUARE_SIZE * LEFT_RACK_BOUND - fm.width(text)
        y = SQUARE_SIZE * EXCHANGE_ROW + (SQUARE_SIZE - fm.height()) / 2
        label = QGraphicsSimpleTextItem(text)
        label.setPos(x, y)
        label.setFont(font)
        label.setBrush(QBrush(Qt.white))
        self._labels[(x, y)] = label
        self.scene.addItem(label)

    def add_square(self, row, column, pen, brush):
        height = SQUARE_SIZE
        width = SQUARE_SIZE

        column_distance = column * width
        row_distance = row * height

        x = column_distance
        y = row_distance
        rectangle = QRectF(x, y, width, height)

        return self.scene.addRect(rectangle, pen, brush)

    def build_labels(self):
        font = QFont('Verdana', 10)
        fm = QFontMetrics(font)
        for count in range(LAST_ROW + 1):
            number = str(count + 1)
            number_label = QGraphicsSimpleTextItem(number)
            x = -fm.width(number) - SQUARE_SIZE / 8
            y = count * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2
            number_label.setPos(x, y)
            number_label.setFont(font)
            number_label.setBrush(QBrush(Qt.white))
            self._labels[(x, y)] = number_label

            letter = chr(count + ord('A'))
            letter_label = QGraphicsSimpleTextItem(letter)
            x = count * SQUARE_SIZE + (SQUARE_SIZE - fm.width(letter)) / 2
            y = -fm.height() - SQUARE_SIZE / 8
            letter_label.setPos(x, y)
            letter_label.setFont(font)
            letter_label.setBrush(QBrush(Qt.white))
            self._labels[(x, y)] = letter_label

            self.scene.addItem(number_label)
            self.scene.addItem(letter_label)

    def prepare_bonus_fields(self):

        triple_word_bonus_fields = {
            "Name": "3S",
            "Pen": QPen(DARK_RED, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin),
            "Brush": QBrush(RED),
            "Label brush": QBrush(DARK_RED),
            "Coords": triple_word_bonuses
        }
        self._bonus_fields.append(triple_word_bonus_fields)

        double_word_bonus_fields = {
            "Name": "2S",
            "Pen": QPen(RED, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin),
            "Brush": QBrush(PINK),
            "Label brush": QBrush(RED),
            "Coords": double_word_bonuses
        }
        self._bonus_fields.append(double_word_bonus_fields)

        triple_letter_bonus_fields = {
            "Name": "3L",
            "Pen": QPen(NAVY_BLUE, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin),
            "Brush": QBrush(BLUE),
            "Label brush": QBrush(NAVY_BLUE),
            "Coords": triple_letter_bonuses
        }
        self._bonus_fields.append(triple_letter_bonus_fields)

        double_letter_bonus_fields = {
            "Name": "2L",
            "Pen": QPen(BLUE2, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin),
            "Brush": QBrush(LIGHT_BLUE),
            "Label brush": QBrush(BLUE2),
            "Coords": double_letter_bonuses
        }
        self._bonus_fields.append(double_letter_bonus_fields)

    def prepare_board(self):
        self.scene.setSceneRect(-SQUARE_SIZE / 2, -SQUARE_SIZE / 2, SQUARE_SIZE * 16, SQUARE_SIZE * 19)
        self.scene.setBackgroundBrush(QBrush(SEA_GREEN))
        self.setMinimumSize(MINIMAL_WIDTH, MINIMAL_HEIGHT)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
예제 #12
0
 def setUp(self):
     """Set up an empty Sack."""
     self.Sack = Sack()
예제 #13
0
class Word:
    _letters = Sack.values_without_blank()

    def __init__(
            self,
            rack: List[str],
            word: Optional[str] = '',
            start: Optional[Coords] = None,
            end: Optional[Coords] = None,
            points: Optional[int] = 0,
            multiplier: Optional[int] = 1,
            bonus: Optional[int] = 0,
            added_letters: Optional[Dict[Coords, Tuple[str,
                                                       int]]] = None) -> None:
        self._rack = rack[:]
        self._word = word
        self._start = start
        self._end = end
        self._points = points
        self._multiplier = multiplier
        self._bonus = bonus
        if not added_letters:
            added_letters = {}
        self._added_letters = added_letters
        self._is_valid = True

    @property
    def word(self) -> str:
        return self._word

    @property
    def rack(self) -> List[str]:
        return self._rack

    @property
    def start(self) -> Coords:
        return self._start

    @property
    def end(self) -> Coords:
        return self._end

    @property
    def added_letters(self) -> Dict[Coords, Tuple[str, int]]:
        return self._added_letters

    @property
    def is_valid(self) -> bool:
        return self._is_valid

    def __str__(self) -> str:
        return self._word

    def check_beginning(self) -> bool:
        self._is_valid = Dictionary.is_in_group(self._word[:MAX_GROUP_LENGTH])
        return self._is_valid

    def check_end(self) -> bool:
        self._is_valid = Dictionary.is_in_group(self._word[-MAX_GROUP_LENGTH:])
        return self._is_valid

    def is_in_dictionary(self) -> bool:
        return Dictionary.is_word_in_dictionary(self._word)

    def __copy__(self) -> 'Word':
        return Word(self._rack, self._word, self._start, self._end,
                    self._points, self._multiplier, self._bonus,
                    self._added_letters.copy())

    def generate_child(self,
                       letter: str,
                       coords: Coords,
                       extra_points: int,
                       is_blank: Optional[bool] = False):
        child = copy(self)
        child.add_letter(letter, coords, extra_points, True, is_blank)
        if not child.is_valid:
            return None
        return child

    def generate_children(self,
                          coords: Coords,
                          neighbours: Optional[Tuple[List[str], int]] = None):
        children = []
        for letter in set(self._rack):
            extra_points = 0

            if neighbours:
                if letter not in neighbours[0]:
                    continue
                extra_points = neighbours[1]

            if letter == BLANK:
                for new_letter in Word._letters:
                    child = self.generate_child(new_letter, coords,
                                                extra_points, True)
                    if child:
                        children.append(child)
            else:
                child = self.generate_child(letter, coords, extra_points)
                if child:
                    children.append(child)
        return children

    def add_letter(self,
                   letter: str,
                   coords: Coords,
                   extra_points: Optional[int] = 0,
                   is_from_rack: Optional[bool] = False,
                   is_blank: Optional[bool] = False):
        if not self._start:
            self._start = coords
            self._end = coords
            self._word = letter

        elif coords < self._start:
            self._start = coords
            self._word = letter + self._word
            self.check_beginning()
        else:
            self._end = coords
            self._word = self._word + letter
            self.check_end()

        if not self.is_valid:
            return

        letter_points = Sack.get_value(letter) if not is_blank else 0

        if is_from_rack:
            self._added_letters[coords] = letter, letter_points
            self._rack.remove(letter if letter_points else BLANK)

            if coords in double_letter_bonuses:
                letter_points *= 2
            elif coords in triple_letter_bonuses:
                letter_points *= 3
            elif coords in double_word_bonuses:
                self._multiplier *= 2
            elif coords in triple_word_bonuses:
                self._multiplier *= 3

        if extra_points:
            extra_points += letter_points
            if coords in double_word_bonuses:
                extra_points *= 2
            elif coords in triple_word_bonuses:
                extra_points *= 3
            self._bonus += extra_points

        self._points += letter_points

        if len(self._added_letters) == MAX_RACK_SIZE:
            self._bonus += 50

    def sum_up(self):
        return self._points * self._multiplier + self._bonus

    def possible_prefix(self,
                        min_length: Optional[int] = 1,
                        max_length: Optional[int] = 1) -> List[str]:
        return Dictionary.find_prefixes(self._word, len(self._word),
                                        max_length, min_length)

    def possible_suffix(self,
                        min_length: Optional[int] = 1,
                        max_length: Optional[int] = 1) -> List[str]:
        return Dictionary.find_suffixes(self._word, len(self._word),
                                        max_length, min_length)

    def is_vertical(self) -> bool:
        return self._start.is_same_column(self._end)

    def is_horizontal(self) -> bool:
        return self._start.is_same_row(self._end)

    def direction(self) -> Vector:
        if self.is_vertical():
            return DOWN
        return RIGHT
예제 #14
0
파일: ai.py 프로젝트: Kacpri/Scrabble
    def points_for_letters(letters: Iterable[str]) -> int:
        points = 0
        for letter in letters:
            points += Sack.get_value(letter)

        return points