The Tetris Project

Nice pattern, @Jacek, somewhat reminiscent of a switch-case structure, but most importantly, neatly mapping values to actions …
value1: action1
value2: action2
value3: action3

I’m curious how you increased levels. I’m trying with linear function of turn (time) , but it seems like exponential in game. I left minimum value of delay as 10 ms.

I think my scoring system makes sense, but I’m not sure.

I wanted the levels to come in constant time, to keep the player interested, but also to give increasing points as the play goes on for the increasing difficulty due to the piece moving faster.

I thought the Nintendo scoring system worked well, so I used it. It gives the level plus one times the points given for clearing a certain amount of rows. 40 points times the level plus one for one row. 100 points times the level plus one for two rows. 300 times level plus one for three rows, and 1200 times level plus one for four rows.

I wanted the player’s level to increase in constant time, (a fixed interval reinforcement schedule, not that that’s important). Their “income” increases linearly (n1). Their score then would be integral, or accumulated area up until that point. If I’m remembering my calculus correctly, the accumulated area of a linear function is a parabola (n2), according to the power rule. Therefore, I made a guess as to something that would work, which looks like this:

        if self.score > 50*((self.level + 1) ** 2):
            self.level += 1

So the pattern looks like:

+-------+---------------+
| Level | Score (up to) |
+-------+---------------+
| 0     | 50            |
+-------+---------------+
| 1     | 200           |
+-------+---------------+
| 2     | 450           |
+-------+---------------+
| 3     | 800           |
+-------+---------------+
| 4     | 1250          |
+-------+---------------+
| 5     | 1800          |
+-------+---------------+
| 6     | 2450          |
+-------+---------------+
| 7     | 3200          |
+-------+---------------+
| 8     | 4050          |
+-------+---------------+
| 9     | 5000          |
+-------+---------------+

Every level, the delay decreases by 10%, roughly.

If I wanted longer games, I would likely modify the constant 50 to something larger, that way levels wouldn’t increase so fast. Or vice versa for shorter games.

If you would like to try my version yourself, or read my code, you may find it here.

1 Like

I am so incredibly close to a PiecePreview Class, I can taste it. It’s still not working, but I have at least gotten somewhere:

I have really gone on circles with this one. I originally attempted to just create the class at the bottom, being ignorant of canvas placing. It didn’t really fit well on my monitor, so I attempted to place the piece preview window to the side. I tried to do it using the Tkinter pack manager. Then I realized that in order to do so, I would have to create a Frame (or Canvas?) to the right of the Board. No problem. Then I wanted to move it to the top right for visibility. Much more problem. I tried to nest the PiecePreview class within a separate placeholder CanvasFrame, however, they don’t appear to nest. Then I tried…blaaa.

Anyways, after a long frustrating series of events I ended up giving up on the top right location and was just happy with it being to the right of the board. It still doesn’t work correctly, but I have a place to put the piece now and it sort of shows up.

The tetris_template.py seems like it was really not intended to be expanded beyond the original design. The shapes’ drawing methods are dependent upon the coordinate system of the Board class. Because of that, I really can’t figure out how to get a shape to draw on a separate location on screen. Incredibly annoying. Anyways, we will get there somehow.

1 Like

Not sure if this will help, but to accommodate the display of the score, I made room for both the ScoreBoard and the ScoreBoard in the main window in the Tetris __init__ method. Would it help for you to do the same for the PiecePreview class?

That would work only if you wanted to place all of the game components in the same window.

    def __init__(self, win):
        self.score = 0
        self.board = Board(win, self.BOARD_WIDTH, self.BOARD_HEIGHT)
        self.scoreBoard = ScoreBoard(win, self.BOARD_WIDTH * Block.BLOCK_SIZE, 50, 0)
 
 
        self.win = win
        self.delay = 1000 #ms
 
        # sets up the keyboard events
        # when a key is called the method key_pressed will be called
        self.win.bind_all('<Key>', self.key_pressed)
 
        # set the current shape to a random new shape
        self.current_shape = self.create_new_shape()
 
        # Draw the current_shape on the board (take a look at the
        # draw_shape method in the Board class)
        ####  YOUR CODE HERE ####
        self.board.draw_shape(self.current_shape)
        self.increment_score(1)
        # For Step 9:  animate the shape!
        ####  YOUR CODE HERE ####
        self.paused = False
        self.animate_shape()
1 Like

Sheesh, finally made the Piece Preview. Took long enough. I think the Pareto Principle applies here. It’s not fancy, and the pieces shift at gameover, but it’s close enough for me. I can’t seem to get a screenshot to work right, but you can find the code here.

1 Like

The Piece Preview is a nice feature that helps with planning where to steer the current shape.

I did manage, accidentally, to get your code to throw an error by hitting an invalid key at some point.

Exception in Tkinter callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "/Python/MechanicalMOOC/_Tetris_2015/cedar_mora_tetris.py", line 602, in key_pressed
    self.do_move(key)
  File "/Python/MechanicalMOOC/_Tetris_2015/cedar_mora_tetris.py", line 556, in do_move
    dx = self.DIRECTION[direction][0]
KeyError: '??'

It could be addressed by adding some defensive code to the Tetris class’s key_pressed method.

Fixed. I used a try and except block. Now it just ignores invalid keys to the DIRECTION dictionary in the Tetris class, as you may see in the commit.

By KeyError, it didn’t mean a key on a keyboard, it meant a key to a dictionary, the DIRECTION dictionary. So when you press some invalid key, say ‘a’, it will still accept it as input, but when it attempts to use the do_move method of the Tetris class, it would look up ‘a’ as a key in the DIRECTION dictionary, which doesn’t exist. The DIRECTION dictionary only has ‘Left’, ‘Right’, and ‘Down’. ‘a’ is not among them. ‘space’ doesn’t throw an exception because it is handled in the key_pressed method of the Tetris class.

1 Like