<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Marcelo Martins</title>
    <description>The latest articles on Forem by Marcelo Martins (@marcelo_martins_41c7f1c95).</description>
    <link>https://forem.com/marcelo_martins_41c7f1c95</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3492421%2F48463ad2-f278-4629-a1cb-b36241e55bfa.jpg</url>
      <title>Forem: Marcelo Martins</title>
      <link>https://forem.com/marcelo_martins_41c7f1c95</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/marcelo_martins_41c7f1c95"/>
    <language>en</language>
    <item>
      <title>Dominoes Game ⚅</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Wed, 14 Jan 2026 10:14:32 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/dominoes-game-mj9</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/dominoes-game-mj9</guid>
      <description>&lt;p&gt;import random&lt;/p&gt;

&lt;h1&gt;
  
  
  Create domino set
&lt;/h1&gt;

&lt;p&gt;def create_dominoes():&lt;br&gt;
    return [(i, j) for i in range(7) for j in range(i, 7)]&lt;/p&gt;

&lt;h1&gt;
  
  
  Print domino nicely
&lt;/h1&gt;

&lt;p&gt;def print_domino(d):&lt;br&gt;
    return f"[{d[0]}|{d[1]}]"&lt;/p&gt;

&lt;p&gt;def print_hand(hand):&lt;br&gt;
    for i, d in enumerate(hand):&lt;br&gt;
        print(f"{i}: {print_domino(d)}")&lt;/p&gt;

&lt;p&gt;def can_play(domino, left, right):&lt;br&gt;
    return domino[0] == left or domino[1] == left or \&lt;br&gt;
           domino[0] == right or domino[1] == right&lt;/p&gt;

&lt;p&gt;def play_domino(domino, board, side):&lt;br&gt;
    left, right = board[0][0], board[-1][1]&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a, b = domino
if side == "L":
    if b == left:
        board.insert(0, (a, b))
    else:
        board.insert(0, (b, a))
else:
    if a == right:
        board.append((a, b))
    else:
        board.append((b, a))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def pip_sum(hand):&lt;br&gt;
    return sum(a + b for a, b in hand)&lt;/p&gt;

&lt;p&gt;def main():&lt;br&gt;
    dominoes = create_dominoes()&lt;br&gt;
    random.shuffle(dominoes)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;player = dominoes[:7]
computer = dominoes[7:14]

# Find starting tile (highest double)
all_tiles = player + computer
doubles = [d for d in all_tiles if d[0] == d[1]]

if doubles:
    start = max(doubles)
else:
    start = max(all_tiles)

if start in player:
    turn = "player"
    player.remove(start)
else:
    turn = "computer"
    computer.remove(start)

board = [start]

print("Starting tile:", print_domino(start))

passes = 0

while True:
    print("\nBoard:", " ".join(print_domino(d) for d in board))
    left, right = board[0][0], board[-1][1]

    if turn == "player":
        print("\nYour hand:")
        print_hand(player)

        playable = [d for d in player if can_play(d, left, right)]
        if not playable:
            print("You pass.")
            passes += 1
            turn = "computer"
            continue

        passes = 0
        choice = int(input("Choose tile index: "))
        side = input("Play Left or Right? (L/R): ").upper()

        domino = player[choice]
        if not can_play(domino, left, right):
            print("Invalid move!")
            continue

        play_domino(domino, board, side)
        player.remove(domino)

        if not player:
            print("🎉 You win!")
            break

        turn = "computer"

    else:
        playable = [d for d in computer if can_play(d, left, right)]
        if not playable:
            print("\nComputer passes.")
            passes += 1
            turn = "player"
            continue

        passes = 0
        domino = random.choice(playable)

        if domino[0] == left or domino[1] == left:
            play_domino(domino, board, "L")
        else:
            play_domino(domino, board, "R")

        computer.remove(domino)
        print("\nComputer plays", print_domino(domino))

        if not computer:
            print("💻 Computer wins!")
            break

        turn = "player"

    if passes == 2:
        print("\nGame blocked!")
        ps, cs = pip_sum(player), pip_sum(computer)
        print("Your pips:", ps, "| Computer pips:", cs)
        if ps &amp;lt; cs:
            print("🎉 You win!")
        elif cs &amp;lt; ps:
            print("💻 Computer wins!")
        else:
            print("🤝 Draw!")
        break
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    main()&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Ninja Fruit 🥷 ⚔️ 🥥</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Mon, 24 Nov 2025 11:58:06 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/ninja-fruit-5hm4</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/ninja-fruit-5hm4</guid>
      <description>&lt;p&gt;import pygame&lt;br&gt;
import random&lt;br&gt;
import math&lt;br&gt;
import sys&lt;/p&gt;

&lt;p&gt;pygame.init()&lt;/p&gt;

&lt;p&gt;WIDTH, HEIGHT = 800, 600&lt;br&gt;
screen = pygame.display.set_mode((WIDTH, HEIGHT))&lt;br&gt;
clock = pygame.time.Clock()&lt;br&gt;
font = pygame.font.Font(None, 40)&lt;/p&gt;

&lt;h1&gt;
  
  
  Colors
&lt;/h1&gt;

&lt;p&gt;WHITE = (255, 255, 255)&lt;br&gt;
RED = (200, 50, 50)&lt;br&gt;
BLACK = (0, 0, 0)&lt;br&gt;
YELLOW = (240, 230, 40)&lt;/p&gt;

&lt;h1&gt;
  
  
  Game data
&lt;/h1&gt;

&lt;p&gt;fruits = []&lt;br&gt;
score = 0&lt;br&gt;
game_over = False&lt;/p&gt;

&lt;p&gt;def spawn_fruit():&lt;br&gt;
    """Create fruit objects."""&lt;br&gt;
    x = random.randint(100, WIDTH - 100)&lt;br&gt;
    y = HEIGHT + 50&lt;br&gt;
    speed_x = random.uniform(-3, 3)&lt;br&gt;
    speed_y = random.uniform(-10, -15)&lt;br&gt;
    fruit_type = random.choice(["fruit", "fruit", "fruit", "bomb"])  # bombs are rarer&lt;br&gt;
    fruits.append({&lt;br&gt;
        "x": x,&lt;br&gt;
        "y": y,&lt;br&gt;
        "vx": speed_x,&lt;br&gt;
        "vy": speed_y,&lt;br&gt;
        "type": fruit_type&lt;br&gt;
    })&lt;/p&gt;

&lt;p&gt;def draw_fruit(f):&lt;br&gt;
    if f["type"] == "fruit":&lt;br&gt;
        pygame.draw.circle(screen, RED, (int(f["x"]), int(f["y"])), 25)&lt;br&gt;
    else:&lt;br&gt;
        pygame.draw.circle(screen, BLACK, (int(f["x"]), int(f["y"])), 25)&lt;br&gt;
        pygame.draw.circle(screen, YELLOW, (int(f["x"]), int(f["y"])), 10)&lt;/p&gt;

&lt;p&gt;def update_fruit(f):&lt;br&gt;
    f["x"] += f["vx"]&lt;br&gt;
    f["y"] += f["vy"]&lt;br&gt;
    f["vy"] += 0.4  # gravity&lt;/p&gt;

&lt;p&gt;def slice_check(f, mouse_path):&lt;br&gt;
    """Check if mouse swiped across the fruit."""&lt;br&gt;
    if len(mouse_path) &amp;lt; 2:&lt;br&gt;
        return False&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(len(mouse_path) - 1):
    x1, y1 = mouse_path[i]
    x2, y2 = mouse_path[i+1]
    dist = abs((x2-x1)*(f["y"]-y1) - (y2-y1)*(f["x"]-x1)) / (
        math.hypot(x2-x1, y2-y1) + 0.001
    )
    if dist &amp;lt; 30:  # slice width
        return True
return False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;mouse_path = []&lt;/p&gt;

&lt;p&gt;SPAWN_EVENT = pygame.USEREVENT + 1&lt;br&gt;
pygame.time.set_timer(SPAWN_EVENT, 700)&lt;/p&gt;

&lt;p&gt;while True:&lt;br&gt;
    screen.fill((30, 30, 30))&lt;br&gt;
    mouse_path = mouse_path[-15:] + [pygame.mouse.get_pos()]  # trailing swipe path&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for event in pygame.event.get():
    if event.type == pygame.QUIT:
        pygame.quit()
        sys.exit()

    if game_over and event.type == pygame.MOUSEBUTTONDOWN:
        # restart game
        fruits = []
        score = 0
        game_over = False

    if event.type == SPAWN_EVENT and not game_over:
        spawn_fruit()

if not game_over:
    # Update &amp;amp; draw fruits
    for f in fruits[:]:
        update_fruit(f)
        draw_fruit(f)

        if slice_check(f, mouse_path):
            if f["type"] == "bomb":
                game_over = True
            else:
                score += 1
            fruits.remove(f)

        if f["y"] &amp;gt; HEIGHT + 100:
            fruits.remove(f)

    # Draw swipe trail
    if len(mouse_path) &amp;gt; 1:
        pygame.draw.lines(screen, WHITE, False, mouse_path, 2)

    # Score
    s_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(s_text, (10, 10))

else:
    over_text = font.render("GAME OVER - Click to restart", True, WHITE)
    screen.blit(over_text, (200, HEIGHT // 2))

pygame.display.flip()
clock.tick(60)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Tic Tac Toe#️⃣❎0️⃣</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Wed, 22 Oct 2025 20:33:08 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/tic-tac-toe0-4g1c</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/tic-tac-toe0-4g1c</guid>
      <description>&lt;h1&gt;
  
  
  Tic Tac Toe game in Python
&lt;/h1&gt;

&lt;p&gt;def print_board(board):&lt;br&gt;
    for row in board:&lt;br&gt;
        print(" | ".join(row))&lt;br&gt;
        print("-" * 9)&lt;/p&gt;

&lt;p&gt;def check_winner(board, player):&lt;br&gt;
    # Check rows, columns, and diagonals&lt;br&gt;
    for row in board:&lt;br&gt;
        if all(s == player for s in row):&lt;br&gt;
            return True&lt;br&gt;
    for col in range(3):&lt;br&gt;
        if all(board[row][col] == player for row in range(3)):&lt;br&gt;
            return True&lt;br&gt;
    if all(board[i][i] == player for i in range(3)):&lt;br&gt;
        return True&lt;br&gt;
    if all(board[i][2 - i] == player for i in range(3)):&lt;br&gt;
        return True&lt;br&gt;
    return False&lt;/p&gt;

&lt;p&gt;def is_full(board):&lt;br&gt;
    return all(all(cell != " " for cell in row) for row in board)&lt;/p&gt;

&lt;p&gt;def tic_tac_toe():&lt;br&gt;
    board = [[" " for _ in range(3)] for _ in range(3)]&lt;br&gt;
    current_player = "X"&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while True:&lt;br&gt;
    print_board(board)&lt;br&gt;
    print(f"Player {current_player}'s turn.")
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Ask for move
try:
    row = int(input("Enter row (0-2): "))
    col = int(input("Enter column (0-2): "))
except ValueError:
    print("Please enter a valid number!")
    continue

if row not in range(3) or col not in range(3):
    print("Invalid coordinates! Try again.")
    continue
if board[row][col] != " ":
    print("Cell already taken! Try again.")
    continue

board[row][col] = current_player

if check_winner(board, current_player):
    print_board(board)
    print(f"Player {current_player} wins!")
    break
if is_full(board):
    print_board(board)
    print("It's a tie!")
    break

# Switch player
current_player = "O" if current_player == "X" else "X"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Start the game&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;tic_tac_toe()&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>gamedev</category>
      <category>python</category>
    </item>
    <item>
      <title>Ping Pong 🏓</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Fri, 10 Oct 2025 12:29:31 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/ping-pong-l7i</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/ping-pong-l7i</guid>
      <description>&lt;p&gt;"""&lt;br&gt;
Simple Ping Pong (Pong) game in Python using pygame&lt;/p&gt;

&lt;p&gt;Controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Left paddle: W (up), S (down)&lt;/li&gt;
&lt;li&gt;Right paddle: Up Arrow, Down Arrow&lt;/li&gt;
&lt;li&gt;P to pause, R to reset scores&lt;/li&gt;
&lt;li&gt;Escape or close window to quit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.8+&lt;/li&gt;
&lt;li&gt;pygame (pip install pygame)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run:&lt;br&gt;
  python pong_game.py&lt;/p&gt;

&lt;p&gt;This is a single-file, self-contained implementation with basic sound effects (requires SDL mixer&lt;br&gt;
support available in pygame). It uses simple collision, scoring, and gradual speed increase.&lt;br&gt;
"""&lt;/p&gt;

&lt;p&gt;import pygame&lt;br&gt;
import sys&lt;br&gt;
import random&lt;/p&gt;

&lt;h1&gt;
  
  
  ---- Configuration ----
&lt;/h1&gt;

&lt;p&gt;WIDTH, HEIGHT = 900, 600&lt;br&gt;
FPS = 60&lt;br&gt;
PADDLE_WIDTH, PADDLE_HEIGHT = 10, 100&lt;br&gt;
BALL_SIZE = 16&lt;br&gt;
PADDLE_SPEED = 6&lt;br&gt;
BALL_START_SPEED = 5&lt;br&gt;
SCORE_FONT_SIZE = 48&lt;br&gt;
WINNING_SCORE = 10&lt;/p&gt;

&lt;h1&gt;
  
  
  Colors
&lt;/h1&gt;

&lt;p&gt;WHITE = (255, 255, 255)&lt;br&gt;
BLACK = (0, 0, 0)&lt;/p&gt;

&lt;h1&gt;
  
  
  ---- Classes ----
&lt;/h1&gt;

&lt;p&gt;class Paddle:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, x, y):&lt;br&gt;
        self.rect = pygame.Rect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT)&lt;br&gt;
        self.speed = 0&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def move(self, dy):
    self.speed = dy
    self.rect.y += dy
    # clamp
    if self.rect.top &amp;lt; 0:
        self.rect.top = 0
    if self.rect.bottom &amp;gt; HEIGHT:
        self.rect.bottom = HEIGHT

def update(self):
    self.move(self.speed)

def draw(self, surface):
    pygame.draw.rect(surface, WHITE, self.rect)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;class Ball:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.rect = pygame.Rect((WIDTH // 2) - BALL_SIZE // 2,&lt;br&gt;
                                (HEIGHT // 2) - BALL_SIZE // 2,&lt;br&gt;
                                BALL_SIZE, BALL_SIZE)&lt;br&gt;
        self.reset()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def reset(self, serveto=None):
    self.rect.center = (WIDTH // 2, HEIGHT // 2)
    angle = random.uniform(-0.4, 0.4)  # slight vertical angle
    direction = random.choice([-1, 1]) if serveto is None else serveto
    self.speed = BALL_START_SPEED
    self.vx = direction * self.speed * (1 - abs(angle))
    self.vy = self.speed * angle

def update(self, left_paddle, right_paddle):
    self.rect.x += int(self.vx)
    self.rect.y += int(self.vy)

    # Top/bottom collision
    if self.rect.top &amp;lt;= 0 or self.rect.bottom &amp;gt;= HEIGHT:
        self.vy = -self.vy
        play_sound('wall')

    # Paddle collisions
    if self.rect.colliderect(left_paddle.rect) and self.vx &amp;lt; 0:
        self._bounce(left_paddle)
        play_sound('paddle')

    if self.rect.colliderect(right_paddle.rect) and self.vx &amp;gt; 0:
        self._bounce(right_paddle)
        play_sound('paddle')

def _bounce(self, paddle):
    # Determine hit position on paddle: -1 (top) .. 0 center .. 1 bottom
    rel = (self.rect.centery - paddle.rect.centery) / (paddle.rect.height / 2)
    rel = max(-1, min(1, rel))
    # Increase speed slightly each hit
    self.speed *= 1.05
    # New velocities
    self.vx = -self.vx / abs(self.vx) * self.speed * (1 - 0.5 * abs(rel))
    self.vy = self.speed * rel

def draw(self, surface):
    pygame.draw.ellipse(surface, WHITE, self.rect)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  ---- Sound helper ----
&lt;/h1&gt;

&lt;p&gt;SOUNDS = {}&lt;/p&gt;

&lt;p&gt;def load_sounds():&lt;br&gt;
    try:&lt;br&gt;
        SOUNDS['paddle'] = pygame.mixer.Sound(pygame.mixer.Sound.get_length)&lt;br&gt;
    except Exception:&lt;br&gt;
        # If loading real files isn't desired, we'll skip. Sound optional.&lt;br&gt;
        pass&lt;/p&gt;

&lt;p&gt;def play_sound(name):&lt;br&gt;
    # Keep non-fatal: if sound present, play it. We intentionally keep this minimal.&lt;br&gt;
    s = SOUNDS.get(name)&lt;br&gt;
    if s:&lt;br&gt;
        try:&lt;br&gt;
            s.play()&lt;br&gt;
        except Exception:&lt;br&gt;
            pass&lt;/p&gt;
&lt;h1&gt;
  
  
  ---- Main Game ----
&lt;/h1&gt;

&lt;p&gt;def draw_center_line(surface):&lt;br&gt;
    for y in range(0, HEIGHT, 20):&lt;br&gt;
        pygame.draw.rect(surface, WHITE, (WIDTH // 2 - 1, y, 2, 12))&lt;/p&gt;

&lt;p&gt;def main():&lt;br&gt;
    pygame.init()&lt;br&gt;
    try:&lt;br&gt;
        pygame.mixer.init()&lt;br&gt;
    except Exception:&lt;br&gt;
        pass&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Ping Pong - Python (pygame)')
clock = pygame.time.Clock()

# Score
score_left = 0
score_right = 0

# Entities
left_paddle = Paddle(30, (HEIGHT - PADDLE_HEIGHT) // 2)
right_paddle = Paddle(WIDTH - 30 - PADDLE_WIDTH, (HEIGHT - PADDLE_HEIGHT) // 2)
ball = Ball()

font = pygame.font.Font(None, SCORE_FONT_SIZE)
small_font = pygame.font.Font(None, 24)

paused = False

# Optional simple AI toggle (comment/uncomment to enable)
ai_enabled = False

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
            if event.key == pygame.K_p:
                paused = not paused
            if event.key == pygame.K_r:
                score_left = 0
                score_right = 0
                ball.reset()
            if event.key == pygame.K_a:
                ai_enabled = not ai_enabled

    # Input handling
    keys = pygame.key.get_pressed()
    left_speed = 0
    right_speed = 0
    if keys[pygame.K_w]:
        left_speed = -PADDLE_SPEED
    elif keys[pygame.K_s]:
        left_speed = PADDLE_SPEED

    if not ai_enabled:
        if keys[pygame.K_UP]:
            right_speed = -PADDLE_SPEED
        elif keys[pygame.K_DOWN]:
            right_speed = PADDLE_SPEED
    else:
        # Very simple AI: follow ball with some damping
        if ball.rect.centery &amp;lt; right_paddle.rect.centery - 10:
            right_speed = -PADDLE_SPEED
        elif ball.rect.centery &amp;gt; right_paddle.rect.centery + 10:
            right_speed = PADDLE_SPEED
        else:
            right_speed = 0

    if not paused:
        left_paddle.move(left_speed)
        right_paddle.move(right_speed)
        ball.update(left_paddle, right_paddle)

        # Check scoring
        if ball.rect.right &amp;lt; 0:
            score_right += 1
            ball.reset(serveto=1)
            play_sound('score')

        if ball.rect.left &amp;gt; WIDTH:
            score_left += 1
            ball.reset(serveto=-1)
            play_sound('score')

        # Win condition
        if score_left &amp;gt;= WINNING_SCORE or score_right &amp;gt;= WINNING_SCORE:
            paused = True

    # Draw
    screen.fill(BLACK)
    draw_center_line(screen)
    left_paddle.draw(screen)
    right_paddle.draw(screen)
    ball.draw(screen)

    # Scores
    left_surf = font.render(str(score_left), True, WHITE)
    right_surf = font.render(str(score_right), True, WHITE)
    screen.blit(left_surf, (WIDTH // 4 - left_surf.get_width() // 2, 20))
    screen.blit(right_surf, (WIDTH * 3 // 4 - right_surf.get_width() // 2, 20))

    # Hints
    hint = small_font.render("W/S: left  |  Up/Down: right  |  P: pause  |  R: reset  |  A: toggle AI", True, WHITE)
    screen.blit(hint, (WIDTH // 2 - hint.get_width() // 2, HEIGHT - 30))

    if paused:
        pause_surf = font.render("PAUSED" if not (score_left &amp;gt;= WINNING_SCORE or score_right &amp;gt;= WINNING_SCORE) else "GAME OVER", True, WHITE)
        screen.blit(pause_surf, (WIDTH // 2 - pause_surf.get_width() // 2, HEIGHT // 2 - pause_surf.get_height() // 2))
        if score_left &amp;gt;= WINNING_SCORE or score_right &amp;gt;= WINNING_SCORE:
            winner = 'Left' if score_left &amp;gt; score_right else 'Right'
            win_surf = small_font.render(f"{winner} player wins! Press R to restart.", True, WHITE)
            screen.blit(win_surf, (WIDTH // 2 - win_surf.get_width() // 2, HEIGHT // 2 + 40))

    pygame.display.flip()
    clock.tick(FPS)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == '&lt;strong&gt;main&lt;/strong&gt;':&lt;br&gt;
    main()&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>showdev</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Sudoku</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Fri, 10 Oct 2025 12:27:34 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/sudoku-27i3</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/sudoku-27i3</guid>
      <description>&lt;p&gt;import random&lt;/p&gt;

&lt;p&gt;def print_grid(grid):&lt;br&gt;
    for i in range(9):&lt;br&gt;
        if i % 3 == 0 and i != 0:&lt;br&gt;
            print("-" * 21)&lt;br&gt;
        for j in range(9):&lt;br&gt;
            if j % 3 == 0 and j != 0:&lt;br&gt;
                print("|", end=" ")&lt;br&gt;
            print(grid[i][j] if grid[i][j] != 0 else ".", end=" ")&lt;br&gt;
        print()&lt;/p&gt;

&lt;p&gt;def is_valid(grid, row, col, num):&lt;br&gt;
    # Check row&lt;br&gt;
    if num in grid[row]:&lt;br&gt;
        return False&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Check column
for i in range(9):
    if grid[i][col] == num:
        return False

# Check 3x3 square
start_row, start_col = row - row % 3, col - col % 3
for i in range(3):
    for j in range(3):
        if grid[start_row + i][start_col + j] == num:
            return False
return True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def solve(grid):&lt;br&gt;
    for row in range(9):&lt;br&gt;
        for col in range(9):&lt;br&gt;
            if grid[row][col] == 0:&lt;br&gt;
                for num in range(1, 10):&lt;br&gt;
                    if is_valid(grid, row, col, num):&lt;br&gt;
                        grid[row][col] = num&lt;br&gt;
                        if solve(grid):&lt;br&gt;
                            return True&lt;br&gt;
                        grid[row][col] = 0&lt;br&gt;
                return False&lt;br&gt;
    return True&lt;/p&gt;

&lt;p&gt;def generate_sudoku():&lt;br&gt;
    grid = [[0 for _ in range(9)] for _ in range(9)]&lt;br&gt;
    for _ in range(15):  # Fill some numbers randomly&lt;br&gt;
        row, col = random.randint(0, 8), random.randint(0, 8)&lt;br&gt;
        num = random.randint(1, 9)&lt;br&gt;
        if is_valid(grid, row, col, num):&lt;br&gt;
            grid[row][col] = num&lt;br&gt;
    return grid&lt;/p&gt;

&lt;h1&gt;
  
  
  Game
&lt;/h1&gt;

&lt;p&gt;grid = generate_sudoku()&lt;br&gt;
print("Welcome to Sudoku!")&lt;br&gt;
print_grid(grid)&lt;/p&gt;

&lt;p&gt;while True:&lt;br&gt;
    try:&lt;br&gt;
        row = int(input("Row (0-8): "))&lt;br&gt;
        col = int(input("Col (0-8): "))&lt;br&gt;
        num = int(input("Number (1-9): "))&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    if grid[row][col] == 0 and is_valid(grid, row, col, num):
        grid[row][col] = num
        print_grid(grid)
    else:
        print("Invalid move!")
except ValueError:
    print("Please enter valid integers.")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>algorithms</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>TETRIS TIME 👾</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Wed, 01 Oct 2025 11:17:50 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/tetris-time-7g3</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/tetris-time-7g3</guid>
      <description>&lt;p&gt;"""&lt;br&gt;
Simple Tetris implementation in Python using pygame.&lt;/p&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playable Tetris with 7 tetrominoes&lt;/li&gt;
&lt;li&gt;Rotation, left/right, soft drop, hard drop&lt;/li&gt;
&lt;li&gt;Line clearing and scoring&lt;/li&gt;
&lt;li&gt;Next piece preview and hold&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Left/Right Arrow: move&lt;/li&gt;
&lt;li&gt;Up Arrow or X: rotate clockwise&lt;/li&gt;
&lt;li&gt;Z: rotate counter-clockwise&lt;/li&gt;
&lt;li&gt;Down Arrow: soft drop&lt;/li&gt;
&lt;li&gt;Space: hard drop&lt;/li&gt;
&lt;li&gt;C: hold piece&lt;/li&gt;
&lt;li&gt;P: pause&lt;/li&gt;
&lt;li&gt;Esc / Q: quit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.8+&lt;/li&gt;
&lt;li&gt;pygame (pip install pygame)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save as tetris.py and run: python tetris.py&lt;br&gt;
"""&lt;/p&gt;

&lt;p&gt;import pygame&lt;br&gt;
import random&lt;br&gt;
import sys&lt;br&gt;
from copy import deepcopy&lt;/p&gt;

&lt;h1&gt;
  
  
  ---------- Configuration ----------
&lt;/h1&gt;

&lt;p&gt;FPS = 60&lt;br&gt;
CELL_SIZE = 30&lt;br&gt;
COLS = 10&lt;br&gt;
ROWS = 20&lt;br&gt;
PLAY_WIDTH = COLS * CELL_SIZE&lt;br&gt;
PLAY_HEIGHT = ROWS * CELL_SIZE&lt;br&gt;
SIDE_PANEL = 200&lt;br&gt;
WIDTH = PLAY_WIDTH + SIDE_PANEL + 40&lt;br&gt;
HEIGHT = PLAY_HEIGHT + 40&lt;br&gt;
TOP_LEFT_X = 20&lt;br&gt;
TOP_LEFT_Y = 20&lt;/p&gt;

&lt;h1&gt;
  
  
  Colors
&lt;/h1&gt;

&lt;p&gt;WHITE = (255, 255, 255)&lt;br&gt;
GRAY = (128, 128, 128)&lt;br&gt;
BLACK = (0, 0, 0)&lt;/p&gt;

&lt;p&gt;SHAPE_COLORS = [&lt;br&gt;
    (0, 240, 240),  # I - cyan&lt;br&gt;
    (0, 0, 240),    # J - blue&lt;br&gt;
    (240, 160, 0),  # L - orange&lt;br&gt;
    (240, 240, 0),  # O - yellow&lt;br&gt;
    (0, 240, 0),    # S - green&lt;br&gt;
    (160, 0, 240),  # T - purple&lt;br&gt;
    (240, 0, 0),    # Z - red&lt;br&gt;
]&lt;/p&gt;

&lt;h1&gt;
  
  
  Tetromino shapes (4x4 grids represented by strings)
&lt;/h1&gt;

&lt;p&gt;S = [['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '..00.',&lt;br&gt;
      '.00..',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..00.',&lt;br&gt;
      '...0.',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;Z = [['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.00..',&lt;br&gt;
      '..00.',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.00..',&lt;br&gt;
      '.0...',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;I = [['..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '0000.',&lt;br&gt;
      '.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;O = [['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.00..',&lt;br&gt;
      '.00..',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;J = [['.....',&lt;br&gt;
      '.0...',&lt;br&gt;
      '.000.',&lt;br&gt;
      '.....',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..00.',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.000.',&lt;br&gt;
      '...0.',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.00..',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;L = [['.....',&lt;br&gt;
      '...0.',&lt;br&gt;
      '.000.',&lt;br&gt;
      '.....',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..00.',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.000.',&lt;br&gt;
      '.0...',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '.00..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;T = [['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.000.',&lt;br&gt;
      '.....',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '..00.',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '.....',&lt;br&gt;
      '.000.',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....'],&lt;br&gt;
     ['.....',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.00..',&lt;br&gt;
      '..0..',&lt;br&gt;
      '.....']]&lt;/p&gt;

&lt;p&gt;SHAPES = [S, Z, I, O, J, L, T]&lt;br&gt;
SHAPE_NAMES = ['S', 'Z', 'I', 'O', 'J', 'L', 'T']&lt;/p&gt;

&lt;h1&gt;
  
  
  ---------- Game Logic ----------
&lt;/h1&gt;

&lt;p&gt;class Piece:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, x, y, shape_index):&lt;br&gt;
        self.x = x&lt;br&gt;
        self.y = y&lt;br&gt;
        self.shape_index = shape_index&lt;br&gt;
        self.shape = SHAPES[shape_index]&lt;br&gt;
        self.rotation = 0&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def image(self):
    return self.shape[self.rotation % len(self.shape)]

def get_cells(self):
    """Return list of (x,y) cells occupied by this piece relative to grid."""
    positions = []
    format = self.image()
    for i, line in enumerate(format):
        row = list(line)
        for j, column in enumerate(row):
            if column == '0':
                positions.append((self.x + j - 2, self.y + i - 4))
    return positions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def create_grid(locked_positions={}):&lt;br&gt;
    grid = [[BLACK for _ in range(COLS)] for _ in range(ROWS)]&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(ROWS):
    for j in range(COLS):
        if (j, i) in locked_positions:
            grid[i][j] = locked_positions[(j, i)]
return grid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def valid_space(piece, grid):&lt;br&gt;
    accepted_positions = [[(j, i) for j in range(COLS) if grid[i][j] == BLACK] for i in range(ROWS)]&lt;br&gt;
    accepted = [pos for row in accepted_positions for pos in row]&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for pos in piece.get_cells():
    x, y = pos
    if x &amp;lt; 0 or x &amp;gt;= COLS or y &amp;gt;= ROWS:
        return False
    if y &amp;gt;= 0 and (x, y) not in accepted:
        return False
return True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def check_lost(positions):&lt;br&gt;
    for pos in positions:&lt;br&gt;
        x, y = pos&lt;br&gt;
        if y &amp;lt; 0:&lt;br&gt;
            return True&lt;br&gt;
    return False&lt;/p&gt;

&lt;p&gt;def get_shape():&lt;br&gt;
    index = random.randrange(len(SHAPES))&lt;br&gt;
    return Piece(COLS // 2 - 2, -2, index)&lt;/p&gt;

&lt;p&gt;def convert_shape_format(piece):&lt;br&gt;
    positions = []&lt;br&gt;
    format = piece.image()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i, line in enumerate(format):
    row = list(line)
    for j, column in enumerate(row):
        if column == '0':
            positions.append((piece.x + j - 2, piece.y + i - 4))

return positions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def clear_rows(grid, locked):&lt;br&gt;
    """Check for full rows and clear them. Return number of cleared rows."""&lt;br&gt;
    inc = 0&lt;br&gt;
    for i in range(ROWS - 1, -1, -1):&lt;br&gt;
        row = grid[i]&lt;br&gt;
        if BLACK not in row:&lt;br&gt;
            inc += 1&lt;br&gt;
            # remove from locked&lt;br&gt;
            for j in range(COLS):&lt;br&gt;
                try:&lt;br&gt;
                    del locked[(j, i)]&lt;br&gt;
                except:&lt;br&gt;
                    continue&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if inc &amp;gt; 0:
    # shift every row above down
    new_locked = {}
    for (x, y), color in sorted(locked.items(), key=lambda x: x[0][1]):
        shift = 0
        for _ in range(inc):
            if y &amp;lt; ROWS and True:
                shift += 1
        new_locked[(x, y + inc)] = color
    locked.clear()
    locked.update(new_locked)
return inc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  ---------- Drawing Helpers ----------
&lt;/h1&gt;

&lt;p&gt;def draw_text_middle(surface, text, size, y_offset=0):&lt;br&gt;
    font = pygame.font.SysFont('comicsans', size, bold=True)&lt;br&gt;
    label = font.render(text, 1, WHITE)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH/2 - (label.get_width()/2), TOP_LEFT_Y + PLAY_HEIGHT/2 - label.get_height()/2 + y_offset))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def draw_grid(surface, grid):&lt;br&gt;
    sx = TOP_LEFT_X&lt;br&gt;
    sy = TOP_LEFT_Y&lt;br&gt;
    for i in range(ROWS):&lt;br&gt;
        pygame.draw.line(surface, GRAY, (sx, sy + i * CELL_SIZE), (sx + PLAY_WIDTH, sy + i * CELL_SIZE))&lt;br&gt;
        for j in range(COLS):&lt;br&gt;
            pygame.draw.line(surface, GRAY, (sx + j * CELL_SIZE, sy), (sx + j * CELL_SIZE, sy + PLAY_HEIGHT))&lt;/p&gt;

&lt;p&gt;def draw_window(surface, grid, score=0, level=1):&lt;br&gt;
    surface.fill(BLACK)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Title
font = pygame.font.SysFont('comicsans', 40)
label = font.render('TETRIS', 1, WHITE)

surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH/2 - label.get_width()/2, 5))

# Score
font_small = pygame.font.SysFont('comicsans', 24)
score_label = font_small.render(f'Score: {score}', 1, WHITE)
level_label = font_small.render(f'Level: {level}', 1, WHITE)
surface.blit(score_label, (TOP_LEFT_X + PLAY_WIDTH + 20, TOP_LEFT_Y + 50))
surface.blit(level_label, (TOP_LEFT_X + PLAY_WIDTH + 20, TOP_LEFT_Y + 90))

# draw play area
sx = TOP_LEFT_X
sy = TOP_LEFT_Y

for i in range(ROWS):
    for j in range(COLS):
        pygame.draw.rect(surface, grid[i][j], (sx + j * CELL_SIZE, sy + i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 0)

# draw grid lines
draw_grid(surface, grid)

# border
pygame.draw.rect(surface, WHITE, (sx, sy, PLAY_WIDTH, PLAY_HEIGHT), 4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def draw_next_shape(surface, shape):&lt;br&gt;
    font = pygame.font.SysFont('comicsans', 24)&lt;br&gt;
    label = font.render('Next', 1, WHITE)&lt;br&gt;
    surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH + 20, TOP_LEFT_Y + 140))&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;format = shape.image()
sx = TOP_LEFT_X + PLAY_WIDTH + 50
sy = TOP_LEFT_Y + 170

for i, line in enumerate(format):
    row = list(line)
    for j, column in enumerate(row):
        if column == '0':
            pygame.draw.rect(surface, SHAPE_COLORS[shape.shape_index], (sx + j * CELL_SIZE, sy + i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def draw_hold_shape(surface, shape):&lt;br&gt;
    font = pygame.font.SysFont('comicsans', 24)&lt;br&gt;
    label = font.render('Hold', 1, WHITE)&lt;br&gt;
    surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH + 20, TOP_LEFT_Y + 260))&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if not shape:
    return

format = shape.image()
sx = TOP_LEFT_X + PLAY_WIDTH + 50
sy = TOP_LEFT_Y + 300

for i, line in enumerate(format):
    row = list(line)
    for j, column in enumerate(row):
        if column == '0':
            pygame.draw.rect(surface, SHAPE_COLORS[shape.shape_index], (sx + j * CELL_SIZE, sy + i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  ---------- Main Game Loop ----------
&lt;/h1&gt;

&lt;p&gt;def main():&lt;br&gt;
    pygame.init()&lt;br&gt;
    win = pygame.display.set_mode((WIDTH, HEIGHT))&lt;br&gt;
    pygame.display.set_caption('Tetris')&lt;br&gt;
    clock = pygame.time.Clock()&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;locked_positions = {}
grid = create_grid(locked_positions)

change_piece = False
run = True
current_piece = get_shape()
next_piece = get_shape()
hold_piece = None
hold_locked = False

fall_time = 0
fall_speed = 0.5  # seconds per cell fall
level = 1
score = 0
lines_cleared_total = 0

while run:
    grid = create_grid(locked_positions)
    dt = clock.tick(FPS) / 1000.0
    fall_time += dt

    # handle fall speed acceleration by level
    if lines_cleared_total &amp;gt;= level * 10:
        level += 1
        fall_speed = max(0.05, fall_speed * 0.9)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
                run = False
                pygame.quit()
                sys.exit()

            if event.key == pygame.K_LEFT:
                current_piece.x -= 1
                if not valid_space(current_piece, grid):
                    current_piece.x += 1

            elif event.key == pygame.K_RIGHT:
                current_piece.x += 1
                if not valid_space(current_piece, grid):
                    current_piece.x -= 1

            elif event.key == pygame.K_DOWN:
                current_piece.y += 1
                if not valid_space(current_piece, grid):
                    current_piece.y -= 1

            elif event.key == pygame.K_UP or event.key == pygame.K_x:
                current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                if not valid_space(current_piece, grid):
                    current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)

            elif event.key == pygame.K_z:
                current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                if not valid_space(current_piece, grid):
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)

            elif event.key == pygame.K_SPACE:
                # hard drop
                while valid_space(current_piece, grid):
                    current_piece.y += 1
                current_piece.y -= 1
                change_piece = True

            elif event.key == pygame.K_c:
                if not hold_locked:
                    if hold_piece is None:
                        hold_piece = Piece(COLS//2 - 2, -2, current_piece.shape_index)
                        current_piece = next_piece
                        next_piece = get_shape()
                    else:
                        temp = Piece(COLS//2 - 2, -2, current_piece.shape_index)
                        current_piece = Piece(COLS//2 - 2, -2, hold_piece.shape_index)
                        hold_piece = Piece(COLS//2 - 2, -2, temp.shape_index)
                    hold_locked = True

            elif event.key == pygame.K_p:
                paused = True
                while paused:
                    for e in pygame.event.get():
                        if e.type == pygame.QUIT:
                            pygame.quit()
                            sys.exit()
                        if e.type == pygame.KEYDOWN and e.key == pygame.K_p:
                            paused = False

    # automatic piece fall
    if fall_time &amp;gt;= fall_speed:
        fall_time = 0
        current_piece.y += 1
        if not valid_space(current_piece, grid):
            current_piece.y -= 1
            change_piece = True

    shape_pos = convert_shape_format(current_piece)

    # add piece to the grid for drawing
    for i in range(len(shape_pos)):
        x, y = shape_pos[i]
        if y &amp;gt;= 0:
            grid[y][x] = SHAPE_COLORS[current_piece.shape_index]

    # when piece lands
    if change_piece:
        for pos in shape_pos:
            p = (pos[0], pos[1])
            locked_positions[p] = SHAPE_COLORS[current_piece.shape_index]
        current_piece = next_piece
        next_piece = get_shape()
        change_piece = False
        hold_locked = False

        # clear rows
        cleared = clear_rows(grid, locked_positions)
        if cleared &amp;gt; 0:
            lines_cleared_total += cleared
            # scoring (classic-ish)
            if cleared == 1:
                score += 40 * level
            elif cleared == 2:
                score += 100 * level
            elif cleared == 3:
                score += 300 * level
            elif cleared &amp;gt;= 4:
                score += 1200 * level

    draw_window(win, grid, score, level)
    draw_next_shape(win, next_piece)
    draw_hold_shape(win, hold_piece)

    if check_lost(list(locked_positions.keys())):
        draw_text_middle(win, 'GAME OVER', 50)
        pygame.display.update()
        pygame.time.delay(1500)
        run = False

    pygame.display.update()

pygame.quit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == '&lt;strong&gt;main&lt;/strong&gt;':&lt;br&gt;
    main()&lt;/p&gt;

&lt;p&gt;"""&lt;br&gt;
runnable Python file named tetris.py in a code canvas. It uses pygame and includes:&lt;/p&gt;

&lt;p&gt;All 7 tetrominoes with rotation and collision handling&lt;/p&gt;

&lt;p&gt;Left / right movement, soft drop, hard drop, rotate (CW/CCW)&lt;/p&gt;

&lt;p&gt;Hold piece, next-piece preview, scoring, levels, and game-over detection&lt;/p&gt;

&lt;p&gt;Pause, quit, and simple UI&lt;/p&gt;

&lt;p&gt;How to run:&lt;/p&gt;

&lt;p&gt;Install pygame if you don't have it: pip install pygame&lt;/p&gt;

&lt;p&gt;Save the canvas file as tetris.py (it's already created in the code canvas) and run:&lt;br&gt;
python tetris.py&lt;/p&gt;

&lt;p&gt;Controls recap:&lt;/p&gt;

&lt;p&gt;Left / Right arrows: move&lt;/p&gt;

&lt;p&gt;Down arrow: soft drop&lt;/p&gt;

&lt;p&gt;Space: hard drop&lt;/p&gt;

&lt;p&gt;Up arrow or X: rotate clockwise&lt;/p&gt;

&lt;p&gt;Z: rotate counter-clockwise&lt;/p&gt;

&lt;p&gt;C: hold piece&lt;/p&gt;

&lt;p&gt;P: pause&lt;/p&gt;

&lt;p&gt;Esc or Q: quit&lt;br&gt;
"""&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Snake Game 🐍</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Thu, 18 Sep 2025 16:42:58 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/snake-game-5fi0</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/snake-game-5fi0</guid>
      <description>&lt;h1&gt;
  
  
  before running the game please do install dependencies in requirements.txt file
&lt;/h1&gt;

&lt;p&gt;import os&lt;br&gt;
import sys&lt;/p&gt;

&lt;h1&gt;
  
  
  Use psycopg2 only (simpler for beginners)
&lt;/h1&gt;

&lt;p&gt;try:&lt;br&gt;
    import psycopg2 as pg&lt;br&gt;
except ImportError:&lt;br&gt;
    print("Missing dependency: psycopg2-binary")&lt;br&gt;
    print("Please run: pip install psycopg2-binary")&lt;br&gt;
    sys.exit(1)&lt;/p&gt;

&lt;p&gt;DB_PARAMS = {&lt;br&gt;
    'dbname': os.getenv('PGDATABASE', 'postgres'),&lt;br&gt;
    'user': os.getenv('PGUSER', 'postgres'),&lt;br&gt;
    'password': os.getenv('PGPASSWORD', 'postgres'),&lt;br&gt;
    'host': os.getenv('PGHOST', 'localhost'),&lt;br&gt;
    'port': int(os.getenv('PGPORT', '5432')),&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def connect():&lt;br&gt;
    return pg.connect(**DB_PARAMS)&lt;/p&gt;

&lt;p&gt;def init_game(rows=10, cols=20):&lt;br&gt;
    with connect() as conn, conn.cursor() as cur:&lt;br&gt;
        cur.execute("SELECT init_game(%s,%s)", (rows, cols))&lt;br&gt;
        gid = cur.fetchone()[0]&lt;br&gt;
        return gid&lt;/p&gt;

&lt;p&gt;def get_board(gid):&lt;br&gt;
    with connect() as conn, conn.cursor() as cur:&lt;br&gt;
        cur.execute("SELECT get_board(%s)", (gid,))&lt;br&gt;
        return cur.fetchone()[0]&lt;/p&gt;

&lt;p&gt;def step(gid, direction):&lt;br&gt;
    with connect() as conn, conn.cursor() as cur:&lt;br&gt;
        cur.execute("SELECT step(%s,%s)::text", (gid, direction))&lt;br&gt;
        return cur.fetchone()[0]&lt;/p&gt;

&lt;p&gt;KEY_TO_DIR = {&lt;br&gt;
    'w': 'U',&lt;br&gt;
    's': 'D',&lt;br&gt;
    'a': 'L',&lt;br&gt;
    'd': 'R',&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def read_key():&lt;br&gt;
    """Read a single keypress from stdin (Linux/Mac)."""&lt;br&gt;
    import termios, tty&lt;br&gt;
    fd = sys.stdin.fileno()&lt;br&gt;
    old_settings = termios.tcgetattr(fd)&lt;br&gt;
    try:&lt;br&gt;
        tty.setraw(fd)&lt;br&gt;
        ch = sys.stdin.read(1)&lt;br&gt;
    finally:&lt;br&gt;
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)&lt;br&gt;
    return ch&lt;/p&gt;

&lt;p&gt;def main():&lt;br&gt;
    print("Starting new SQL Snake game...")&lt;br&gt;
    gid = init_game(10, 20)&lt;br&gt;
    print(f"Game id: {gid}\n")&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current_dir = 'R'

while True:
    os.system('clear')
    print(get_board(gid))
    print("Use WASD keys to move, q to quit.")

    ch = read_key()
    if ch == 'q':
        print("Quitting.")
        break
    if ch in KEY_TO_DIR:
        current_dir = KEY_TO_DIR[ch]

    status = step(gid, current_dir)
    if 'dead' in status:
        os.system('clear')
        print(get_board(gid))
        print("Game over! Final status:", status)
        break
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    main()&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rock 🗿 Paper 🗞️ Scissors ✂️</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Mon, 15 Sep 2025 09:51:35 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/rock-paper-scissors-2g23</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/rock-paper-scissors-2g23</guid>
      <description>&lt;p&gt;Rock 🗿 Paper 🗞️ Scissors ✂️ - the classic hand game where:&lt;/p&gt;

&lt;p&gt;Rock beats Scissors (crushes them)&lt;br&gt;
Scissors beat Paper (cut it)&lt;br&gt;
Paper beats Rock (wraps it)&lt;/p&gt;

&lt;p&gt;enhanced version of Rock–Paper–Scissors in Python where you can play multiple rounds, keep score, and even choose when to quit:&lt;/p&gt;

&lt;p&gt;import random&lt;/p&gt;

&lt;h1&gt;
  
  
  Choices available
&lt;/h1&gt;

&lt;p&gt;choices = ["rock", "paper", "scissors"]&lt;/p&gt;

&lt;h1&gt;
  
  
  Function to determine the winner
&lt;/h1&gt;

&lt;p&gt;def determine_winner(user_choice, computer_choice):&lt;br&gt;
    if user_choice == computer_choice:&lt;br&gt;
        return "tie"&lt;br&gt;
    elif (user_choice == "rock" and computer_choice == "scissors") or \&lt;br&gt;
         (user_choice == "scissors" and computer_choice == "paper") or \&lt;br&gt;
         (user_choice == "paper" and computer_choice == "rock"):&lt;br&gt;
        return "user"&lt;br&gt;
    else:&lt;br&gt;
        return "computer"&lt;/p&gt;

&lt;h1&gt;
  
  
  Main game loop
&lt;/h1&gt;

&lt;p&gt;def play_game():&lt;br&gt;
    user_score = 0&lt;br&gt;
    computer_score = 0&lt;br&gt;
    round_number = 1&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print("Welcome to Rock-Paper-Scissors!")&lt;br&gt;
print("Type 'quit' to exit the game anytime.\n")

&lt;p&gt;while True:&lt;br&gt;
    print(f"--- Round {round_number} ---")&lt;br&gt;
    user_choice = input("Enter rock, paper, or scissors: ").lower()&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if user_choice == "quit":
    break

if user_choice not in choices:
    print("Invalid choice. Try again.\n")
    continue

computer_choice = random.choice(choices)
print(f"Computer chose: {computer_choice}")

winner = determine_winner(user_choice, computer_choice)
if winner == "user":
    print("You win this round!\n")
    user_score += 1
elif winner == "computer":
    print("Computer wins this round!\n")
    computer_score += 1
else:
    print("This round is a tie!\n")

print(f"Score -&amp;amp;gt; You: {user_score} | Computer: {computer_score}\n")
round_number += 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;print("Thanks for playing!")&lt;br&gt;
print(f"Final Score -&amp;gt; You: {user_score} | Computer: {computer_score}")&lt;br&gt;
if user_score &amp;gt; computer_score:&lt;br&gt;
    print("You won the game! 🎉")&lt;br&gt;
elif user_score &amp;lt; computer_score:&lt;br&gt;
    print("Computer won the game! 🤖")&lt;br&gt;
else:&lt;br&gt;
    print("It's a tie overall!")&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Start the game&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;play_game()&lt;/p&gt;

&lt;p&gt;✅ Features:&lt;/p&gt;

&lt;p&gt;Multiple rounds until the user quits.&lt;br&gt;
Keeps track of your score and the computer’s score.&lt;br&gt;
Declares the overall winner at the end.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>SQL PUZZLE GAME</title>
      <dc:creator>Marcelo Martins</dc:creator>
      <pubDate>Wed, 10 Sep 2025 13:41:54 +0000</pubDate>
      <link>https://forem.com/marcelo_martins_41c7f1c95/sql-puzzle-game-43fp</link>
      <guid>https://forem.com/marcelo_martins_41c7f1c95/sql-puzzle-game-43fp</guid>
      <description>&lt;h1&gt;
  
  
  DataBricks SQL experience for measuring 4L of water with 2 bukcets one with 5L capacity and other with 3L capacity
&lt;/h1&gt;

&lt;p&gt;-- Possible Tables&lt;br&gt;
CREATE TABLE Buckets (&lt;br&gt;
    step INT PRIMARY KEY,&lt;br&gt;
    action VARCHAR(50),&lt;br&gt;
    bucket5 INT,&lt;br&gt;
    bucket3 INT&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;-- method &lt;br&gt;
INSERT INTO Bucket VALUES&lt;br&gt;
(1, 'Fill 5L'          ,                 5, 0),&lt;br&gt;
(2, 'Transfer 5L to 3L',                 2, 3),&lt;br&gt;
(3, 'Empty  3L'        ,                 2, 0),&lt;br&gt;
(4, 'Transfer 2L to 3L',                 0, 2),&lt;br&gt;
(5, 'Fill 5L'          ,                 5, 2),&lt;br&gt;
(6, 'Transfer 5L to 3L',                 4, 3);&lt;/p&gt;

&lt;p&gt;-- consult final solution (4 l on the bucket of 5L)&lt;br&gt;
SELECT *&lt;br&gt;
FROM Buckets&lt;br&gt;
WHERE bucket5 = 4;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
