Example #1
0
 def __init__(self) -> None:
     """Initialise the Tetris application."""
     self._field = PlayField(10, 24)
     self._generator = RandomGenerator()
     self._keymap = {
         "Left": MoveCommand("left", self._field),
         "Right": MoveCommand("right", self._field),
         "Down": MoveCommand("down", self._field),
         "space": DropCommand(self),
         "Up": RotateCommand("right", self._field),
         "x": RotateCommand("right", self._field),
         "Control_L": RotateCommand("left", self._field),
         "Control_R": RotateCommand("left", self._field),
         "z": RotateCommand("left", self._field),
         "Shift_L": HoldCommand(self),
         "Shift_R": HoldCommand(self),
         "c": HoldCommand(self),
         "Escape": PlayPauseCommand(self)
     }
     self._valid_keys = self._keymap.keys()
     self._window = AppFrame(self._field, self)
     self._field.add_observer(self._window)
     self._fall_delay = 1000
     self._lock_delay = 500
     self._playing = False
     self._new_game = True
     self._counting_down = False
     self._level = 1
     self._progress_to_next_level = 0
     self._score = 0
     self._next_tetrimino = None
     self._held = None
     self._already_held = False
Example #2
0
 def __init__(self, parent, kind) -> None:
     """Initialise display of the tetrimino."""
     tk.Frame.__init__(self, parent)
     self._canvas = tk.Canvas(self, width=25 * 6, height=25 * 4)
     self._canvas.pack()
     self._field = PlayField(6, 8)
     self._rects = [[self._rect(x,y) for y in range(4)] \
                    for x in range(6)]
     self._kind = kind
     self.update(self._kind)
Example #3
0
class SingleTetriminoViewer(PlayFieldViewer):
    """ This class displays a single tetrimino.
    
    Public Methods:
    - update(kind: Optional[str]) -> None
    """
    def __init__(self, parent, kind) -> None:
        """Initialise display of the tetrimino."""
        tk.Frame.__init__(self, parent)
        self._canvas = tk.Canvas(self, width=25 * 6, height=25 * 4)
        self._canvas.pack()
        self._field = PlayField(6, 8)
        self._rects = [[self._rect(x,y) for y in range(4)] \
                       for x in range(6)]
        self._kind = kind
        self.update(self._kind)

    def update(self, kind: Optional[str]) -> None:
        """Update display of the tetrimino."""
        self._field.clear()
        if kind != None:
            self._field.spawn(kind)
            self._field.drop_current()
            self._field.move_current("up")
        self._draw_squares()
Example #4
0
 def setUp(self):
     self.field = PlayField(10, 24)
     self.tetrimino = TetriminoJ("north", (4, 10), self.field)
Example #5
0
 def test_init(self):
     with self.assertRaises(ValueError):
         self.p = PlayField(3, 24)
     with self.assertRaises(ValueError):
         self.p = PlayField(10, 5)
Example #6
0
 def setUp(self):
     self.p = PlayField(10, 24)
Example #7
0
class PlayFieldMethods(unittest.TestCase):
    def setUp(self):
        self.p = PlayField(10, 24)

    def test_init(self):
        with self.assertRaises(ValueError):
            self.p = PlayField(3, 24)
        with self.assertRaises(ValueError):
            self.p = PlayField(10, 5)

    def test_valid_square(self):
        self.assertTrue(self.p.valid_square(5, 10))
        self.assertFalse(self.p.valid_square(10, 24))
        self.assertFalse(self.p.valid_square(-1, 10))

    def test_is_empty_square(self):
        self.assertTrue(self.p.is_empty_square(5, 10))
        self.p._field[5][10] = "J"
        self.assertFalse(self.p.is_empty_square(5, 10))
        with self.assertRaises(ValueError):
            self.p.is_empty_square(-1, 10)

    def test_get_square_kind(self):
        self.assertEqual(self.p.get_square_kind(5, 10), None)
        self.p._field[5][10] = "J"
        self.assertEqual(self.p.get_square_kind(5, 10), "J")
        with self.assertRaises(ValueError):
            self.p.get_square_kind(-1, 10)

    def test_row_is_full(self):
        self.assertFalse(self.p.row_is_full(10))
        for x in range(10):
            self.p._field[x][10] = "J"
        self.assertTrue(self.p.row_is_full(10))
        with self.assertRaises(ValueError):
            self.p.row_is_full(24)

    def test_clear_row(self):
        for x in range(10):
            self.p._field[x][23] = "J"
        for x in range(10):
            self.p._field[x][22] = "T"
        for x in range(5):
            self.p._field[x][21] = "O"
        self.p.clear_row(23)
        # Check if rows above have moved down
        for x in range(10):
            self.assertEqual(self.p.get_square_kind(x, 23), "T")
        for x in range(5):
            self.assertEqual(self.p.get_square_kind(x, 22), "O")
        for x in range(5, 10):
            self.assertTrue(self.p.is_empty_square(x, 22))
        with self.assertRaises(ValueError):
            self.p.clear_row(24)

    def test_clear(self):
        for x in range(10):
            self.p._field[x][23] = "J"
        for x in range(10):
            self.p._field[x][22] = "T"
        for x in range(5):
            self.p._field[x][21] = "O"
        self.p.clear()
        for x in range(10):
            for y in range(24):
                self.assertTrue(self.p.is_empty_square(x, y))

    def test_lock_out(self):
        # Game not started
        self.assertFalse(self.p.lock_out())
        # Game lost to lock out
        for x in range(10):
            self.p._field[x][4] = "J"
        self.p.spawn("I")
        self.assertTrue(self.p.lock_out())
        self.p.clear()
        # Game not lost
        self.p.spawn("I")
        self.assertFalse(self.p.lock_out())

    def test_move_current(self):
        with self.assertRaises(AssertionError):
            self.p.move_current("down")
        self.p.spawn("J")
        self.p.move_current("down")
        self.assertEqual(self.p.get_square_kind(3, 3), "J")
        self.assertEqual(self.p.get_square_kind(3, 4), "J")
        self.assertEqual(self.p.get_square_kind(4, 4), "J")
        self.assertEqual(self.p.get_square_kind(5, 4), "J")
        self.p.clear()

        self.p.spawn("O")
        self.p.move_current("right")
        self.assertEqual(self.p.get_square_kind(5, 2), "O")
        self.assertEqual(self.p.get_square_kind(5, 3), "O")
        self.assertEqual(self.p.get_square_kind(6, 2), "O")
        self.assertEqual(self.p.get_square_kind(6, 3), "O")
        self.p.clear()

        self.p.spawn("T")
        self.p.move_current("left")
        self.assertEqual(self.p.get_square_kind(3, 2), "T")
        self.assertEqual(self.p.get_square_kind(2, 3), "T")
        self.assertEqual(self.p.get_square_kind(3, 3), "T")
        self.assertEqual(self.p.get_square_kind(4, 3), "T")
        self.p.clear()

        self.p.spawn("I")
        self.p.move_current("up")
        self.assertEqual(self.p.get_square_kind(3, 2), "I")
        self.assertEqual(self.p.get_square_kind(4, 2), "I")
        self.assertEqual(self.p.get_square_kind(5, 2), "I")
        self.assertEqual(self.p.get_square_kind(6, 2), "I")
        with self.assertRaises(ValueError):
            self.p.move_current("a")

    def test_rotate_current(self):
        # Note rotations based on SRS
        with self.assertRaises(AssertionError):
            self.p.rotate_current("left")
        self.p.spawn("S")
        self.p.rotate_current("left")
        self.assertEqual(self.p.get_square_kind(3, 3), "S")
        self.assertEqual(self.p.get_square_kind(4, 4), "S")
        self.assertEqual(self.p.get_square_kind(4, 3), "S")
        self.assertEqual(self.p.get_square_kind(3, 2), "S")
        self.p.clear()

        self.p.spawn("L")
        self.p.rotate_current("right")
        self.assertEqual(self.p.get_square_kind(4, 3), "L")
        self.assertEqual(self.p.get_square_kind(4, 2), "L")
        self.assertEqual(self.p.get_square_kind(4, 4), "L")
        self.assertEqual(self.p.get_square_kind(5, 4), "L")
        with self.assertRaises(ValueError):
            self.p.rotate_current("laft")

    def test_drop_current(self):
        with self.assertRaises(AssertionError):
            self.p.drop_current()
        self.p.spawn("Z")
        self.p.drop_current()
        self.assertEqual(self.p.get_square_kind(3, 22), "Z")
        self.assertEqual(self.p.get_square_kind(4, 22), "Z")
        self.assertEqual(self.p.get_square_kind(4, 23), "Z")
        self.assertEqual(self.p.get_square_kind(5, 23), "Z")

    def test_delete_current(self):
        with self.assertRaises(AssertionError):
            self.p.drop_current()
        self.p.spawn("I")
        self.p.delete_current()
        self.assertTrue(self.p.is_empty_square(3, 3))
        self.assertTrue(self.p.is_empty_square(4, 3))
        self.assertTrue(self.p.is_empty_square(5, 3))
        self.assertTrue(self.p.is_empty_square(6, 3))

    def test_spawn(self):
        self.p.spawn("J")
        self.assertEqual(self.p.get_square_kind(3, 2), "J")
        self.assertEqual(self.p.get_square_kind(3, 3), "J")
        self.assertEqual(self.p.get_square_kind(4, 3), "J")
        self.assertEqual(self.p.get_square_kind(5, 3), "J")
        self.p.clear()

        self.p.spawn("L")
        self.assertEqual(self.p.get_square_kind(5, 2), "L")
        self.assertEqual(self.p.get_square_kind(3, 3), "L")
        self.assertEqual(self.p.get_square_kind(4, 3), "L")
        self.assertEqual(self.p.get_square_kind(5, 3), "L")
        self.p.clear()

        self.p.spawn("O")
        self.assertEqual(self.p.get_square_kind(4, 2), "O")
        self.assertEqual(self.p.get_square_kind(4, 3), "O")
        self.assertEqual(self.p.get_square_kind(5, 2), "O")
        self.assertEqual(self.p.get_square_kind(5, 3), "O")
        self.p.clear()

        self.p.spawn("I")
        self.assertEqual(self.p.get_square_kind(3, 3), "I")
        self.assertEqual(self.p.get_square_kind(4, 3), "I")
        self.assertEqual(self.p.get_square_kind(5, 3), "I")
        self.assertEqual(self.p.get_square_kind(6, 3), "I")
        self.p.clear()

        self.p.spawn("S")
        self.assertEqual(self.p.get_square_kind(3, 3), "S")
        self.assertEqual(self.p.get_square_kind(4, 3), "S")
        self.assertEqual(self.p.get_square_kind(4, 2), "S")
        self.assertEqual(self.p.get_square_kind(5, 2), "S")
        self.p.clear()

        self.p.spawn("Z")
        self.assertEqual(self.p.get_square_kind(3, 2), "Z")
        self.assertEqual(self.p.get_square_kind(4, 2), "Z")
        self.assertEqual(self.p.get_square_kind(4, 3), "Z")
        self.assertEqual(self.p.get_square_kind(5, 3), "Z")
        self.p.clear()

        self.p.spawn("T")
        self.assertEqual(self.p.get_square_kind(4, 2), "T")
        self.assertEqual(self.p.get_square_kind(3, 3), "T")
        self.assertEqual(self.p.get_square_kind(4, 3), "T")
        self.assertEqual(self.p.get_square_kind(5, 3), "T")
        self.p.clear()
        with self.assertRaises(ValueError):
            self.p.spawn("A")
Example #8
0
class Tetris:
    """This is the main application class.

    This class acts as the controller and contains the main gameplay
    loop. 
    
    Public Methods:
    - get_level() -> int
    - get_score() -> int
    - get_playing() -> bool
    - get_next() -> Optional[str]
    - get_held() -> Optional[str]
    - play_or_pause() -> None
    - drop() -> None
    - hold() -> None
    - activate() -> None
    """
    def __init__(self) -> None:
        """Initialise the Tetris application."""
        self._field = PlayField(10, 24)
        self._generator = RandomGenerator()
        self._keymap = {
            "Left": MoveCommand("left", self._field),
            "Right": MoveCommand("right", self._field),
            "Down": MoveCommand("down", self._field),
            "space": DropCommand(self),
            "Up": RotateCommand("right", self._field),
            "x": RotateCommand("right", self._field),
            "Control_L": RotateCommand("left", self._field),
            "Control_R": RotateCommand("left", self._field),
            "z": RotateCommand("left", self._field),
            "Shift_L": HoldCommand(self),
            "Shift_R": HoldCommand(self),
            "c": HoldCommand(self),
            "Escape": PlayPauseCommand(self)
        }
        self._valid_keys = self._keymap.keys()
        self._window = AppFrame(self._field, self)
        self._field.add_observer(self._window)
        self._fall_delay = 1000
        self._lock_delay = 500
        self._playing = False
        self._new_game = True
        self._counting_down = False
        self._level = 1
        self._progress_to_next_level = 0
        self._score = 0
        self._next_tetrimino = None
        self._held = None
        self._already_held = False

    def get_level(self) -> int:
        """Return the current level."""
        return self._level

    def get_score(self) -> int:
        """Return the current score."""
        return self._score

    def get_playing(self) -> bool:
        """Return whether or not a game of Tetris is being played."""
        return self._playing

    def get_next(self) -> Optional[str]:
        """Return the kind of tetrimino that will be played next."""
        return self._next_tetrimino

    def get_held(self) -> Optional[str]:
        """Return the kind of tetrimino currently being held."""
        return self._held

    def play_or_pause(self) -> None:
        """If a game of Tetris is playing, pause the game; otherwise,
        play the game."""
        if self._counting_down:  # Can't activate while counting down
            return
        if self._playing:
            self._pause()
        else:
            self._play()

    def _play(self) -> None:
        """Start/Resume a game of Tetris."""
        self._window.clear_key()
        # Starting a new game
        if self._new_game:
            self._new_game = False
            self._field.clear()
            self._held = None
            self._field.spawn(self._generator.next())
            self._next_tetrimino = self._generator.next()
            self._window.remove_game_over_text()
        # Resuming a game
        else:
            self._window.remove_pause_text()
        self._counting_down = True
        self._window.countdown()  # Takes 4 seconds
        self._window.after(4000, self._counting_down_false)
        self._window.after(4000, self._playing_true)
        self._window.after(4000, self._window.update_ui, self)
        self._window.after(4000, self._game_loop)
        self._window.after(4000, self._listen_to_keys)

    def _playing_true(self) -> None:
        """Set self._playing to be true."""
        self._playing = True

    def _counting_down_false(self) -> None:
        """Set self._counting_down to be false."""
        self._counting_down = False

    def _pause(self) -> None:
        """Pause a game of Tetris."""
        self._playing = False
        self._window.show_pause_text()
        self._window.update_ui(self)

    def drop(self) -> None:
        """Drop the current tetrimino."""
        self._field.drop_current()
        # Instantly lock
        rows_cleared = 0
        for y in range(self._field.get_height()):
            if self._field.row_is_full(y):
                self._field.clear_row(y)
                rows_cleared += 1
        self._update_scores_and_levels(rows_cleared)
        self._update_fall_delay()
        if self._game_over():
            self._playing = False
            self._new_game = True
            self._next_tetrimino = None
            self._window.update_ui(self)
            self._window.show_game_over_text()
            self._window.game_over_dialog(self._level, self._score)
        self._already_held = False  # Can hold again

    def hold(self) -> None:
        """Hold the current tetrimino and spawn in the previously held
        tetrimino; if such a tetrimino does not exist, spawn a new 
        tetrimino."""
        if self._already_held:  # Prevent infinitely spamming hold
            return  # without placing a tetrimino
        self._already_held = True
        prev_held = self._held
        self._held = self._field.delete_current().kind
        if prev_held == None:
            self._field.spawn(self._next_tetrimino)
            self._next_tetrimino = self._generator.next()
        else:
            self._field.spawn(prev_held)
        self._window.update_ui(self)

    def _game_loop(self) -> None:
        """The main gameplay loop for Tetris."""
        if self._playing:
            # Current tetrimino is set
            if not self._field.move_current("down"):
                self._already_held = False
                self._window.after(self._lock_delay,
                                   self._set_current_tetrimino)
            # Current block has fallen one space
            else:
                self._window.after(self._fall_delay, self._game_loop)

    def _set_current_tetrimino(self) -> None:
        """Set the current tetrimino into place, clearing any filled
        rows, updating scores, levels and movement delay and check if
        the game is over."""
        if not self._field.move_current("down"):
            rows_cleared = 0
            for y in range(self._field.get_height()):
                if self._field.row_is_full(y):
                    self._field.clear_row(y)
                    rows_cleared += 1
            self._update_scores_and_levels(rows_cleared)
            self._update_fall_delay()
            if self._game_over():
                self._playing = False
                self._new_game = True
                self._next_tetrimino = None
                self._window.update_ui(self)
                self._window.game_over_dialog(self._level, self._score)
            self._window.after(0, self._game_loop)
        # User has moved block to where it can fall again
        else:
            self._window.after(self._fall_delay, self._game_loop)

    def _update_scores_and_levels(self, rows_cleared: int) -> None:
        """Update the score and level based on how many rows were
        cleared."""
        if rows_cleared == 1:
            self._progress_to_next_level += 1
            self._score += 100 * self._level
        elif rows_cleared == 2:
            self._progress_to_next_level += 3
            self._score += 300 * self._level
        elif rows_cleared == 3:
            self._progress_to_next_level += 5
            self._score += 500 * self._level
        elif rows_cleared == 4:
            self._progress_to_next_level += 8
            self._score += 800 * self._level
        if self._progress_to_next_level >= self._level * 5:
            self._progress_to_next_level -= self._level * 5
            self._level += 1
        self._window.update_ui(self)

    def _update_fall_delay(self) -> None:
        """Update the speed at which tetriminoes fall based on the
        current level."""
        self._fall_delay = (0.8 - (self._level - 1) * 0.007)**(self._level - 1)
        self._fall_delay *= 1000
        self._fall_delay = int(self._fall_delay)

    def _game_over(self) -> bool:
        """Return whether the game is over.

        If the game is not over, this method has the side effect of
        spawning the next tetrimino."""
        over = (self._field.lock_out()
                or not self._field.spawn(self._next_tetrimino))
        self._next_tetrimino = self._generator.next()
        self._window.update_ui(self)
        return over

    def _listen_to_keys(self) -> None:
        """Respond to user keyboard input."""
        if self._playing:
            key = self._window.get_key()
            if key in self._valid_keys:
                cmd = self._keymap[key]
                cmd.execute()
            self._window.after(10, self._listen_to_keys)
        else:
            key = self._window.get_key()
            if key == "Escape":  # If not playing only listen to the
                cmd = self._keymap[key]  # escape key which pauses/plays the
                cmd.execute()  # game
            self._window.after(10, self._listen_to_keys)

    def activate(self) -> None:
        """Activate the application."""
        self._field.notify_observers()
        self._window.update_ui(self)
        self._window.mainloop()
Example #9
0
    initLog('kajongg')

    ABOUT = About()
    KCmdLineArgs.init (sys.argv, ABOUT.about)
    KCmdLineArgs.addCmdLineOptions(defineOptions())
    KApplication.setGraphicsSystem('raster')
    APP = KApplication()
    parseOptions()

    if Debug.events:
        EVHANDLER = EvHandler()
        APP.installEventFilter(EVHANDLER)

    from config import SetupPreferences
    SetupPreferences()

    import qt4reactor
    qt4reactor.install()
    from twisted.internet import reactor
    reactor.runReturn(installSignalHandlers=False) # pylint: disable=E1101
    # pylint thinks reactor is missing runReturn
    Internal.reactor = reactor

    if Options.gui:
        from playfield import PlayField
        PlayField().show()
    else:
        from humanclient import HumanClient
        HumanClient()
    Internal.app.exec_()
Example #10
0
def run():
    global game_finished
    global startTime
    global scoreKeeper
    hard = False

    playfield = PlayField()
    hand = Hand()

    clock = pygame.time.Clock()
    is_running = True
    show_menu = True

    while is_running:
        if not show_menu:
            playfield.advance(hand, hard)
            clock.tick(25)

        #event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_running = False

            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    is_running = False
                if event.key == pygame.K_a:
                    a, b = new_easy_rectangle_pair(
                        pygame.Rect(100, 100, 100, 100),
                        pygame.Rect(100, 100, 100, 100))
                    hand.add(b)
                if event.key == pygame.K_l:
                    to_remove = randint(0, len(hand.pieces) - 1)
                    hand.remove(to_remove)

            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:

                    #catch event for dificulty selection
                    if show_menu and Menu.easy.rect.collidepoint(event.pos):
                        hard = False
                        show_menu = False
                    if show_menu and Menu.hard.rect.collidepoint(event.pos):
                        hard = True
                        show_menu = False

                    #catch event for GameOverScreen
                    if game_finished and GameOverScreen.restart.rect.collidepoint(
                            event.pos):
                        game_finished = False
                        show_menu = True  #set this to true when select dificulty is a thing
                        scoreKeeper = ScoreKeeper()
                        playfield = PlayField()
                        hand = Hand()
                        startTime = time.time()
                        elapsedTime = 0

                    for i, r in enumerate(hand.pieces):
                        grabbable = r.grabbable
                        r = r.rect
                        if r.collidepoint(
                                event.pos) and grabbable and not show_menu:
                            hand.selected = i
                            selected_offset_x = r.x - event.pos[0]
                            selected_offset_y = r.y - event.pos[1]

            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    if hand.selected is not None:
                        buckets = playfield.buckets()
                        foundMatch = False
                        for i in range(0, len(buckets)):
                            if buckets[i].rect.colliderect(
                                    hand.selected_piece().rect
                            ) and buckets[i].value == hand.selected_piece(
                            ).value:
                                playfield.remove(i)
                                playfield.speed += 0.01
                                hand.remove(hand.selected)
                                scoreKeeper.increment(
                                    buckets[i].value)  #increment score by 10
                                foundMatch = True
                                break

                        #reset combo if no matching piece was selected
                        if foundMatch == False:
                            scoreKeeper.endCombo()
                        hand.selected = None
                        hand.realign()

            elif event.type == pygame.MOUSEMOTION:
                if hand.selected is not None:  # selected can be `0` so `is not None` is required
                    # move object
                    hand.selected_piece(
                    ).rect.x = event.pos[0] + selected_offset_x
                    hand.selected_piece(
                    ).rect.y = event.pos[1] + selected_offset_y

        #keep track of game state here
        buckets = playfield.buckets()
        for bucket in buckets:
            if bucket.rect.colliderect(HAND_AREA):
                game_finished = True  #game over condition

        #draw graphics
        screen.fill((32, 34, 37))
        pygame.draw.rect(screen, (64, 68, 75), HAND_AREA)

        drawScoreAndTime()
        if game_finished:
            GameOverScreen.draw(screen)
        else:
            for r in playfield.buckets():
                r.draw_on(screen)
            for r in hand.pieces:
                r.draw_on(screen)
            if show_menu:
                Menu.draw(screen)
        pygame.display.update()

    pygame.quit()