joriszwart.nl

I code dreams™

pytris

Download
from random import randrange

from blocks import blocks
from bucket import Bucket
from render import draw_bucket

from browser import document, bind, window, timer

class Tetris:

    def __init__(self):
        canvas = document["tetris"]
        self.ctx = canvas.getContext("2d")

        self.bucket = Bucket()

        # new game
        self.lines = 0
        self.score = 0
        self.timer = 0

        # new block
        self.new_block()

    def new_block(self):
        self.block = randrange(len(blocks))     # TODO seems not very random, lots of same blocks
        self.rotation = 0
        self.row = 0
        self.column = 3

        if not self.bucket.test_tetromino(self.row, self.column, self.block, self.rotation):
            window.alert('Game over!')
            timer.clear_interval(self.timer)
            return

        self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

        timer.clear_interval(self.timer)
        self.timer = timer.set_interval(self.move_down, 650 - self.lines)

    def move_down(self):
        self.bucket.clear_tetromino(self.row, self.column, self.block, self.rotation)

        if self.bucket.test_tetromino(self.row + 1, self.column, self.block, self.rotation):
            self.score += 1
            self.row += 1
            self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

        else:
            # land block
            self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)
            lines_cleared = self.bucket.clear_lines()

            self.score += [0, 150, 300, 700, 1500][lines_cleared]
            self.lines += lines_cleared

            # new block
            self.new_block()

    def move_left(self):
        self.bucket.clear_tetromino(self.row, self.column, self.block, self.rotation)

        if self.bucket.test_tetromino(self.row, self.column - 1, self.block, self.rotation):
            self.column -= 1

        self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

    def move_right(self):
        self.bucket.clear_tetromino(self.row, self.column, self.block, self.rotation)

        if self.bucket.test_tetromino(self.row, self.column + 1, self.block, self.rotation):
            self.column += 1

        self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

    def rotate(self):
        self.bucket.clear_tetromino(self.row, self.column, self.block, self.rotation)

        if self.bucket.test_tetromino(
            self.row, self.column, self.block, (self.rotation + 1) % 4
        ):
            self.rotation = (self.rotation + 1) % 4

        self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

    def drop(self):
        self.bucket.clear_tetromino(self.row, self.column, self.block, self.rotation)

        while self.bucket.test_tetromino(self.row + 1, self.column, self.block, self.rotation):
            self.row += 1
            self.score += 5

        self.bucket.draw_tetromino(self.row, self.column, self.block, self.rotation)

    def draw_score(self):
        self.ctx.fillStyle = "white"
        self.ctx.fillText(f"Score: {self.score}", 220, 20)
        self.ctx.fillText(f"Lines: {self.lines}", 220, 40)

    def loop(self, *args):
        self.ctx.clearRect(0, 0, self.ctx.canvas.width, self.ctx.canvas.height)
        self.draw_score()
        draw_bucket(self.ctx, self.bucket.bucket)

        # TODO optimize timer.set_timeout(self.loop, self.speed)
        window.requestAnimationFrame(self.loop)

@bind(document, "keydown")
def keyDownHandler(e):

    if e.metaKey or e.altKey or e.shiftKey or e.ctrlKey:
        return

    match e.code:
        case "ArrowLeft" | "KeyJ":
            e.preventDefault()
            tetris.move_left()
 
        case "ArrowRight" | "KeyL":
            e.preventDefault()
            tetris.move_right()
 
        case "ArrowDown" | "KeyM":
            e.preventDefault()
            tetris.move_down()
 
        case "ArrowUp" | "KeyK":
            e.preventDefault()
            tetris.rotate()

        case "Space":
            e.preventDefault()
            tetris.drop()

tetris = Tetris()
tetris.loop()