#pragma once // Auto-generated pico games static const char game_2048_lua_src[] = "-- NAME: 2048\n" "-- DESC: Merge tiles to reach 2048\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "local STATE_WIN = 3\n" "\n" "-- Game constants\n" "local GRID_SIZE = 4\n" "\n" "-- Calculate tile size based on screen size\n" "local function get_tile_size()\n" " -- Use smallest dimension for square grid\n" " local min_dim = math.min(game.width(), game.height())\n" " local padding = math.floor(min_dim / 8)\n" " local available = min_dim - (padding * 2)\n" " local tile_size = math.floor(available / GRID_SIZE)\n" " return tile_size\n" "end\n" "\n" "local function get_grid_start_x()\n" " local tile_size = get_tile_size()\n" " local grid_width = tile_size * GRID_SIZE\n" " return math.floor((game.width() - grid_width) / 2)\n" "end\n" "\n" "local function get_grid_start_y()\n" " local tile_size = get_tile_size()\n" " local grid_height = tile_size * GRID_SIZE\n" " return math.floor((game.height() - grid_height) / 2)\n" "end\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " \n" " -- Grid (4x4, 0 = empty)\n" " game.vars.grid = {}\n" " for y = 1, GRID_SIZE do\n" " game.vars.grid[y] = {}\n" " for x = 1, GRID_SIZE do\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " \n" " game.vars.moved = false\n" " game.vars.won = false\n" " \n" " -- Enable continuous updates\n" " -- game.set_frame_updates(true)\n" " \n" " print(\"2048 initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " if event.type == INPUT.TOUCH_DOWN then\n" " -- Determine swipe direction\n" " local direction = get_swipe_direction(event.x, event.y)\n" " if direction then\n" " game.vars.moved = false\n" " move_tiles(direction)\n" " \n" " if game.vars.moved then\n" " spawn_tile()\n" " \n" " -- Check win/lose\n" " if has_tile(2048) then\n" " if not game.vars.won then\n" " game.vars.state = STATE_WIN\n" " game.vars.won = true\n" " end\n" " end\n" " \n" " if not can_move() then\n" " game.vars.state = STATE_GAME_OVER\n" " end\n" " \n" " return true\n" " end\n" " end\n" " end\n" " \n" " elseif state == STATE_WIN then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " -- Can continue playing or go to menu\n" " if event.y < game.height() / 2 then\n" " game.vars.state = STATE_PLAYING\n" " else\n" " game.vars.state = STATE_MENU\n" " end\n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" " \n" " local state = game.vars.state\n" " local tile_size = get_tile_size()\n" " local start_x = get_grid_start_x()\n" " local start_y = get_grid_start_y()\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 15, game.height() / 2 - 30, \"2048\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 30, \"Welcome Adolfo\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_WIN or state == STATE_GAME_OVER then\n" " -- Draw grid\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " local tile_x = start_x + (x - 1) * tile_size\n" " local tile_y = start_y + (y - 1) * tile_size\n" " local value = game.vars.grid[y][x]\n" " \n" " if value == 0 then\n" " -- Empty tile\n" " renderer.rect(tile_x, tile_y, tile_size, tile_size, true, false)\n" " else\n" " local reduce_size\n" " if value == 2 then\n" " reduce_size = 10\n" " elseif value == 4 then\n" " reduce_size = 8\n" " elseif value == 8 then\n" " reduce_size = 6\n" " elseif value == 16 then\n" " reduce_size = 4\n" " elseif value == 32 then\n" " reduce_size = 2\n" " else\n" " reduce_size = 0\n" " end\n" " -- Empty tile\n" " renderer.rect(tile_x, tile_y, tile_size, tile_size, true, false)\n" " -- Filled tile\n" " renderer.rect(tile_x+reduce_size, tile_y+reduce_size, tile_size-reduce_size*2, tile_size-reduce_size*2, true, true)\n" " \n" " -- Draw value (simplified)\n" " local text = tostring(value)\n" " if string.len(text) < 2 then\n" " renderer.text_scaled(tile_x + tile_size / 2 - 4, tile_y + tile_size / 2 - 8, text, false, 2)\n" " else\n" " renderer.text_scaled(tile_x + tile_size / 2 - 12, tile_y + tile_size / 2 - 8, text, false, 2)\n" " end\n" " end\n" " end\n" " end\n" " \n" " -- Draw score\n" " renderer.text_scaled(10, 10, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " \n" " if state == STATE_WIN then\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2 - 20, \"YOU WIN!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2, \"Tap up: Continue\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 15, \"Tap down: Menu\", true, 2)\n" " end\n" " \n" " if state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2 + 15, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 30, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function get_swipe_direction(x, y)\n" " -- Simple tap-based direction (could be enhanced with swipe tracking)\n" " local mid_x = game.width() / 2\n" " local mid_y = game.height() / 2\n" " \n" " local dx = x - mid_x\n" " local dy = y - mid_y\n" " \n" " if math.abs(dx) > math.abs(dy) then\n" " if dx > 0 then return \"right\" end\n" " return \"left\"\n" " else\n" " if dy > 0 then return \"down\" end\n" " return \"up\"\n" " end\n" "end\n" "\n" "function move_tiles(direction)\n" " local old_grid = {}\n" " for y = 1, GRID_SIZE do\n" " old_grid[y] = {}\n" " for x = 1, GRID_SIZE do\n" " old_grid[y][x] = game.vars.grid[y][x]\n" " end\n" " end\n" " \n" " if direction == \"left\" then\n" " move_left()\n" " elseif direction == \"right\" then\n" " move_right()\n" " elseif direction == \"up\" then\n" " move_up()\n" " elseif direction == \"down\" then\n" " move_down()\n" " end\n" " \n" " -- Check if grid changed\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " if old_grid[y][x] ~= game.vars.grid[y][x] then\n" " game.vars.moved = true\n" " return\n" " end\n" " end\n" " end\n" "end\n" "\n" "function move_left()\n" " for y = 1, GRID_SIZE do\n" " -- Compact\n" " local row = {}\n" " for x = 1, GRID_SIZE do\n" " if game.vars.grid[y][x] ~= 0 then\n" " table.insert(row, game.vars.grid[y][x])\n" " end\n" " end\n" " \n" " -- Merge\n" " local i = 1\n" " while i < #row do\n" " if row[i] == row[i + 1] then\n" " row[i] = row[i] * 2\n" " game.vars.score = game.vars.score + row[i]\n" " table.remove(row, i + 1)\n" " end\n" " i = i + 1\n" " end\n" " \n" " -- Fill back\n" " for x = 1, GRID_SIZE do\n" " if x <= #row then\n" " game.vars.grid[y][x] = row[x]\n" " else\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " end\n" "end\n" "\n" "function move_right()\n" " for y = 1, GRID_SIZE do\n" " local row = {}\n" " for x = GRID_SIZE, 1, -1 do\n" " if game.vars.grid[y][x] ~= 0 then\n" " table.insert(row, game.vars.grid[y][x])\n" " end\n" " end\n" " \n" " local i = 1\n" " while i < #row do\n" " if row[i] == row[i + 1] then\n" " row[i] = row[i] * 2\n" " game.vars.score = game.vars.score + row[i]\n" " table.remove(row, i + 1)\n" " end\n" " i = i + 1\n" " end\n" " \n" " for x = GRID_SIZE, 1, -1 do\n" " if GRID_SIZE - x + 1 <= #row then\n" " game.vars.grid[y][x] = row[GRID_SIZE - x + 1]\n" " else\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " end\n" "end\n" "\n" "function move_up()\n" " for x = 1, GRID_SIZE do\n" " local col = {}\n" " for y = 1, GRID_SIZE do\n" " if game.vars.grid[y][x] ~= 0 then\n" " table.insert(col, game.vars.grid[y][x])\n" " end\n" " end\n" " \n" " local i = 1\n" " while i < #col do\n" " if col[i] == col[i + 1] then\n" " col[i] = col[i] * 2\n" " game.vars.score = game.vars.score + col[i]\n" " table.remove(col, i + 1)\n" " end\n" " i = i + 1\n" " end\n" " \n" " for y = 1, GRID_SIZE do\n" " if y <= #col then\n" " game.vars.grid[y][x] = col[y]\n" " else\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " end\n" "end\n" "\n" "function move_down()\n" " for x = 1, GRID_SIZE do\n" " local col = {}\n" " for y = GRID_SIZE, 1, -1 do\n" " if game.vars.grid[y][x] ~= 0 then\n" " table.insert(col, game.vars.grid[y][x])\n" " end\n" " end\n" " \n" " local i = 1\n" " while i < #col do\n" " if col[i] == col[i + 1] then\n" " col[i] = col[i] * 2\n" " game.vars.score = game.vars.score + col[i]\n" " table.remove(col, i + 1)\n" " end\n" " i = i + 1\n" " end\n" " \n" " for y = GRID_SIZE, 1, -1 do\n" " if GRID_SIZE - y + 1 <= #col then\n" " game.vars.grid[y][x] = col[GRID_SIZE - y + 1]\n" " else\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " end\n" "end\n" "\n" "function spawn_tile()\n" " local empty = {}\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " if game.vars.grid[y][x] == 0 then\n" " table.insert(empty, {x = x, y = y})\n" " end\n" " end\n" " end\n" " \n" " if #empty > 0 then\n" " local pos = empty[math.random(1, #empty)]\n" " game.vars.grid[pos.y][pos.x] = math.random() > 0.9 and 4 or 2\n" " end\n" "end\n" "\n" "function has_tile(value)\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " if game.vars.grid[y][x] == value then\n" " return true\n" " end\n" " end\n" " end\n" " return false\n" "end\n" "\n" "function can_move()\n" " -- Check if any empty tiles\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " if game.vars.grid[y][x] == 0 then\n" " return true\n" " end\n" " end\n" " end\n" " \n" " -- Check if any merges possible\n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " local val = game.vars.grid[y][x]\n" " if x < GRID_SIZE and game.vars.grid[y][x + 1] == val then return true end\n" " if y < GRID_SIZE and game.vars.grid[y + 1][x] == val then return true end\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.won = false\n" " \n" " for y = 1, GRID_SIZE do\n" " for x = 1, GRID_SIZE do\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " \n" " spawn_tile()\n" " spawn_tile()\n" "end\n" ""; static const char air_hockey_lua_src[] = "-- NAME: Air Hockey\n" "-- DESC: Fast-paced 2-player hockey\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local PADDLE_WIDTH = 6\n" "local PADDLE_HEIGHT = 35\n" "local PUCK_RADIUS = 3\n" "local MAX_SCORE = 7\n" "local PUCK_SPEED = 4\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " \n" " -- Left paddle (player 1)\n" " game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_left_score = 0\n" " \n" " -- Right paddle (player 2)\n" " game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_right_score = 0\n" " \n" " -- Puck\n" " game.vars.puck_x = game.width() / 2\n" " game.vars.puck_y = game.height() / 2\n" " game.vars.puck_vel_x = PUCK_SPEED\n" " game.vars.puck_vel_y = 1\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Air Hockey initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle paddle input via touch\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then\n" " if event.x < game.width() / 2 then\n" " -- Left paddle\n" " game.vars.paddle_left_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))\n" " else\n" " -- Right paddle\n" " game.vars.paddle_right_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))\n" " end\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_puck()\n" " check_collisions()\n" " \n" " -- Check win\n" " if game.vars.paddle_left_score >= MAX_SCORE or game.vars.paddle_right_score >= MAX_SCORE then\n" " game.vars.state = STATE_GAME_OVER\n" " end\n" " \n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 35, game.height() / 2 - 30, \"AIR HOCKEY\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"First to \" .. tostring(MAX_SCORE), true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_GAME_OVER then\n" " -- Draw center line\n" " for y = 0, game.height(), 4 do\n" " renderer.pixel(game.width() / 2, y, true)\n" " end\n" " \n" " -- Draw goal areas (top/bottom highlights)\n" " renderer.line(0, 5, game.width(), 5, true, 1)\n" " renderer.line(0, game.height() - 5, game.width(), game.height() - 5, true, 1)\n" " \n" " -- Draw paddles\n" " renderer.rect(5, game.vars.paddle_left_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)\n" " renderer.rect(game.width() - 5 - PADDLE_WIDTH, game.vars.paddle_right_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)\n" " \n" " -- Draw puck (convert to integers)\n" " renderer.circle(math.floor(game.vars.puck_x + 0.5), math.floor(game.vars.puck_y + 0.5), PUCK_RADIUS, true, true)\n" " \n" " -- Draw scores\n" " renderer.text_scaled(game.width() / 2 - 30, 5, tostring(game.vars.paddle_left_score), true, 2)\n" " renderer.text_scaled(game.width() / 2 + 20, 5, tostring(game.vars.paddle_right_score), true, 2)\n" " \n" " if state == STATE_GAME_OVER then\n" " local winner = game.vars.paddle_left_score > game.vars.paddle_right_score and \"Player 1\" or \"Player 2\"\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 20, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2, winner .. \" Wins!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function update_puck()\n" " -- Move puck\n" " game.vars.puck_x = game.vars.puck_x + game.vars.puck_vel_x\n" " game.vars.puck_y = game.vars.puck_y + game.vars.puck_vel_y\n" " \n" " -- Bounce off top/bottom\n" " if game.vars.puck_y - PUCK_RADIUS < 0 or game.vars.puck_y + PUCK_RADIUS > game.height() then\n" " game.vars.puck_vel_y = -game.vars.puck_vel_y\n" " game.vars.puck_y = math.max(PUCK_RADIUS, math.min(game.height() - PUCK_RADIUS, game.vars.puck_y))\n" " end\n" " \n" " -- Goal: left side\n" " if game.vars.puck_x < 0 then\n" " game.vars.paddle_right_score = game.vars.paddle_right_score + 1\n" " reset_puck()\n" " end\n" " \n" " -- Goal: right side\n" " if game.vars.puck_x > game.width() then\n" " game.vars.paddle_left_score = game.vars.paddle_left_score + 1\n" " reset_puck()\n" " end\n" "end\n" "\n" "function check_collisions()\n" " -- Left paddle collision\n" " if game.vars.puck_x - PUCK_RADIUS < 5 + PADDLE_WIDTH then\n" " if game.vars.puck_y > game.vars.paddle_left_y and game.vars.puck_y < game.vars.paddle_left_y + PADDLE_HEIGHT then\n" " if game.vars.puck_vel_x < 0 then\n" " game.vars.puck_vel_x = -game.vars.puck_vel_x + 0.5 -- Speed up slightly\n" " \n" " -- Add spin\n" " local hit_pos = (game.vars.puck_y - game.vars.paddle_left_y) / PADDLE_HEIGHT\n" " game.vars.puck_vel_y = (hit_pos - 0.5) * 6\n" " end\n" " end\n" " end\n" " \n" " -- Right paddle collision\n" " if game.vars.puck_x + PUCK_RADIUS > game.width() - 5 - PADDLE_WIDTH then\n" " if game.vars.puck_y > game.vars.paddle_right_y and game.vars.puck_y < game.vars.paddle_right_y + PADDLE_HEIGHT then\n" " if game.vars.puck_vel_x > 0 then\n" " game.vars.puck_vel_x = -game.vars.puck_vel_x - 0.5 -- Speed up slightly\n" " \n" " -- Add spin\n" " local hit_pos = (game.vars.puck_y - game.vars.paddle_right_y) / PADDLE_HEIGHT\n" " game.vars.puck_vel_y = (hit_pos - 0.5) * 6\n" " end\n" " end\n" " end\n" "end\n" "\n" "function reset_puck()\n" " game.vars.puck_x = game.width() / 2\n" " game.vars.puck_y = game.height() / 2\n" " game.vars.puck_vel_x = PUCK_SPEED * (math.random() > 0.5 and 1 or -1)\n" " game.vars.puck_vel_y = (math.random() - 0.5) * 2\n" "end\n" "\n" "function reset_game()\n" " game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_left_score = 0\n" " game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_right_score = 0\n" " reset_puck()\n" "end\n" ""; static const char asteroids_lua_src[] = "-- NAME: Asteroids\n" "-- DESC: Destroy asteroids, avoid collisions\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local SHIP_SPEED = 2\n" "local SHIP_ROTATION_SPEED = 8\n" "local BULLET_SPEED = 5\n" "local ASTEROID_SPAWN_RATE = 120\n" "local ASTEROID_SPEEDS = {1.5, 2, 2.5, 3}\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.level = 1\n" " \n" " -- Ship\n" " game.vars.ship_x = game.width() / 2\n" " game.vars.ship_y = game.height() / 2\n" " game.vars.ship_angle = 0 -- Radians\n" " game.vars.ship_vel_x = 0\n" " game.vars.ship_vel_y = 0\n" " game.vars.thrusting = false\n" " \n" " -- Bullets\n" " game.vars.bullets = {}\n" " game.vars.bullet_cooldown = 0\n" " \n" " -- Asteroids\n" " game.vars.asteroids = {}\n" " game.vars.frame_count = 0\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Asteroids initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle input\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then\n" " if event.x < game.width() / 2 then\n" " -- Left side: rotate counter-clockwise\n" " game.vars.ship_angle = game.vars.ship_angle - SHIP_ROTATION_SPEED * 0.017\n" " else\n" " -- Right side: rotate clockwise\n" " game.vars.ship_angle = game.vars.ship_angle + SHIP_ROTATION_SPEED * 0.017\n" " end\n" " \n" " -- Thrust\n" " game.vars.thrusting = true\n" " else\n" " game.vars.thrusting = false\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_ship()\n" " update_bullets()\n" " update_asteroids()\n" " check_collisions()\n" " \n" " -- Spawn asteroids\n" " game.vars.frame_count = game.vars.frame_count + 1\n" " if game.vars.frame_count >= ASTEROID_SPAWN_RATE then\n" " spawn_asteroid(game.width() / 2, game.height() / 2, 3)\n" " game.vars.frame_count = 0\n" " end\n" " \n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 35, game.height() / 2 - 30, \"ASTEROIDS\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_GAME_OVER then\n" " -- Draw asteroids (convert to integers)\n" " for i = 1, #game.vars.asteroids do\n" " local ast = game.vars.asteroids[i]\n" " renderer.circle(math.floor(ast.x + 0.5), math.floor(ast.y + 0.5), ast.size, true, false)\n" " end\n" " \n" " -- Draw bullets\n" " for i = 1, #game.vars.bullets do\n" " local bullet = game.vars.bullets[i]\n" " renderer.pixel(bullet.x, bullet.y, true)\n" " end\n" " \n" " -- Draw ship\n" " local ship_size = 6\n" " local nose_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * ship_size\n" " local nose_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * ship_size\n" " local back_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * (ship_size / 2)\n" " local back_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * (ship_size / 2)\n" " \n" " renderer.line(game.vars.ship_x, game.vars.ship_y, nose_x, nose_y, true, 1)\n" " renderer.line(back_x, back_y, nose_x, nose_y, true, 1)\n" " \n" " -- Draw thrust indicator\n" " if game.vars.thrusting then\n" " local flame_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * ship_size\n" " local flame_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * ship_size\n" " renderer.line(game.vars.ship_x, game.vars.ship_y, flame_x, flame_y, true, 1)\n" " end\n" " \n" " -- Draw score\n" " renderer.text_scaled(10, 10, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(10, 20, \"Level: \" .. tostring(game.vars.level), true, 2)\n" " \n" " if state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function update_ship()\n" " if game.vars.thrusting then\n" " game.vars.ship_vel_x = game.vars.ship_vel_x + math.cos(game.vars.ship_angle) * SHIP_SPEED\n" " game.vars.ship_vel_y = game.vars.ship_vel_y + math.sin(game.vars.ship_angle) * SHIP_SPEED\n" " end\n" " \n" " -- Friction\n" " game.vars.ship_vel_x = game.vars.ship_vel_x * 0.98\n" " game.vars.ship_vel_y = game.vars.ship_vel_y * 0.98\n" " \n" " -- Move ship\n" " game.vars.ship_x = game.vars.ship_x + game.vars.ship_vel_x\n" " game.vars.ship_y = game.vars.ship_y + game.vars.ship_vel_y\n" " \n" " -- Wrap around screen\n" " if game.vars.ship_x < 0 then game.vars.ship_x = game.width() end\n" " if game.vars.ship_x > game.width() then game.vars.ship_x = 0 end\n" " if game.vars.ship_y < 0 then game.vars.ship_y = game.height() end\n" " if game.vars.ship_y > game.height() then game.vars.ship_y = 0 end\n" "end\n" "\n" "function update_bullets()\n" " -- Update existing bullets\n" " for i = #game.vars.bullets, 1, -1 do\n" " local bullet = game.vars.bullets[i]\n" " bullet.x = bullet.x + bullet.vel_x\n" " bullet.y = bullet.y + bullet.vel_y\n" " \n" " -- Remove if off-screen\n" " if bullet.x < 0 or bullet.x > game.width() or bullet.y < 0 or bullet.y > game.height() then\n" " table.remove(game.vars.bullets, i)\n" " end\n" " end\n" " \n" " -- Fire bullet\n" " game.vars.bullet_cooldown = math.max(0, game.vars.bullet_cooldown - 1)\n" " if game.vars.thrusting and game.vars.bullet_cooldown == 0 then\n" " local bullet_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * 8\n" " local bullet_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * 8\n" " \n" " table.insert(game.vars.bullets, {\n" " x = bullet_x,\n" " y = bullet_y,\n" " vel_x = math.cos(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_x,\n" " vel_y = math.sin(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_y\n" " })\n" " \n" " game.vars.bullet_cooldown = 5\n" " end\n" "end\n" "\n" "function update_asteroids()\n" " for i = 1, #game.vars.asteroids do\n" " local ast = game.vars.asteroids[i]\n" " ast.x = ast.x + ast.vel_x\n" " ast.y = ast.y + ast.vel_y\n" " \n" " -- Wrap around screen\n" " if ast.x < -ast.size then ast.x = game.width() + ast.size end\n" " if ast.x > game.width() + ast.size then ast.x = -ast.size end\n" " if ast.y < -ast.size then ast.y = game.height() + ast.size end\n" " if ast.y > game.height() + ast.size then ast.y = -ast.size end\n" " end\n" "end\n" "\n" "function check_collisions()\n" " -- Bullet-asteroid collisions\n" " for b = #game.vars.bullets, 1, -1 do\n" " local bullet = game.vars.bullets[b]\n" " for a = #game.vars.asteroids, 1, -1 do\n" " local ast = game.vars.asteroids[a]\n" " \n" " local dx = bullet.x - ast.x\n" " local dy = bullet.y - ast.y\n" " local dist = math.sqrt(dx * dx + dy * dy)\n" " \n" " if dist < ast.size then\n" " -- Hit!\n" " table.remove(game.vars.bullets, b)\n" " table.remove(game.vars.asteroids, a)\n" " game.vars.score = game.vars.score + (4 - ast.size) * 50\n" " \n" " -- Spawn smaller asteroids\n" " if ast.size > 1 then\n" " for _ = 1, 2 do\n" " spawn_asteroid(ast.x, ast.y, ast.size - 1)\n" " end\n" " end\n" " \n" " break\n" " end\n" " end\n" " end\n" " \n" " -- Ship-asteroid collisions\n" " for i = 1, #game.vars.asteroids do\n" " local ast = game.vars.asteroids[i]\n" " \n" " local dx = game.vars.ship_x - ast.x\n" " local dy = game.vars.ship_y - ast.y\n" " local dist = math.sqrt(dx * dx + dy * dy)\n" " \n" " if dist < ast.size + 6 then\n" " game.vars.state = STATE_GAME_OVER\n" " end\n" " end\n" "end\n" "\n" "function spawn_asteroid(x, y, size)\n" " if size < 1 then return end\n" " \n" " local speed = ASTEROID_SPEEDS[size]\n" " local angle = math.random() * math.pi * 2\n" " \n" " table.insert(game.vars.asteroids, {\n" " x = x,\n" " y = y,\n" " size = size,\n" " vel_x = math.cos(angle) * speed,\n" " vel_y = math.sin(angle) * speed\n" " })\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.level = 1\n" " game.vars.ship_x = game.width() / 2\n" " game.vars.ship_y = game.height() / 2\n" " game.vars.ship_angle = 0\n" " game.vars.ship_vel_x = 0\n" " game.vars.ship_vel_y = 0\n" " game.vars.bullets = {}\n" " game.vars.asteroids = {}\n" " game.vars.frame_count = 0\n" " \n" " spawn_asteroid(game.width() / 2 - 40, game.height() / 2 - 40, 3)\n" " spawn_asteroid(game.width() / 2 + 40, game.height() / 2 + 40, 3)\n" "end\n" ""; static const char ball_lua_src[] = "-- NAME: Bouncing Ball\n" "-- DESC: Physics demo with state management\n" "\n" "-- States\n" "local STATE_PAUSED = 0\n" "local STATE_RUNNING = 1\n" "\n" "function init()\n" " game.vars.state = STATE_PAUSED\n" " game.vars.ball_x = game.width() / 2\n" " game.vars.ball_y = game.height() / 2\n" " game.vars.vel_x = 3\n" " game.vars.vel_y = 2\n" " game.vars.radius = 10\n" " game.vars.frame_count = 0\n" " \n" " -- Enable continuous frame updates for smooth animation\n" " game.set_frame_updates(true)\n" " \n" " print(\"Bouncing Ball initialized\")\n" "end\n" "\n" "function update(event)\n" " -- Toggle pause on tap\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " if game.vars.state == STATE_PAUSED then\n" " game.vars.state = STATE_RUNNING\n" " else\n" " game.vars.state = STATE_PAUSED\n" " end\n" " return true\n" " end\n" " \n" " -- Update physics if running (on any frame tick)\n" " if event.type == INPUT.FRAME_TICK and game.vars.state == STATE_RUNNING then\n" " -- Move ball\n" " game.vars.ball_x = game.vars.ball_x + game.vars.vel_x\n" " game.vars.ball_y = game.vars.ball_y + game.vars.vel_y\n" " \n" " -- Bounce off walls\n" " if game.vars.ball_x - game.vars.radius < 0 or game.vars.ball_x + game.vars.radius > game.width() then\n" " game.vars.vel_x = -game.vars.vel_x\n" " game.vars.ball_x = math.max(game.vars.radius, math.min(game.width() - game.vars.radius, game.vars.ball_x))\n" " end\n" " \n" " if game.vars.ball_y - game.vars.radius < 0 or game.vars.ball_y + game.vars.radius > game.height() then\n" " game.vars.vel_y = -game.vars.vel_y\n" " game.vars.ball_y = math.max(game.vars.radius, math.min(game.height() - game.vars.radius, game.vars.ball_y))\n" " end\n" " \n" " game.vars.frame_count = game.vars.frame_count + 1\n" " return true -- Always redraw when running\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" " \n" " -- Draw ball (convert to integers)\n" " renderer.circle(math.floor(game.vars.ball_x + 0.5), math.floor(game.vars.ball_y + 0.5), game.vars.radius, true, true)\n" " \n" " -- Draw trail (previous positions)\n" " local trail_radius = game.vars.radius - 2\n" " if trail_radius > 2 then\n" " renderer.circle(math.floor(game.vars.ball_x - game.vars.vel_x + 0.5), \n" " math.floor(game.vars.ball_y - game.vars.vel_y + 0.5), \n" " trail_radius, true, false)\n" " end\n" " \n" " -- Draw status\n" " if game.vars.state == STATE_PAUSED then\n" " renderer.text_scaled(10, 10, \"PAUSED - Tap to start\", true, 2)\n" " else\n" " renderer.text_scaled(10, 10, \"Frames: \" .. tostring(game.vars.frame_count), true, 2)\n" " renderer.text_scaled(10, 25, \"Tap to pause\", true, 2)\n" " end\n" " \n" " -- Draw velocity vector\n" " local arrow_x = game.vars.ball_x + game.vars.vel_x * 3\n" " local arrow_y = game.vars.ball_y + game.vars.vel_y * 3\n" " renderer.line(math.floor(game.vars.ball_x + 0.5), math.floor(game.vars.ball_y + 0.5), math.floor(arrow_x + 0.5), math.floor(arrow_y + 0.5), true, 2)\n" "end\n" ""; static const char breakout_lua_src[] = "-- NAME: Breakout\n" "-- DESC: Break bricks with bouncing ball and paddle\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "local STATE_LEVEL_COMPLETE = 3\n" "\n" "-- Game constants\n" "local PADDLE_WIDTH = 40\n" "local PADDLE_HEIGHT = 6\n" "local BALL_RADIUS = 4\n" "local BRICK_WIDTH = 16\n" "local BRICK_HEIGHT = 6\n" "local BRICK_COLS = 16\n" "local BRICK_ROWS = 5\n" "local BRICK_START_Y = 20\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.lives = 3\n" " \n" " -- Paddle\n" " game.vars.paddle_x = (game.width() / 2) - (PADDLE_WIDTH / 2)\n" " \n" " -- Ball\n" " game.vars.ball_x = game.width() / 2\n" " game.vars.ball_y = game.height() - 30\n" " game.vars.ball_vel_x = 2\n" " game.vars.ball_vel_y = -3\n" " \n" " -- Bricks (true = exists, false = broken)\n" " game.vars.bricks = {}\n" " game.vars.bricks_remaining = 0\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Breakout initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle paddle input\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then\n" " game.vars.paddle_x = math.max(0, math.min(game.width() - PADDLE_WIDTH, event.x - PADDLE_WIDTH / 2))\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_ball()\n" " check_brick_collisions()\n" " \n" " -- Check win\n" " if game.vars.bricks_remaining <= 0 then\n" " game.vars.state = STATE_LEVEL_COMPLETE\n" " end\n" " \n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " \n" " elseif state == STATE_LEVEL_COMPLETE then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2 - 30, \"BREAKOUT\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Draw bricks\n" " for row = 1, BRICK_ROWS do\n" " for col = 1, BRICK_COLS do\n" " local idx = (row - 1) * BRICK_COLS + col\n" " if game.vars.bricks[idx] then\n" " local x = (col - 1) * BRICK_WIDTH\n" " local y = BRICK_START_Y + (row - 1) * BRICK_HEIGHT\n" " renderer.rect(x, y, BRICK_WIDTH, BRICK_HEIGHT, true, true)\n" " end\n" " end\n" " end\n" " \n" " -- Draw paddle\n" " renderer.rect(game.vars.paddle_x, game.height() - PADDLE_HEIGHT - 2, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)\n" " \n" " -- Draw ball (convert to integers)\n" " renderer.circle(math.floor(game.vars.ball_x + 0.5), math.floor(game.vars.ball_y + 0.5), BALL_RADIUS, true, true)\n" " \n" " -- Draw score and lives\n" " renderer.text_scaled(5, 5, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() - 50, 5, \"Lives: \" .. tostring(game.vars.lives), true, 2)\n" " \n" " elseif state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 20, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " \n" " elseif state == STATE_LEVEL_COMPLETE then\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 20, \"LEVEL COMPLETE!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" "end\n" "\n" "function update_ball()\n" " -- Move ball\n" " game.vars.ball_x = game.vars.ball_x + game.vars.ball_vel_x\n" " game.vars.ball_y = game.vars.ball_y + game.vars.ball_vel_y\n" " \n" " -- Bounce off walls\n" " if game.vars.ball_x - BALL_RADIUS < 0 or game.vars.ball_x + BALL_RADIUS > game.width() then\n" " game.vars.ball_vel_x = -game.vars.ball_vel_x\n" " game.vars.ball_x = math.max(BALL_RADIUS, math.min(game.width() - BALL_RADIUS, game.vars.ball_x))\n" " end\n" " \n" " -- Bounce off top\n" " if game.vars.ball_y - BALL_RADIUS < 0 then\n" " game.vars.ball_vel_y = -game.vars.ball_vel_y\n" " game.vars.ball_y = BALL_RADIUS\n" " end\n" " \n" " -- Check paddle collision\n" " if game.vars.ball_y + BALL_RADIUS > game.height() - PADDLE_HEIGHT - 2 then\n" " if game.vars.ball_x > game.vars.paddle_x and game.vars.ball_x < game.vars.paddle_x + PADDLE_WIDTH then\n" " if game.vars.ball_vel_y > 0 then\n" " game.vars.ball_vel_y = -game.vars.ball_vel_y\n" " \n" " -- Add spin based on hit position\n" " local hit_pos = (game.vars.ball_x - game.vars.paddle_x) / PADDLE_WIDTH\n" " game.vars.ball_vel_x = (hit_pos - 0.5) * 4\n" " end\n" " end\n" " end\n" " \n" " -- Fall off bottom = lose life\n" " if game.vars.ball_y > game.height() then\n" " game.vars.lives = game.vars.lives - 1\n" " if game.vars.lives <= 0 then\n" " game.vars.state = STATE_GAME_OVER\n" " else\n" " reset_ball()\n" " end\n" " end\n" "end\n" "\n" "function check_brick_collisions()\n" " for row = 1, BRICK_ROWS do\n" " for col = 1, BRICK_COLS do\n" " local idx = (row - 1) * BRICK_COLS + col\n" " if game.vars.bricks[idx] then\n" " local brick_x = (col - 1) * BRICK_WIDTH\n" " local brick_y = BRICK_START_Y + (row - 1) * BRICK_HEIGHT\n" " \n" " -- Simple AABB collision with ball\n" " if game.vars.ball_x + BALL_RADIUS > brick_x and\n" " game.vars.ball_x - BALL_RADIUS < brick_x + BRICK_WIDTH and\n" " game.vars.ball_y + BALL_RADIUS > brick_y and\n" " game.vars.ball_y - BALL_RADIUS < brick_y + BRICK_HEIGHT then\n" " \n" " -- Destroy brick\n" " game.vars.bricks[idx] = false\n" " game.vars.bricks_remaining = game.vars.bricks_remaining - 1\n" " game.vars.score = game.vars.score + 10\n" " \n" " -- Bounce ball (simple: vertical bounce)\n" " game.vars.ball_vel_y = -game.vars.ball_vel_y\n" " end\n" " end\n" " end\n" " end\n" "end\n" "\n" "function reset_ball()\n" " game.vars.ball_x = game.vars.paddle_x + PADDLE_WIDTH / 2\n" " game.vars.ball_y = game.height() - 30\n" " game.vars.ball_vel_x = 2\n" " game.vars.ball_vel_y = -3\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.lives = 3\n" " game.vars.paddle_x = (game.width() / 2) - (PADDLE_WIDTH / 2)\n" " \n" " -- Create brick grid\n" " game.vars.bricks = {}\n" " game.vars.bricks_remaining = BRICK_ROWS * BRICK_COLS\n" " for i = 1, BRICK_ROWS * BRICK_COLS do\n" " game.vars.bricks[i] = true\n" " end\n" " \n" " reset_ball()\n" "end\n" ""; static const char counter_lua_src[] = "-- NAME: Touch Counter\n" "-- DESC: Simple tap counter demo\n" "\n" "-- Initialize game state\n" "function init()\n" " game.vars.count = 0\n" " game.vars.last_x = 0\n" " game.vars.last_y = 0\n" " print(\"Counter initialized\")\n" "end\n" "\n" "-- Update game logic based on input\n" "function update(event)\n" " -- Check if touch/button pressed\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.count = game.vars.count + 1\n" " game.vars.last_x = event.x\n" " game.vars.last_y = event.y\n" " print(\"Count: \" .. game.vars.count)\n" " return true -- Request redraw\n" " end\n" " \n" " return false -- No redraw needed\n" "end\n" "\n" "-- Draw the game\n" "function draw()\n" " -- Clear screen\n" " renderer.clear(true)\n" " \n" " -- Draw title\n" " renderer.text_scaled(20, 20, \"Touch Counter\", true, 2)\n" " \n" " -- Draw count (centered)\n" " local count_text = \"Count: \" .. tostring(game.vars.count)\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 10, count_text, true, 2)\n" " \n" " -- Draw last touch position\n" " if game.vars.count > 0 then\n" " local pos_text = \"Last: (\" .. tostring(game.vars.last_x) .. \", \" .. tostring(game.vars.last_y) .. \")\"\n" " renderer.text_scaled(20, game.height() - 30, pos_text, true, 2)\n" " \n" " -- Draw marker at last touch (convert to integers)\n" " renderer.circle(math.floor(game.vars.last_x + 0.5), math.floor(game.vars.last_y + 0.5), 5, true, false)\n" " end\n" " \n" " -- Draw instructions\n" " renderer.text_scaled(20, 50, \"Tap screen to increment\", true, 2)\n" "end\n" ""; static const char flappy_bird_lua_src[] = "-- NAME: Flappy Bird\n" "-- DESC: Tap to flap, avoid pipes\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local BIRD_SIZE = 8\n" "local BIRD_GRAVITY = 0.3\n" "local BIRD_FLAP_POWER = -7\n" "local PIPE_WIDTH = 20\n" "local PIPE_GAP = 50\n" "local PIPE_SPEED = 3\n" "local SPAWN_RATE = 80 -- Frames between pipe spawns\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.frame_count = 0\n" " \n" " -- Bird\n" " game.vars.bird_y = game.height() / 2\n" " game.vars.bird_vel = 0\n" " \n" " -- Pipes (array of {x, gap_y})\n" " game.vars.pipes = {}\n" " game.vars.last_pipe_frame = 0\n" " game.vars.score_submit_pending = false\n" " game.vars.score_submitted = 0\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Flappy Bird initialized\")\n" "end\n" "\n" "function set_game_over()\n" " if game.vars.state ~= STATE_GAME_OVER then\n" " game.vars.state = STATE_GAME_OVER\n" " game.vars.score_submitted = game.vars.score\n" " game.vars.score_submit_pending = true\n" " end\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle flap input\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.bird_vel = BIRD_FLAP_POWER\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_bird()\n" " update_pipes()\n" " check_collisions()\n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 30, \"FLAPPY BIRD\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Draw bird (convert to integer)\n" " renderer.circle(20, math.floor(game.vars.bird_y + 0.5), BIRD_SIZE, true, true)\n" " \n" " -- Draw pipes\n" " for i = 1, #game.vars.pipes do\n" " local pipe = game.vars.pipes[i]\n" " \n" " -- Top pipe\n" " renderer.rect(pipe.x, 0, PIPE_WIDTH, pipe.gap_y, true, true)\n" " \n" " -- Bottom pipe\n" " local bottom_start = pipe.gap_y + PIPE_GAP\n" " renderer.rect(pipe.x, bottom_start, PIPE_WIDTH, game.height() - bottom_start, true, true)\n" " end\n" " \n" " -- Draw score\n" " renderer.text_scaled(10, 10, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " \n" " elseif state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 30, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Restart\", true, 2)\n" " end\n" "end\n" "\n" "function update_bird()\n" " -- Apply gravity\n" " game.vars.bird_vel = game.vars.bird_vel + BIRD_GRAVITY\n" " game.vars.bird_y = game.vars.bird_y + game.vars.bird_vel\n" " \n" " -- Clamp to screen (game over if hit top/bottom)\n" " if game.vars.bird_y - BIRD_SIZE < 0 or game.vars.bird_y + BIRD_SIZE > game.height() then\n" " set_game_over()\n" " end\n" "end\n" "\n" "function update_pipes()\n" " game.vars.frame_count = game.vars.frame_count + 1\n" " \n" " -- Spawn new pipe\n" " if game.vars.frame_count - game.vars.last_pipe_frame >= SPAWN_RATE then\n" " local gap_y = math.random(30, game.height() - PIPE_GAP - 30)\n" " table.insert(game.vars.pipes, {x = game.width(), gap_y = gap_y})\n" " game.vars.last_pipe_frame = game.vars.frame_count\n" " end\n" " \n" " -- Move and remove off-screen pipes\n" " for i = #game.vars.pipes, 1, -1 do\n" " local pipe = game.vars.pipes[i]\n" " pipe.x = pipe.x - PIPE_SPEED\n" " \n" " -- Score when pipe passes bird\n" " if pipe.x == 20 then\n" " game.vars.score = game.vars.score + 1\n" " end\n" " \n" " -- Remove if off-screen\n" " if pipe.x < -PIPE_WIDTH then\n" " table.remove(game.vars.pipes, i)\n" " end\n" " end\n" "end\n" "\n" "function check_collisions()\n" " -- Check collision with pipes\n" " for i = 1, #game.vars.pipes do\n" " local pipe = game.vars.pipes[i]\n" " \n" " -- Bird hitbox: circle at (20, bird_y) with radius BIRD_SIZE\n" " -- Check if within pipe's X range\n" " if 20 + BIRD_SIZE > pipe.x and 20 - BIRD_SIZE < pipe.x + PIPE_WIDTH then\n" " -- Check Y collision\n" " if game.vars.bird_y - BIRD_SIZE < pipe.gap_y or \n" " game.vars.bird_y + BIRD_SIZE > pipe.gap_y + PIPE_GAP then\n" " set_game_over()\n" " end\n" " end\n" " end\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.bird_y = game.height() / 2\n" " game.vars.bird_vel = 0\n" " game.vars.pipes = {}\n" " game.vars.frame_count = 0\n" " game.vars.last_pipe_frame = 0\n" " game.vars.score_submit_pending = false\n" "end\n" ""; static const char lunar_lander_lua_src[] = "-- NAME: Lunar Lander\n" "-- DESC: Land safely with limited fuel\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_LANDED = 2\n" "local STATE_CRASHED = 3\n" "\n" "-- Game constants\n" "local GRAVITY = 0.15\n" "local THRUST_POWER = 0.3\n" "local MAX_FUEL = 100\n" "local SAFE_LANDING_SPEED = 1.5\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " \n" " -- Lander\n" " game.vars.lander_x = game.width() / 2\n" " game.vars.lander_y = 10\n" " game.vars.lander_vel_y = 0\n" " game.vars.fuel = MAX_FUEL\n" " game.vars.thrusting = false\n" " \n" " -- Terrain\n" " game.vars.landing_zone_x = game.width() / 2 - 20\n" " game.vars.landing_zone_w = 40\n" " game.vars.terrain_y = game.height() - 15\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Lunar Lander initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle thrust input\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then\n" " if game.vars.fuel > 0 then\n" " game.vars.thrusting = true\n" " game.vars.fuel = game.vars.fuel - 1\n" " else\n" " game.vars.thrusting = false\n" " end\n" " else\n" " game.vars.thrusting = false\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_lander()\n" " check_landing()\n" " return true\n" " end\n" " \n" " elseif state == STATE_LANDED or state == STATE_CRASHED then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 30, \"LUNAR LANDER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 70, game.height() / 2 - 5, \"Land in the zone safely\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_LANDED or state == STATE_CRASHED then\n" " -- Draw terrain\n" " renderer.rect(0, game.vars.terrain_y, game.width(), game.height() - game.vars.terrain_y, true, true)\n" " \n" " -- Draw landing zone (outline)\n" " renderer.rect(game.vars.landing_zone_x, game.vars.terrain_y - 2, game.vars.landing_zone_w, 2, true, true)\n" " \n" " -- Draw lander (triangle)\n" " local lander_w = 8\n" " local lander_h = 6\n" " renderer.line(game.vars.lander_x - lander_w / 2, game.vars.lander_y + lander_h, \n" " game.vars.lander_x, game.vars.lander_y, true, 1)\n" " renderer.line(game.vars.lander_x, game.vars.lander_y, \n" " game.vars.lander_x + lander_w / 2, game.vars.lander_y + lander_h, true, 1)\n" " renderer.line(game.vars.lander_x - lander_w / 2, game.vars.lander_y + lander_h,\n" " game.vars.lander_x + lander_w / 2, game.vars.lander_y + lander_h, true, 1)\n" " \n" " -- Draw thrust flame\n" " if game.vars.thrusting then\n" " renderer.line(game.vars.lander_x - 2, game.vars.lander_y + lander_h,\n" " game.vars.lander_x - 1, game.vars.lander_y + lander_h + 3, true, 1)\n" " renderer.line(game.vars.lander_x + 2, game.vars.lander_y + lander_h,\n" " game.vars.lander_x + 1, game.vars.lander_y + lander_h + 3, true, 1)\n" " end\n" " \n" " -- Draw stats\n" " renderer.text_scaled(5, 5, \"Fuel: \" .. tostring(math.floor(game.vars.fuel)), true, 2)\n" " renderer.text_scaled(5, 15, \"Speed: \" .. tostring(math.floor(game.vars.lander_vel_y * 10)), true, 2)\n" " \n" " if state == STATE_LANDED then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 20, \"LANDED!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" " \n" " if state == STATE_CRASHED then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 20, \"CRASHED!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function update_lander()\n" " -- Apply gravity\n" " game.vars.lander_vel_y = game.vars.lander_vel_y + GRAVITY\n" " \n" " -- Apply thrust\n" " if game.vars.thrusting then\n" " game.vars.lander_vel_y = game.vars.lander_vel_y - THRUST_POWER\n" " end\n" " \n" " -- Update position\n" " game.vars.lander_y = game.vars.lander_y + game.vars.lander_vel_y\n" "end\n" "\n" "function check_landing()\n" " -- Check if lander reached terrain\n" " if game.vars.lander_y + 6 >= game.vars.terrain_y then\n" " local lander_left = game.vars.lander_x - 4\n" " local lander_right = game.vars.lander_x + 4\n" " local zone_left = game.vars.landing_zone_x\n" " local zone_right = game.vars.landing_zone_x + game.vars.landing_zone_w\n" " \n" " -- Check if in landing zone\n" " if lander_left >= zone_left and lander_right <= zone_right then\n" " -- Check landing speed\n" " if game.vars.lander_vel_y <= SAFE_LANDING_SPEED then\n" " game.vars.state = STATE_LANDED\n" " game.vars.score = 100 + math.floor(game.vars.fuel)\n" " else\n" " game.vars.state = STATE_CRASHED\n" " end\n" " else\n" " game.vars.state = STATE_CRASHED\n" " end\n" " end\n" "end\n" "\n" "function reset_game()\n" " game.vars.lander_x = game.width() / 2\n" " game.vars.lander_y = 10\n" " game.vars.lander_vel_y = 0\n" " game.vars.fuel = MAX_FUEL\n" " game.vars.thrusting = false\n" " game.vars.score = 0\n" "end\n" ""; static const char memory_match_lua_src[] = "-- NAME: Memory Match\n" "-- DESC: Find matching pairs\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local GRID_COLS = 4\n" "local GRID_ROWS = 4\n" "local FLIP_DURATION = 15 -- Frames to show flip animation\n" "\n" "-- Calculate card size based on screen size\n" "local function get_card_size()\n" " -- Use available space with padding, based on smallest dimension\n" " local min_dim = math.min(game.width(), game.height())\n" " local padding = math.floor(min_dim / 8)\n" " local available_w = game.width() - (padding * 2)\n" " local available_h = game.height() - 80 -- Leave room for text\n" " \n" " -- Calculate based on grid\n" " local card_width = math.floor(available_w / GRID_COLS)\n" " local card_height = math.floor(available_h / GRID_ROWS)\n" " \n" " -- Use the smaller dimension for square cards\n" " return math.min(card_width, card_height)\n" "end\n" "\n" "local function get_grid_start_x()\n" " local card_size = get_card_size()\n" " local grid_width = card_size * GRID_COLS\n" " return math.floor((game.width() - grid_width) / 2)\n" "end\n" "\n" "local function get_grid_start_y()\n" " return 60\n" "end\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.moves = 0\n" " \n" " -- Card grid\n" " game.vars.cards = {} -- {id, face_up, matched}\n" " game.vars.selected = {} -- Indices of selected cards\n" " game.vars.flip_frame = 0\n" " game.vars.waiting = false -- Waiting to flip back incorrect pair\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Memory Match initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle card selection\n" " if event.type == INPUT.TOUCH_DOWN and not game.vars.waiting then\n" " local card_idx = get_card_at(event.x, event.y)\n" " if card_idx and not game.vars.cards[card_idx].matched and not game.vars.cards[card_idx].face_up then\n" " -- Select card\n" " game.vars.cards[card_idx].face_up = true\n" " table.insert(game.vars.selected, card_idx)\n" " \n" " if #game.vars.selected == 2 then\n" " game.vars.moves = game.vars.moves + 1\n" " \n" " -- Check for match\n" " if game.vars.cards[game.vars.selected[1]].id == game.vars.cards[game.vars.selected[2]].id then\n" " -- Match!\n" " game.vars.cards[game.vars.selected[1]].matched = true\n" " game.vars.cards[game.vars.selected[2]].matched = true\n" " game.vars.score = game.vars.score + 1\n" " game.vars.selected = {}\n" " \n" " -- Check win\n" " if game.vars.score == (GRID_COLS * GRID_ROWS) / 2 then\n" " game.vars.state = STATE_GAME_OVER\n" " end\n" " else\n" " -- No match, wait then flip back\n" " game.vars.waiting = true\n" " game.vars.flip_frame = 0\n" " end\n" " end\n" " \n" " return true\n" " end\n" " end\n" " \n" " -- Handle flip-back animation\n" " if game.vars.waiting and event.type == INPUT.FRAME_TICK then\n" " game.vars.flip_frame = game.vars.flip_frame + 1\n" " \n" " if game.vars.flip_frame >= FLIP_DURATION then\n" " -- Flip cards back\n" " game.vars.cards[game.vars.selected[1]].face_up = false\n" " game.vars.cards[game.vars.selected[2]].face_up = false\n" " game.vars.selected = {}\n" " game.vars.waiting = false\n" " game.vars.flip_frame = 0\n" " end\n" " \n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " local card_size = get_card_size()\n" " local start_x = get_grid_start_x()\n" " local start_y = get_grid_start_y()\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 40, \"MEMORY MATCH\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 10, \"Find all pairs\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_GAME_OVER then\n" " -- Draw grid\n" " for row = 0, GRID_ROWS - 1 do\n" " for col = 0, GRID_COLS - 1 do\n" " local idx = row * GRID_COLS + col + 1\n" " local card = game.vars.cards[idx]\n" " local x = start_x + col * card_size\n" " local y = start_y + row * card_size\n" " \n" " if card.face_up or card.matched then\n" " -- Show card value\n" " renderer.rect(x, y, card_size, card_size, true, true)\n" " local text = tostring(card.id)\n" " renderer.text_scaled(x + math.floor(card_size / 2 - 2), y + math.floor(card_size / 2 - 2), text, false, 2)\n" " else\n" " -- Face down (outline)\n" " renderer.rect(x, y, card_size, card_size, true, false)\n" " end\n" " end\n" " end\n" " \n" " -- Draw stats\n" " renderer.text_scaled(10, 10, \"Pairs: \" .. tostring(game.vars.score) .. \"/\" .. tostring((GRID_COLS * GRID_ROWS) / 2), true, 2)\n" " renderer.text_scaled(10, 25, \"Moves: \" .. tostring(game.vars.moves), true, 2)\n" " \n" " if state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, 5, \"YOU WIN!\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() - 20, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function get_card_at(x, y)\n" " local card_size = get_card_size()\n" " local start_x = get_grid_start_x()\n" " local start_y = get_grid_start_y()\n" " \n" " for row = 0, GRID_ROWS - 1 do\n" " for col = 0, GRID_COLS - 1 do\n" " local card_x = start_x + col * card_size\n" " local card_y = start_y + row * card_size\n" " \n" " if x >= card_x and x < card_x + card_size and\n" " y >= card_y and y < card_y + card_size then\n" " return row * GRID_COLS + col + 1\n" " end\n" " end\n" " end\n" " \n" " return nil\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.moves = 0\n" " game.vars.selected = {}\n" " game.vars.flip_frame = 0\n" " game.vars.waiting = false\n" " \n" " -- Create shuffled card pairs\n" " local card_ids = {}\n" " local num_pairs = (GRID_COLS * GRID_ROWS) / 2\n" " for i = 1, num_pairs do\n" " table.insert(card_ids, i)\n" " table.insert(card_ids, i)\n" " end\n" " \n" " -- Shuffle\n" " for i = #card_ids, 2, -1 do\n" " local j = math.random(1, i)\n" " card_ids[i], card_ids[j] = card_ids[j], card_ids[i]\n" " end\n" " \n" " -- Create card objects\n" " game.vars.cards = {}\n" " for i = 1, #card_ids do\n" " game.vars.cards[i] = {\n" " id = card_ids[i],\n" " face_up = false,\n" " matched = false\n" " }\n" " end\n" "end\n" ""; static const char pacman_lua_src[] = "-- NAME: Pacman\n" "-- DESC: Simplified pacman with digital tile movement\n" "\n" "local TILE = 14\n" "\n" "local LEVEL = {\n" " \"####################\",\n" " \"#o...#........#....#\",\n" " \"#.##.#.######.#.##.#\",\n" " \"#.#..............#.#\",\n" " \"#.#.##.## ##.##.#.#\",\n" " \"#......# #......#\",\n" " \"#.#.##.######.##.#.#\",\n" " \"#.#..............#.#\",\n" " \"#.##.#.######.#.##.#\",\n" " \"#o...#........#....#\",\n" " \"####################\",\n" "}\n" "\n" "local WALL = 1\n" "local DOT = 2\n" "local POWER = 3\n" "local EMPTY = 0\n" "\n" "local DIRS = {\n" " U = {0, -1},\n" " D = {0, 1},\n" " L = {-1, 0},\n" " R = {1, 0},\n" "}\n" "\n" "local OPP = {U = \"D\", D = \"U\", L = \"R\", R = \"L\"}\n" "local BTN = 22\n" "local POWER_DURATION_TICKS = 240\n" "\n" "local function level_dims()\n" " return #LEVEL[1], #LEVEL\n" "end\n" "\n" "local function level_origin()\n" " local w, h = level_dims()\n" " local px_w = w * TILE\n" " local px_h = h * TILE\n" " local ox = math.floor((game.width() - px_w) / 2)\n" " local oy = 64\n" " return ox, oy, px_w, px_h\n" "end\n" "\n" "local function parse_level()\n" " local w, h = level_dims()\n" " game.vars.map_w = w\n" " game.vars.map_h = h\n" " game.vars.map = {}\n" " game.vars.pellet_count = 0\n" "\n" " for y = 1, h do\n" " game.vars.map[y] = {}\n" " local row = LEVEL[y]\n" " for x = 1, w do\n" " local ch = string.sub(row, x, x)\n" " local v = EMPTY\n" " if ch == \"#\" then\n" " v = WALL\n" " elseif ch == \".\" then\n" " v = DOT\n" " game.vars.pellet_count = game.vars.pellet_count + 1\n" " elseif ch == \"o\" then\n" " v = POWER\n" " game.vars.pellet_count = game.vars.pellet_count + 1\n" " end\n" " game.vars.map[y][x] = v\n" " end\n" " end\n" "end\n" "\n" "local function in_bounds(tx, ty)\n" " return tx >= 1 and tx <= game.vars.map_w and ty >= 1 and ty <= game.vars.map_h\n" "end\n" "\n" "local function is_wall(tx, ty)\n" " if not in_bounds(tx, ty) then return true end\n" " return game.vars.map[ty][tx] == WALL\n" "end\n" "\n" "local function tile_to_px(tx, ty)\n" " local ox, oy = level_origin()\n" " return ox + (tx - 1) * TILE, oy + (ty - 1) * TILE\n" "end\n" "\n" "local function tile_center(tx, ty)\n" " local px, py = tile_to_px(tx, ty)\n" " return px + math.floor(TILE / 2), py + math.floor(TILE / 2)\n" "end\n" "\n" "local function nearest_open_tile(tx, ty)\n" " if in_bounds(tx, ty) and not is_wall(tx, ty) then\n" " return tx, ty\n" " end\n" "\n" " local best_tx, best_ty = 1, 1\n" " local best_d = 999999\n" " for y = 1, game.vars.map_h do\n" " for x = 1, game.vars.map_w do\n" " if not is_wall(x, y) then\n" " local d = math.abs(x - tx) + math.abs(y - ty)\n" " if d < best_d then\n" " best_d = d\n" " best_tx = x\n" " best_ty = y\n" " end\n" " end\n" " end\n" " end\n" " return best_tx, best_ty\n" "end\n" "\n" "local function try_step_tile(tx, ty, dir)\n" " local dv = DIRS[dir]\n" " local nx = tx + dv[1]\n" " local ny = ty + dv[2]\n" " if not is_wall(nx, ny) then\n" " return nx, ny, true\n" " end\n" " return tx, ty, false\n" "end\n" "\n" "local function consume_pellet_at(tx, ty)\n" " if not in_bounds(tx, ty) then return end\n" " local v = game.vars.map[ty][tx]\n" " if v == DOT then\n" " game.vars.map[ty][tx] = EMPTY\n" " game.vars.pellet_count = game.vars.pellet_count - 1\n" " game.vars.score = game.vars.score + 1\n" " elseif v == POWER then\n" " game.vars.map[ty][tx] = EMPTY\n" " game.vars.pellet_count = game.vars.pellet_count - 1\n" " game.vars.score = game.vars.score + 5\n" " game.vars.power_ticks = POWER_DURATION_TICKS\n" " end\n" "\n" " if game.vars.pellet_count <= 0 then\n" " game.vars.state = \"won\"\n" " end\n" "end\n" "\n" "local function respawn_ghost(g)\n" " local sx, sy = nearest_open_tile(math.floor(game.vars.map_w / 2), math.floor(game.vars.map_h / 2))\n" " g.x = sx\n" " g.y = sy\n" " g.dir = (math.random(1, 2) == 1) and \"L\" or \"R\"\n" " g.release = game.vars.tick + 30\n" "end\n" "\n" "local function resolve_ghost_collision(g)\n" " if game.vars.tick <= game.vars.grace then return end\n" " if g.x ~= game.vars.px or g.y ~= game.vars.py then return end\n" "\n" " if game.vars.power_ticks > 0 then\n" " game.vars.score = game.vars.score + 20\n" " respawn_ghost(g)\n" " else\n" " game.vars.state = \"lost\"\n" " end\n" "end\n" "\n" "local function draw_wall_tile(tx, ty)\n" " local x, y = tile_to_px(tx, ty)\n" " local ix = x + 1\n" " local iy = y + 1\n" " local ex = x + TILE - 2\n" " local ey = y + TILE - 2\n" "\n" " if not is_wall(tx, ty - 1) then renderer.line(ix, iy, ex, iy, true, 1) end\n" " if not is_wall(tx, ty + 1) then renderer.line(ix, ey, ex, ey, true, 1) end\n" " if not is_wall(tx - 1, ty) then renderer.line(ix, iy, ix, ey, true, 1) end\n" " if not is_wall(tx + 1, ty) then renderer.line(ex, iy, ex, ey, true, 1) end\n" "\n" " if (not is_wall(tx, ty - 1)) and (not is_wall(tx - 1, ty)) then renderer.pixel(ix, iy, true) end\n" " if (not is_wall(tx, ty - 1)) and (not is_wall(tx + 1, ty)) then renderer.pixel(ex, iy, true) end\n" " if (not is_wall(tx, ty + 1)) and (not is_wall(tx - 1, ty)) then renderer.pixel(ix, ey, true) end\n" " if (not is_wall(tx, ty + 1)) and (not is_wall(tx + 1, ty)) then renderer.pixel(ex, ey, true) end\n" "end\n" "\n" "local function draw_level()\n" " for y = 1, game.vars.map_h do\n" " for x = 1, game.vars.map_w do\n" " local v = game.vars.map[y][x]\n" " if v == WALL then\n" " draw_wall_tile(x, y)\n" " elseif v == DOT then\n" " local px, py = tile_center(x, y)\n" " renderer.circle(px, py, 1, true, true)\n" " elseif v == POWER then\n" " local px, py = tile_center(x, y)\n" " renderer.circle(px, py, 3, true, true)\n" " end\n" " end\n" " end\n" "end\n" "\n" "local function draw_ghost(cx, cy, vulnerable, blink)\n" " if vulnerable then\n" " renderer.rect(cx - 5, cy - 2, 10, 7, true, false)\n" " renderer.circle(cx - 2, cy - 2, 3, true, false)\n" " renderer.circle(cx + 2, cy - 2, 3, true, false)\n" " renderer.rect(cx - 4, cy + 4, 2, 2, false, true)\n" " renderer.rect(cx - 1, cy + 4, 2, 2, false, true)\n" " renderer.rect(cx + 2, cy + 4, 2, 2, false, true)\n" " if blink then\n" " renderer.circle(cx, cy, 7, true, false)\n" " end\n" " else\n" " renderer.rect(cx - 5, cy - 2, 10, 7, true, true)\n" " renderer.circle(cx - 2, cy - 2, 3, true, true)\n" " renderer.circle(cx + 2, cy - 2, 3, true, true)\n" " renderer.rect(cx - 4, cy + 4, 2, 2, false, true)\n" " renderer.rect(cx - 1, cy + 4, 2, 2, false, true)\n" " renderer.rect(cx + 2, cy + 4, 2, 2, false, true)\n" " end\n" " renderer.rect(cx - 3, cy - 1, 2, 2, false, true)\n" " renderer.rect(cx + 1, cy - 1, 2, 2, false, true)\n" "end\n" "\n" "local function draw_pacman(cx, cy, mouth_open, dir)\n" " renderer.circle(cx, cy, 5, true, true)\n" " if not mouth_open then return end\n" "\n" " if dir == \"R\" then\n" " renderer.triangle(cx, cy, cx + 6, cy - 3, cx + 6, cy + 3, false, true)\n" " elseif dir == \"L\" then\n" " renderer.triangle(cx, cy, cx - 6, cy - 3, cx - 6, cy + 3, false, true)\n" " elseif dir == \"U\" then\n" " renderer.triangle(cx, cy, cx - 3, cy - 6, cx + 3, cy - 6, false, true)\n" " else\n" " renderer.triangle(cx, cy, cx - 3, cy + 6, cx + 3, cy + 6, false, true)\n" " end\n" "end\n" "\n" "local function control_positions()\n" " local cx = game.width() - 48\n" " local cy = game.height() - 50\n" " return {\n" " U = {x = cx, y = cy - BTN, w = BTN, h = BTN},\n" " D = {x = cx, y = cy + BTN, w = BTN, h = BTN},\n" " L = {x = cx - BTN, y = cy, w = BTN, h = BTN},\n" " R = {x = cx + BTN, y = cy, w = BTN, h = BTN},\n" " }\n" "end\n" "\n" "local function point_in(px, py, r)\n" " return px >= r.x and px < (r.x + r.w) and py >= r.y and py < (r.y + r.h)\n" "end\n" "\n" "local function touch_to_dir(tx, ty)\n" " local ctl = control_positions()\n" " if point_in(tx, ty, ctl.U) then return \"U\" end\n" " if point_in(tx, ty, ctl.D) then return \"D\" end\n" " if point_in(tx, ty, ctl.L) then return \"L\" end\n" " if point_in(tx, ty, ctl.R) then return \"R\" end\n" " return nil\n" "end\n" "\n" "local function handle_touch(tx, ty)\n" " local pcx, pcy = tile_center(game.vars.px, game.vars.py)\n" " local dx = tx - pcx\n" " local dy = ty - pcy\n" " if math.abs(dx) > math.abs(dy) then\n" " game.vars.want_dir = (dx >= 0) and \"R\" or \"L\"\n" " else\n" " game.vars.want_dir = (dy >= 0) and \"D\" or \"U\"\n" " end\n" "end\n" "\n" "local function available_dirs_tile(tx, ty, current)\n" " local out = {}\n" " for dir, _ in pairs(DIRS) do\n" " if dir ~= OPP[current] then\n" " local _, _, ok = try_step_tile(tx, ty, dir)\n" " if ok then out[#out + 1] = dir end\n" " end\n" " end\n" " if #out == 0 then\n" " out[1] = OPP[current]\n" " end\n" " return out\n" "end\n" "\n" "local function move_player_step()\n" " local _, _, ok_turn = try_step_tile(game.vars.px, game.vars.py, game.vars.want_dir)\n" " if ok_turn then\n" " game.vars.dir = game.vars.want_dir\n" " end\n" "\n" " local nx, ny, ok = try_step_tile(game.vars.px, game.vars.py, game.vars.dir)\n" " if ok then\n" " game.vars.px = nx\n" " game.vars.py = ny\n" " consume_pellet_at(nx, ny)\n" " end\n" "\n" " for i = 1, #game.vars.ghosts do\n" " resolve_ghost_collision(game.vars.ghosts[i])\n" " end\n" "end\n" "\n" "local function move_ghosts_step()\n" " for i = 1, #game.vars.ghosts do\n" " local g = game.vars.ghosts[i]\n" " if game.vars.tick >= g.release then\n" " local dirs = available_dirs_tile(g.x, g.y, g.dir)\n" " local pick = dirs[1]\n" "\n" " local vulnerable = game.vars.power_ticks > 0\n" " if math.random(1, 100) <= 70 then\n" " local best = pick\n" " local bestd = vulnerable and -1 or 99999\n" " for k = 1, #dirs do\n" " local dv = DIRS[dirs[k]]\n" " local tx = g.x + dv[1]\n" " local ty = g.y + dv[2]\n" " local md = math.abs(tx - game.vars.px) + math.abs(ty - game.vars.py)\n" " if (not vulnerable and md < bestd) or (vulnerable and md > bestd) then\n" " bestd = md\n" " best = dirs[k]\n" " end\n" " end\n" " pick = best\n" " else\n" " pick = dirs[math.random(1, #dirs)]\n" " end\n" "\n" " g.dir = pick\n" " local nx, ny, ok = try_step_tile(g.x, g.y, g.dir)\n" " if ok then\n" " g.x = nx\n" " g.y = ny\n" " end\n" "\n" " resolve_ghost_collision(g)\n" " end\n" " end\n" "end\n" "\n" "local function spawn_entities()\n" " local ptx, pty = nearest_open_tile(math.floor(game.vars.map_w / 2), game.vars.map_h - 3)\n" " game.vars.px = ptx\n" " game.vars.py = pty\n" " game.vars.dir = \"R\"\n" " game.vars.want_dir = \"R\"\n" "\n" " local g1tx, g1ty = nearest_open_tile(math.floor(game.vars.map_w / 2), math.floor(game.vars.map_h / 2))\n" " local g2tx, g2ty = nearest_open_tile(math.floor(game.vars.map_w / 2) + 2, math.floor(game.vars.map_h / 2))\n" "\n" " game.vars.ghosts = {\n" " {x = g1tx, y = g1ty, dir = \"L\", release = 18},\n" " {x = g2tx, y = g2ty, dir = \"R\", release = 42},\n" " }\n" "\n" " game.vars.grace = 80\n" " game.vars.mouth_open = true\n" " game.vars.power_ticks = 0\n" "\n" " -- movement cadence (digital): half the previous speed\n" " game.vars.player_step_mod = 6\n" " game.vars.ghost_step_mod = 12\n" " -- Animate mouth twice per movement cycle\n" " game.vars.anim_mod = 3\n" "end\n" "\n" "local function reset_game()\n" " parse_level()\n" " game.vars.score = 0\n" " game.vars.tick = 0\n" " game.vars.state = \"playing\"\n" " spawn_entities()\n" " consume_pellet_at(game.vars.px, game.vars.py)\n" "end\n" "\n" "local function draw_control_button(r, dir, active)\n" " renderer.rect(r.x, r.y, r.w, r.h, true, active)\n" " local cx = r.x + math.floor(r.w / 2)\n" " local cy = r.y + math.floor(r.h / 2)\n" " if dir == \"U\" then\n" " renderer.triangle(cx, cy - 6, cx - 5, cy + 3, cx + 5, cy + 3, not active, true)\n" " elseif dir == \"D\" then\n" " renderer.triangle(cx, cy + 6, cx - 5, cy - 3, cx + 5, cy - 3, not active, true)\n" " elseif dir == \"L\" then\n" " renderer.triangle(cx - 6, cy, cx + 3, cy - 5, cx + 3, cy + 5, not active, true)\n" " else\n" " renderer.triangle(cx + 6, cy, cx - 3, cy - 5, cx - 3, cy + 5, not active, true)\n" " end\n" "end\n" "\n" "local function draw_touch_controls()\n" " local ctl = control_positions()\n" " draw_control_button(ctl.U, \"U\", game.vars.want_dir == \"U\")\n" " draw_control_button(ctl.D, \"D\", game.vars.want_dir == \"D\")\n" " draw_control_button(ctl.L, \"L\", game.vars.want_dir == \"L\")\n" " draw_control_button(ctl.R, \"R\", game.vars.want_dir == \"R\")\n" "end\n" "\n" "function init()\n" " math.randomseed(12345)\n" " reset_game()\n" " game.set_frame_updates(true)\n" "end\n" "\n" "function update(event)\n" " if event.type == INPUT.BUTTON_1 then\n" " game.exit()\n" " return false\n" " end\n" "\n" " if event.type == INPUT.BUTTON_0 then\n" " reset_game()\n" " return true\n" " end\n" "\n" " if game.vars.state ~= \"playing\" then\n" " if event.type == INPUT.TOUCH_DOWN then\n" " reset_game()\n" " return true\n" " end\n" " return false\n" " end\n" "\n" " if event.type == INPUT.TOUCH_DOWN then\n" " local d = touch_to_dir(event.x, event.y)\n" " if d then\n" " game.vars.want_dir = d\n" " else\n" " handle_touch(event.x, event.y)\n" " end\n" " return false\n" " end\n" "\n" " if event.type == INPUT.FRAME_TICK then\n" " game.vars.tick = game.vars.tick + 1\n" " if game.vars.power_ticks > 0 then\n" " game.vars.power_ticks = game.vars.power_ticks - 1\n" " end\n" "\n" " if game.vars.tick % game.vars.anim_mod == 0 then\n" " game.vars.mouth_open = not game.vars.mouth_open\n" " end\n" "\n" " if game.vars.tick % game.vars.player_step_mod == 0 then\n" " move_player_step()\n" " end\n" "\n" " if game.vars.tick % game.vars.ghost_step_mod == 0 then\n" " move_ghosts_step()\n" " end\n" "\n" " return true\n" " end\n" "\n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" "\n" " renderer.text(math.floor(game.width() / 2) - 18, 22, \"PACMAN\", true)\n" " draw_level()\n" "\n" " local pcx, pcy = tile_center(game.vars.px, game.vars.py)\n" " draw_pacman(pcx, pcy, game.vars.mouth_open, game.vars.dir)\n" "\n" " for i = 1, #game.vars.ghosts do\n" " local g = game.vars.ghosts[i]\n" " local gx, gy = tile_center(g.x, g.y)\n" " local vulnerable = game.vars.power_ticks > 0\n" " local blink = vulnerable and ((game.vars.tick % 10) < 5)\n" " draw_ghost(gx, gy, vulnerable, blink)\n" " end\n" "\n" " local ox, oy, _, ph = level_origin()\n" " renderer.text_scaled(ox, oy + ph + 14, \"SCORE:\" .. tostring(game.vars.score), true, 2)\n" "\n" " if game.vars.power_ticks > 0 then\n" " local secs = math.ceil(game.vars.power_ticks / 24)\n" " renderer.rect(ox + 124, oy + ph + 18, 130, 20, true, false)\n" " renderer.text(ox + 132, oy + ph + 24, \"POWER \" .. tostring(secs) .. \"s\", true)\n" " end\n" "\n" " draw_touch_controls()\n" "\n" " if game.vars.state == \"won\" then\n" " renderer.rect(128, 20, 144, 18, true, false)\n" " renderer.text(178, 26, \"YOU WIN\", true)\n" " elseif game.vars.state == \"lost\" then\n" " renderer.rect(128, 20, 144, 18, true, false)\n" " renderer.text(172, 26, \"GAME OVER\", true)\n" " end\n" "end\n" ""; static const char pong_lua_src[] = "-- NAME: Pong\n" "-- DESC: Classic two-player Pong game\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local PADDLE_WIDTH = 8\n" "local PADDLE_HEIGHT = 40\n" "local BALL_RADIUS = 5\n" "local MAX_SCORE = 5\n" "\n" "-- Initialize game\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.frame_count = 0\n" " \n" " -- Left paddle (player 1)\n" " game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_left_score = 0\n" " \n" " -- Right paddle (player 2)\n" " game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_right_score = 0\n" " \n" " -- Ball\n" " game.vars.ball_x = game.width() / 2\n" " game.vars.ball_y = game.height() / 2\n" " game.vars.ball_vel_x = 3\n" " game.vars.ball_vel_y = 2\n" " \n" " -- Enable continuous frame updates for smooth animation\n" " game.set_frame_updates(true)\n" " \n" " print(\"Pong initialized\")\n" "end\n" "\n" "-- Update game logic\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " -- State: MENU\n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " -- State: PLAYING\n" " elseif state == STATE_PLAYING then\n" " -- Handle paddle input via touch\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then\n" " -- Left side touch moves left paddle, right side touch moves right paddle\n" " if event.x < game.width() / 2 then\n" " -- Move left paddle (constrain within bounds)\n" " game.vars.paddle_left_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))\n" " else\n" " -- Move right paddle (constrain within bounds)\n" " game.vars.paddle_right_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))\n" " end\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " update_ball()\n" " \n" " -- Check win condition\n" " if game.vars.paddle_left_score >= MAX_SCORE or game.vars.paddle_right_score >= MAX_SCORE then\n" " game.vars.state = STATE_GAME_OVER\n" " end\n" " \n" " return true -- Always redraw when playing\n" " end\n" " \n" " -- State: GAME_OVER\n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "-- Draw game\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " -- Draw: MENU\n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 15, game.height() / 2 - 30, \"PONG\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 70, game.height() / 2 + 20, \"First to \" .. tostring(MAX_SCORE), true, 2)\n" " \n" " -- Draw: PLAYING\n" " elseif state == STATE_PLAYING then\n" " -- Draw center line\n" " for y = 0, game.height(), 5 do\n" " renderer.pixel(game.width() / 2, y, true)\n" " end\n" " \n" " -- Draw paddles\n" " renderer.rect(10, game.vars.paddle_left_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)\n" " renderer.rect(game.width() - 10 - PADDLE_WIDTH, game.vars.paddle_right_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)\n" " \n" " -- Draw ball (convert to integers)\n" " renderer.circle(math.floor(game.vars.ball_x + 0.5), math.floor(game.vars.ball_y + 0.5), BALL_RADIUS, true, true)\n" " \n" " -- Draw scores\n" " local left_score_text = tostring(game.vars.paddle_left_score)\n" " local right_score_text = tostring(game.vars.paddle_right_score)\n" " renderer.text_scaled(game.width() / 2 - 30, 5, left_score_text, true, 2)\n" " renderer.text_scaled(game.width() / 2 + 20, 5, right_score_text, true, 2)\n" " \n" " -- Draw: GAME_OVER\n" " elseif state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 30, \"GAME OVER\", true, 2)\n" " \n" " local winner = \"Player 1 Wins!\"\n" " if game.vars.paddle_right_score > game.vars.paddle_left_score then\n" " winner = \"Player 2 Wins!\"\n" " end\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, winner, true, 2)\n" " \n" " local final_text = game.vars.paddle_left_score .. \" - \" .. game.vars.paddle_right_score\n" " renderer.text_scaled(game.width() / 2 - 25, game.height() / 2 + 20, final_text, true, 2)\n" " \n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 40, \"Tap to Menu\", true, 2)\n" " end\n" "end\n" "\n" "-- Helper: Update ball physics\n" "function update_ball()\n" " -- Move ball\n" " game.vars.ball_x = game.vars.ball_x + game.vars.ball_vel_x\n" " game.vars.ball_y = game.vars.ball_y + game.vars.ball_vel_y\n" " \n" " -- Bounce off top/bottom\n" " if game.vars.ball_y - BALL_RADIUS < 0 or game.vars.ball_y + BALL_RADIUS > game.height() then\n" " game.vars.ball_vel_y = -game.vars.ball_vel_y\n" " game.vars.ball_y = math.max(BALL_RADIUS, math.min(game.height() - BALL_RADIUS, game.vars.ball_y))\n" " end\n" " \n" " -- Check left paddle collision\n" " if game.vars.ball_x - BALL_RADIUS < 10 + PADDLE_WIDTH then\n" " if game.vars.ball_y > game.vars.paddle_left_y and game.vars.ball_y < game.vars.paddle_left_y + PADDLE_HEIGHT then\n" " if game.vars.ball_vel_x < 0 then\n" " game.vars.ball_vel_x = -game.vars.ball_vel_x\n" " \n" " -- Add spin based on where ball hits paddle\n" " local hit_pos = (game.vars.ball_y - game.vars.paddle_left_y) / PADDLE_HEIGHT\n" " game.vars.ball_vel_y = (hit_pos - 0.5) * 6\n" " end\n" " end\n" " end\n" " \n" " -- Check right paddle collision\n" " if game.vars.ball_x + BALL_RADIUS > game.width() - 10 - PADDLE_WIDTH then\n" " if game.vars.ball_y > game.vars.paddle_right_y and game.vars.ball_y < game.vars.paddle_right_y + PADDLE_HEIGHT then\n" " if game.vars.ball_vel_x > 0 then\n" " game.vars.ball_vel_x = -game.vars.ball_vel_x\n" " \n" " -- Add spin based on where ball hits paddle\n" " local hit_pos = (game.vars.ball_y - game.vars.paddle_right_y) / PADDLE_HEIGHT\n" " game.vars.ball_vel_y = (hit_pos - 0.5) * 6\n" " end\n" " end\n" " end\n" " \n" " -- Score on left side miss\n" " if game.vars.ball_x < 0 then\n" " game.vars.paddle_right_score = game.vars.paddle_right_score + 1\n" " reset_ball()\n" " end\n" " \n" " -- Score on right side miss\n" " if game.vars.ball_x > game.width() then\n" " game.vars.paddle_left_score = game.vars.paddle_left_score + 1\n" " reset_ball()\n" " end\n" "end\n" "\n" "-- Helper: Reset ball to center\n" "function reset_ball()\n" " game.vars.ball_x = game.width() / 2\n" " game.vars.ball_y = game.height() / 2\n" " game.vars.ball_vel_x = 3 * (math.random() > 0.5 and 1 or -1)\n" " game.vars.ball_vel_y = 2 * (math.random() > 0.5 and 1 or -1)\n" "end\n" "\n" "-- Helper: Reset game\n" "function reset_game()\n" " game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_left_score = 0\n" " game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)\n" " game.vars.paddle_right_score = 0\n" " reset_ball()\n" "end\n" ""; static const char simon_says_lua_src[] = "-- NAME: Simon Says\n" "-- DESC: Repeat the color sequence\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_SHOWING = 2\n" "local STATE_GAME_OVER = 3\n" "\n" "-- Game constants\n" "local SHOW_DURATION = 30 -- Frames to show each button\n" "local WAIT_DURATION = 20 -- Frames between shows\n" "\n" "-- Button positions (calculated dynamically based on screen size)\n" "local function get_buttons()\n" " local padding = math.floor(math.min(game.width(), game.height()) / 10)\n" " local available = math.min(game.width(), game.height()) - (padding * 3)\n" " local button_size = math.floor(available / 2)\n" " local spacing = padding\n" " \n" " return {\n" " {x = padding, y = padding, size = button_size, color = 1}, -- Top-left\n" " {x = padding + button_size + spacing, y = padding, size = button_size, color = 2}, -- Top-right\n" " {x = padding, y = padding + button_size + spacing, size = button_size, color = 3}, -- Bottom-left\n" " {x = padding + button_size + spacing, y = padding + button_size + spacing, size = button_size, color = 4} -- Bottom-right\n" " }\n" "end\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " \n" " -- Sequence of button presses\n" " game.vars.sequence = {}\n" " game.vars.player_seq = {}\n" " \n" " -- Animation state\n" " game.vars.showing_idx = 0\n" " game.vars.show_frame = 0\n" " game.vars.show_button = nil\n" " \n" " -- Input state\n" " game.vars.waiting_for_input = false\n" " game.vars.input_idx = 0\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Simon Says initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Start showing sequence\n" " if event.type == INPUT.FRAME_TICK then\n" " game.vars.show_frame = game.vars.show_frame + 1\n" " return true\n" " end\n" " \n" " return false\n" " \n" " elseif state == STATE_SHOWING then\n" " -- Animate sequence\n" " if event.type == INPUT.FRAME_TICK then\n" " game.vars.show_frame = game.vars.show_frame + 1\n" " \n" " -- Move to next button in sequence\n" " if game.vars.show_frame > SHOW_DURATION + WAIT_DURATION then\n" " game.vars.showing_idx = game.vars.showing_idx + 1\n" " game.vars.show_frame = 0\n" " game.vars.show_button = nil\n" " \n" " -- Done showing sequence, wait for player input\n" " if game.vars.showing_idx > #game.vars.sequence then\n" " game.vars.state = STATE_PLAYING\n" " game.vars.waiting_for_input = true\n" " game.vars.input_idx = 0\n" " end\n" " else\n" " -- Highlight button during show duration\n" " if game.vars.show_frame <= SHOW_DURATION then\n" " game.vars.show_button = game.vars.sequence[game.vars.showing_idx]\n" " else\n" " game.vars.show_button = nil\n" " end\n" " end\n" " \n" " return true\n" " end\n" " \n" " return false\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " -- Handle player input\n" " if game.vars.waiting_for_input and event.type == INPUT.TOUCH_DOWN then\n" " local button = get_button_at(event.x, event.y)\n" " if button then\n" " game.vars.player_seq[#game.vars.player_seq + 1] = button\n" " game.vars.input_idx = game.vars.input_idx + 1\n" " \n" " -- Check if correct\n" " if game.vars.sequence[game.vars.input_idx] ~= button then\n" " -- Wrong! Game over\n" " game.vars.state = STATE_GAME_OVER\n" " return true\n" " end\n" " \n" " -- Check if completed sequence\n" " if game.vars.input_idx == #game.vars.sequence then\n" " -- Advance to next round\n" " game.vars.sequence[#game.vars.sequence + 1] = math.random(1, 4)\n" " game.vars.player_seq = {}\n" " game.vars.waiting_for_input = false\n" " game.vars.showing_idx = 0\n" " game.vars.show_frame = 0\n" " game.vars.show_button = nil\n" " game.vars.state = STATE_SHOWING\n" " game.vars.score = game.vars.score + 1\n" " return true\n" " end\n" " \n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " local buttons = get_buttons()\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 40, \"SIMON SAYS\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 10, \"Repeat the sequence\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Start\", true, 2)\n" " \n" " else\n" " -- Draw buttons with highlight\n" " for i = 1, 4 do\n" " local btn = buttons[i]\n" " local filled = (game.vars.show_button == i)\n" " renderer.rect(btn.x, btn.y, btn.size, btn.size, true, filled)\n" " end\n" " \n" " -- Draw score\n" " renderer.text_scaled(10, 10, \"Level: \" .. tostring(game.vars.score + 1), true, 2)\n" " \n" " if state == STATE_PLAYING and game.vars.waiting_for_input then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() - 20, \"Your turn!\", true, 2)\n" " end\n" " \n" " if state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2 - 20, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 30, game.height() / 2, \"Level: \" .. tostring(game.vars.score + 1), true, 2)\n" " renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Restart\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function get_button_at(x, y)\n" " local buttons = get_buttons()\n" " for i = 1, 4 do\n" " local btn = buttons[i]\n" " if x >= btn.x and x < btn.x + btn.size and\n" " y >= btn.y and y < btn.y + btn.size then\n" " return i\n" " end\n" " end\n" " return nil\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.sequence = {math.random(1, 4)}\n" " game.vars.player_seq = {}\n" " game.vars.showing_idx = 0\n" " game.vars.show_frame = 0\n" " game.vars.show_button = nil\n" " game.vars.waiting_for_input = false\n" " game.vars.input_idx = 0\n" " game.vars.state = STATE_SHOWING\n" "end\n" ""; static const char snake_lua_src[] = "-- NAME: Snake Game\n" "-- DESC: Classic snake with state machine\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local CELL_SIZE = 10\n" "local BTN = 30\n" "local ARENA_WIDTH_RATIO = 0.8\n" "local BASE_MOVE_SPEED = 16\n" "local MAX_SPEED_MULTIPLIER = 5\n" "local DOTS_PER_SPEED_STEP = 10\n" "\n" "local function setup_arena()\n" " game.vars.grid_h = math.floor(game.height() / CELL_SIZE)\n" " game.vars.grid_w = math.floor((game.width() * ARENA_WIDTH_RATIO) / CELL_SIZE)\n" " game.vars.arena_x = 0\n" " game.vars.arena_y = 0\n" " game.vars.arena_w = game.vars.grid_w * CELL_SIZE\n" " game.vars.arena_h = game.vars.grid_h * CELL_SIZE\n" "end\n" "\n" "local function control_positions()\n" " local cx = game.width() - 48\n" " local cy = game.height() - 50\n" " return {\n" " U = {x = cx, y = cy - BTN, w = BTN, h = BTN},\n" " D = {x = cx, y = cy + BTN, w = BTN, h = BTN},\n" " L = {x = cx - BTN, y = cy, w = BTN, h = BTN},\n" " R = {x = cx + BTN, y = cy, w = BTN, h = BTN},\n" " }\n" "end\n" "\n" "local function point_in(px, py, r)\n" " return px >= r.x and px < (r.x + r.w) and py >= r.y and py < (r.y + r.h)\n" "end\n" "\n" "local function touch_to_dir(tx, ty)\n" " local ctl = control_positions()\n" " if point_in(tx, ty, ctl.U) then return \"U\" end\n" " if point_in(tx, ty, ctl.D) then return \"D\" end\n" " if point_in(tx, ty, ctl.L) then return \"L\" end\n" " if point_in(tx, ty, ctl.R) then return \"R\" end\n" " return nil\n" "end\n" "\n" "local function set_dir(dir)\n" " if dir == \"R\" and game.vars.dir_x ~= -1 then\n" " game.vars.dir_x = 1\n" " game.vars.dir_y = 0\n" " elseif dir == \"L\" and game.vars.dir_x ~= 1 then\n" " game.vars.dir_x = -1\n" " game.vars.dir_y = 0\n" " elseif dir == \"D\" and game.vars.dir_y ~= -1 then\n" " game.vars.dir_x = 0\n" " game.vars.dir_y = 1\n" " elseif dir == \"U\" and game.vars.dir_y ~= 1 then\n" " game.vars.dir_x = 0\n" " game.vars.dir_y = -1\n" " end\n" "end\n" "\n" "local function global_touch_to_dir(tx, ty)\n" " local cx = math.floor(game.width() / 2)\n" " local cy = math.floor(game.height() / 2)\n" " local dx = tx - cx\n" " local dy = ty - cy\n" "\n" " if math.abs(dx) > math.abs(dy) then\n" " if dx >= 0 then\n" " return \"R\"\n" " end\n" " return \"L\"\n" " end\n" " if dy >= 0 then\n" " return \"D\"\n" " end\n" " return \"U\"\n" "end\n" "\n" "local function draw_control_button(r, dir, active)\n" " renderer.rect(r.x, r.y, r.w, r.h, true, active)\n" " local cx = r.x + math.floor(r.w / 2)\n" " local cy = r.y + math.floor(r.h / 2)\n" " if dir == \"U\" then\n" " renderer.triangle(cx, cy - 6, cx - 5, cy + 3, cx + 5, cy + 3, not active, true)\n" " elseif dir == \"D\" then\n" " renderer.triangle(cx, cy + 6, cx - 5, cy - 3, cx + 5, cy - 3, not active, true)\n" " elseif dir == \"L\" then\n" " renderer.triangle(cx - 6, cy, cx + 3, cy - 5, cx + 3, cy + 5, not active, true)\n" " else\n" " renderer.triangle(cx + 6, cy, cx - 3, cy - 5, cx - 3, cy + 5, not active, true)\n" " end\n" "end\n" "\n" "local function draw_touch_controls()\n" " local ctl = control_positions()\n" " draw_control_button(ctl.U, \"U\", game.vars.dir_y == -1)\n" " draw_control_button(ctl.D, \"D\", game.vars.dir_y == 1)\n" " draw_control_button(ctl.L, \"L\", game.vars.dir_x == -1)\n" " draw_control_button(ctl.R, \"R\", game.vars.dir_x == 1)\n" "end\n" "\n" "local function draw_dotted_boundary()\n" " local x0 = game.vars.arena_x\n" " local y0 = game.vars.arena_y\n" " local x1 = game.vars.arena_x + game.vars.arena_w - 1\n" " local y1 = game.vars.arena_y + game.vars.arena_h - 1\n" " local step = 4\n" "\n" " local x = x0\n" " while x <= x1 do\n" " renderer.pixel(x, y0, true)\n" " renderer.pixel(x, y1, true)\n" " x = x + step\n" " end\n" "\n" " local y = y0\n" " while y <= y1 do\n" " renderer.pixel(x0, y, true)\n" " renderer.pixel(x1, y, true)\n" " y = y + step\n" " end\n" "end\n" "\n" "local function update_move_speed()\n" " local mult = 1 + math.floor(game.vars.food_eaten / DOTS_PER_SPEED_STEP)\n" " if mult > MAX_SPEED_MULTIPLIER then\n" " mult = MAX_SPEED_MULTIPLIER\n" " end\n" " game.vars.speed_multiplier = mult\n" " game.vars.move_speed = math.max(1, math.floor(BASE_MOVE_SPEED / mult))\n" "end\n" "\n" "-- Initialize game\n" "function init()\n" " setup_arena()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.high_score = 0\n" " \n" " -- Snake as array of {x, y} positions\n" " local cx = math.floor(game.vars.grid_w / 2)\n" " local cy = math.floor(game.vars.grid_h / 2)\n" " game.vars.snake = {}\n" " game.vars.snake[1] = {x = cx, y = cy}\n" " game.vars.snake[2] = {x = cx - 1, y = cy}\n" " game.vars.snake[3] = {x = cx - 2, y = cy}\n" " \n" " game.vars.dir_x = 1\n" " game.vars.dir_y = 0\n" " \n" " game.vars.food_x = math.min(cx + 10, game.vars.grid_w - 1)\n" " game.vars.food_y = cy\n" " \n" " game.vars.frame_count = 0\n" " game.vars.food_eaten = 0\n" " game.vars.speed_multiplier = 1\n" " game.vars.move_speed = BASE_MOVE_SPEED\n" " game.vars.score_submit_pending = false\n" " game.vars.score_submitted = 0\n" " \n" " -- Enable continuous frame updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Snake Game initialized\")\n" "end\n" "\n" "-- Update game logic\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " -- State: MENU\n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_PLAYING\n" " game.vars.score = 0\n" " init_snake()\n" " spawn_food()\n" " return true\n" " end\n" " \n" " -- State: PLAYING\n" " elseif state == STATE_PLAYING then\n" " -- Handle input for direction change\n" " if event.type == INPUT.TOUCH_DOWN then\n" " local d = touch_to_dir(event.x, event.y)\n" " if d then\n" " set_dir(d)\n" " else\n" " set_dir(global_touch_to_dir(event.x, event.y))\n" " end\n" " end\n" " \n" " -- Move snake every N frames\n" " game.vars.frame_count = game.vars.frame_count + 1\n" " if game.vars.frame_count >= game.vars.move_speed then\n" " game.vars.frame_count = 0\n" " move_snake()\n" " return true\n" " end\n" " \n" " -- State: GAME_OVER\n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "-- Draw game\n" "function draw()\n" " renderer.clear(false)\n" " \n" " local state = game.vars.state\n" " \n" " -- Draw: MENU\n" " if state == STATE_MENU then\n" " renderer.text(game.width() / 2 - 30, game.height() / 2 - 20, \"SNAKE\", true)\n" " renderer.text(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true)\n" " \n" " if game.vars.high_score > 0 then\n" " local hs_text = \"High: \" .. tostring(game.vars.high_score)\n" " renderer.text(game.width() / 2 - 30, game.height() / 2 + 20, hs_text, true)\n" " end\n" " \n" " -- Draw: PLAYING\n" " elseif state == STATE_PLAYING then\n" " draw_dotted_boundary()\n" "\n" " -- Draw snake\n" " for i = 1, #game.vars.snake do\n" " local seg = game.vars.snake[i]\n" " local filled = (i == 1) -- Head filled, body outline\n" " renderer.rect(game.vars.arena_x + seg.x * CELL_SIZE, game.vars.arena_y + seg.y * CELL_SIZE, CELL_SIZE, CELL_SIZE, true, filled)\n" " end\n" " \n" " -- Draw food (convert center to integers)\n" " renderer.circle(math.floor(game.vars.arena_x + game.vars.food_x * CELL_SIZE + CELL_SIZE / 2 + 0.5), \n" " math.floor(game.vars.arena_y + game.vars.food_y * CELL_SIZE + CELL_SIZE / 2 + 0.5), \n" " CELL_SIZE / 2, true, true)\n" " \n" " -- Draw score\n" " local score_text = \"Score: \" .. tostring(game.vars.score)\n" " renderer.text(5, 5, score_text, true)\n" " draw_touch_controls()\n" " \n" " -- Draw: GAME_OVER\n" " elseif state == STATE_GAME_OVER then\n" " renderer.text(game.width() / 2 - 40, game.height() / 2 - 20, \"GAME OVER\", true)\n" " \n" " local score_text = \"Score: \" .. tostring(game.vars.score)\n" " renderer.text(game.width() / 2 - 40, game.height() / 2, score_text, true)\n" " \n" " renderer.text(game.width() / 2 - 60, game.height() / 2 + 20, \"Tap to Continue\", true)\n" " end\n" "end\n" "\n" "-- Helper: Initialize snake\n" "function init_snake()\n" " local cx = math.floor(game.vars.grid_w / 2)\n" " local cy = math.floor(game.vars.grid_h / 2)\n" " game.vars.snake = {}\n" " game.vars.snake[1] = {x = cx, y = cy}\n" " game.vars.snake[2] = {x = cx - 1, y = cy}\n" " game.vars.snake[3] = {x = cx - 2, y = cy}\n" " game.vars.dir_x = 1\n" " game.vars.dir_y = 0\n" " game.vars.frame_count = 0\n" " game.vars.food_eaten = 0\n" " update_move_speed()\n" " game.vars.score_submit_pending = false\n" "end\n" "\n" "-- Helper: Spawn food at random position\n" "function spawn_food()\n" " game.vars.food_x = math.random(0, game.vars.grid_w - 1)\n" " game.vars.food_y = math.random(0, game.vars.grid_h - 1)\n" "end\n" "\n" "-- Helper: Move snake\n" "function move_snake()\n" " local head = game.vars.snake[1]\n" " local new_head = {\n" " x = (head.x + game.vars.dir_x) % game.vars.grid_w,\n" " y = (head.y + game.vars.dir_y) % game.vars.grid_h\n" " }\n" " \n" " -- Wrap around negative values (Lua modulo behavior)\n" " if new_head.x < 0 then new_head.x = new_head.x + game.vars.grid_w end\n" " if new_head.y < 0 then new_head.y = new_head.y + game.vars.grid_h end\n" " \n" " -- Check self collision\n" " for i = 1, #game.vars.snake do\n" " local seg = game.vars.snake[i]\n" " if new_head.x == seg.x and new_head.y == seg.y then\n" " game_over()\n" " return\n" " end\n" " end\n" " \n" " -- Check food collision\n" " local ate_food = false\n" " if new_head.x == game.vars.food_x and new_head.y == game.vars.food_y then\n" " ate_food = true\n" " game.vars.score = game.vars.score + 10\n" " game.vars.food_eaten = game.vars.food_eaten + 1\n" " update_move_speed()\n" " spawn_food()\n" " end\n" " \n" " -- Move snake\n" " table.insert(game.vars.snake, 1, new_head)\n" " \n" " if not ate_food then\n" " table.remove(game.vars.snake) -- Remove tail\n" " end\n" "end\n" "\n" "-- Helper: Game over\n" "function game_over()\n" " game.vars.state = STATE_GAME_OVER\n" " \n" " if game.vars.score > game.vars.high_score then\n" " game.vars.high_score = game.vars.score\n" " end\n" "\n" " if not game.vars.score_submit_pending then\n" " game.vars.score_submitted = game.vars.score\n" " game.vars.score_submit_pending = true\n" " end\n" " \n" " print(\"Game Over! Score: \" .. game.vars.score)\n" "end\n" ""; static const char solitaire_lua_src[] = "-- NAME: Solitaire\n" "-- DESC: Klondike-style solitaire\n" "\n" "local CARD_W = 38\n" "local CARD_H = 48\n" "local TOP_Y = 30\n" "local TAB_Y = 98\n" "local LEFT = 37\n" "local GAP_X = 10\n" "local FAN_DOWN = 9\n" "\n" "local SUITS = {\"S\", \"H\", \"D\", \"C\"}\n" "\n" "local function C(r, s, up)\n" " return {r = r, s = s, up = up and true or false}\n" "end\n" "\n" "local function card_color_red(c)\n" " return c.s == \"H\" or c.s == \"D\"\n" "end\n" "\n" "local function rank_text(r)\n" " if r == 1 then return \"A\" end\n" " if r == 11 then return \"J\" end\n" " if r == 12 then return \"Q\" end\n" " if r == 13 then return \"K\" end\n" " return tostring(r)\n" "end\n" "\n" "local SUIT_BITMAPS = {\n" " D = {\n" " \"0001000\",\n" " \"0011100\",\n" " \"0111110\",\n" " \"1111111\",\n" " \"0111110\",\n" " \"0011100\",\n" " \"0001000\",\n" " },\n" " H = {\n" " \"0110110\",\n" " \"1111111\",\n" " \"1111111\",\n" " \"1111111\",\n" " \"0111110\",\n" " \"0011100\",\n" " \"0001000\",\n" " },\n" " S = {\n" " \"0001000\",\n" " \"0011100\",\n" " \"0111110\",\n" " \"1111111\",\n" " \"0011100\",\n" " \"0011100\",\n" " \"0001000\",\n" " },\n" " C = {\n" " \"0011100\",\n" " \"0111110\",\n" " \"0011100\",\n" " \"1111111\",\n" " \"0011100\",\n" " \"0011100\",\n" " \"0001000\",\n" " }\n" "}\n" "\n" "local function label_metrics(label, scale)\n" " local w = (#label * 6 * scale)\n" " local h = (7 * scale)\n" " return w, h\n" "end\n" "\n" "local function draw_suit_icon(x, y, suit, scale)\n" " local bmp = SUIT_BITMAPS[suit]\n" " if not bmp then return end\n" " for row = 1, #bmp do\n" " local line = bmp[row]\n" " for col = 1, #line do\n" " if string.sub(line, col, col) == \"1\" then\n" " renderer.rect(\n" " x + (col - 1) * scale,\n" " y + (row - 1) * scale,\n" " scale,\n" " scale,\n" " true,\n" " true\n" " )\n" " end\n" " end\n" " end\n" "end\n" "\n" "local function make_deck()\n" " local d = {}\n" " for _, s in ipairs(SUITS) do\n" " for r = 1, 13 do\n" " d[#d + 1] = {r = r, s = s, up = false}\n" " end\n" " end\n" " return d\n" "end\n" "\n" "local function shuffle(deck)\n" " for i = #deck, 2, -1 do\n" " local j = math.random(1, i)\n" " deck[i], deck[j] = deck[j], deck[i]\n" " end\n" "end\n" "\n" "local function setup_game()\n" " game.vars.stock = {}\n" " game.vars.waste = {}\n" " game.vars.foundations = {{}, {}, {}, {}}\n" " game.vars.tableau = {{}, {}, {}, {}, {}, {}, {}}\n" " game.vars.selected = nil\n" "\n" " local deck = make_deck()\n" " shuffle(deck)\n" "\n" " -- Klondike deal: 1..7 cards in each tableau column, top card face up\n" " local idx = 1\n" " for col = 1, 7 do\n" " for row = 1, col do\n" " local c = deck[idx]\n" " idx = idx + 1\n" " c.up = (row == col)\n" " game.vars.tableau[col][#game.vars.tableau[col] + 1] = c\n" " end\n" " end\n" "\n" " while idx <= #deck do\n" " local c = deck[idx]\n" " c.up = false\n" " game.vars.stock[#game.vars.stock + 1] = c\n" " idx = idx + 1\n" " end\n" "end\n" "\n" "-- Deterministic mid-game tableau to visually match the provided reference.\n" "local function setup_reference_layout()\n" " game.vars.stock = {}\n" " game.vars.waste = {}\n" " game.vars.foundations = {{}, {}, {}, {}}\n" " game.vars.tableau = {{}, {}, {}, {}, {}, {}, {}}\n" " game.vars.selected = nil\n" "\n" " -- Stock / waste\n" " for i = 1, 24 do\n" " game.vars.stock[#game.vars.stock + 1] = C(((i - 1) % 13) + 1, SUITS[((i - 1) % 4) + 1], false)\n" " end\n" " game.vars.waste[#game.vars.waste + 1] = C(7, \"D\", true)\n" "\n" " -- Foundations: A♣ and 2♠ shown\n" " game.vars.foundations[1] = {C(1, \"C\", true)}\n" " game.vars.foundations[2] = {C(1, \"S\", true), C(2, \"S\", true)}\n" "\n" " -- Tableau (approximate composition from reference image)\n" " game.vars.tableau[1] = {C(13, \"D\", true)}\n" " game.vars.tableau[2] = {C(8, \"C\", false), C(9, \"S\", true)}\n" " game.vars.tableau[3] = {C(4, \"D\", false), C(6, \"C\", false), C(10, \"S\", true)}\n" " game.vars.tableau[4] = {C(5, \"D\", false), C(2, \"C\", false), C(8, \"H\", false), C(3, \"H\", true)}\n" " game.vars.tableau[5] = {C(10, \"D\", false), C(7, \"C\", false), C(4, \"S\", false), C(13, \"S\", true), C(12, \"D\", true), C(11, \"S\", true)}\n" " game.vars.tableau[6] = {C(1, \"D\", false), C(12, \"C\", false), C(6, \"H\", false), C(5, \"S\", false), C(3, \"D\", true)}\n" " game.vars.tableau[7] = {C(9, \"H\", false), C(11, \"C\", false), C(2, \"H\", false), C(6, \"D\", false), C(4, \"H\", false), C(13, \"H\", true)}\n" "end\n" "\n" "local function stock_rect()\n" " return LEFT, TOP_Y, CARD_W, CARD_H\n" "end\n" "\n" "local function waste_rect()\n" " return LEFT + CARD_W + GAP_X, TOP_Y, CARD_W, CARD_H\n" "end\n" "\n" "local function foundation_rect(i)\n" " local x = LEFT + (CARD_W + GAP_X) * (2 + i)\n" " return x, TOP_Y, CARD_W, CARD_H\n" "end\n" "\n" "local function tableau_x(col)\n" " return LEFT + (col - 1) * (CARD_W + GAP_X)\n" "end\n" "\n" "local function point_in(px, py, x, y, w, h)\n" " return px >= x and px < x + w and py >= y and py < y + h\n" "end\n" "\n" "local function can_place_on_tableau(card, target)\n" " if not target then\n" " return card.r == 13 -- only King on empty column\n" " end\n" " if not target.up then return false end\n" " local red1 = card_color_red(card)\n" " local red2 = card_color_red(target)\n" " return red1 ~= red2 and card.r + 1 == target.r\n" "end\n" "\n" "local function can_place_on_foundation(card, pile)\n" " if #pile == 0 then\n" " return card.r == 1\n" " end\n" " local top = pile[#pile]\n" " return top.s == card.s and card.r == top.r + 1\n" "end\n" "\n" "local function reveal_tableau_top(col)\n" " local t = game.vars.tableau[col]\n" " if #t > 0 then\n" " t[#t].up = true\n" " end\n" "end\n" "\n" "local function take_from_tableau(col, start_idx)\n" " local t = game.vars.tableau[col]\n" " local moved = {}\n" " for i = start_idx, #t do\n" " moved[#moved + 1] = t[i]\n" " end\n" " for _ = #t, start_idx, -1 do\n" " t[#t] = nil\n" " end\n" " return moved\n" "end\n" "\n" "local function append_cards(dst, cards)\n" " for i = 1, #cards do\n" " dst[#dst + 1] = cards[i]\n" " end\n" "end\n" "\n" "local function clear_selection()\n" " game.vars.selected = nil\n" "end\n" "\n" "local function select_from_waste()\n" " if #game.vars.waste == 0 then return false end\n" " game.vars.selected = {src = \"waste\"}\n" " return true\n" "end\n" "\n" "local function select_from_foundation(fi)\n" " local pile = game.vars.foundations[fi]\n" " if not pile or #pile == 0 then return false end\n" " game.vars.selected = {src = \"foundation\", idx = fi}\n" " return true\n" "end\n" "\n" "local function select_from_tableau(col, idx)\n" " local t = game.vars.tableau[col]\n" " local c = t[idx]\n" " if not c or not c.up then return false end\n" "\n" " -- Ensure selected run is valid descending alternating colors\n" " for i = idx, #t - 1 do\n" " local a = t[i]\n" " local b = t[i + 1]\n" " if card_color_red(a) == card_color_red(b) or a.r ~= b.r + 1 then\n" " return false\n" " end\n" " end\n" "\n" " game.vars.selected = {src = \"tableau\", col = col, idx = idx}\n" " return true\n" "end\n" "\n" "local function is_valid_tableau_start(col, idx)\n" " local t = game.vars.tableau[col]\n" " local c = t[idx]\n" " if not c or not c.up then return false end\n" "\n" " for i = idx, #t - 1 do\n" " local a = t[i]\n" " local b = t[i + 1]\n" " if card_color_red(a) == card_color_red(b) or a.r ~= b.r + 1 then\n" " return false\n" " end\n" " end\n" " return true\n" "end\n" "\n" "local function next_tableau_selection(col, current_idx, clicked_idx)\n" " local t = game.vars.tableau[col]\n" " if #t == 0 then return nil end\n" "\n" " local candidates = {}\n" " for i = 1, #t do\n" " if is_valid_tableau_start(col, i) then\n" " candidates[#candidates + 1] = i\n" " end\n" " end\n" " if #candidates == 0 then return nil end\n" "\n" " -- Repeated taps on same column cycle through valid starts.\n" " if current_idx then\n" " for k = 1, #candidates do\n" " if candidates[k] == current_idx then\n" " local nk = (k % #candidates) + 1\n" " return candidates[nk]\n" " end\n" " end\n" " end\n" "\n" " -- First tap: choose nearest valid start at/after click; otherwise wrap.\n" " if clicked_idx then\n" " for k = 1, #candidates do\n" " if candidates[k] >= clicked_idx then\n" " return candidates[k]\n" " end\n" " end\n" " end\n" "\n" " return candidates[1]\n" "end\n" "\n" "local function selected_first_card()\n" " local s = game.vars.selected\n" " if not s then return nil end\n" " if s.src == \"waste\" then\n" " return game.vars.waste[#game.vars.waste]\n" " end\n" " if s.src == \"tableau\" then\n" " return game.vars.tableau[s.col][s.idx]\n" " end\n" " if s.src == \"foundation\" then\n" " local pile = game.vars.foundations[s.idx]\n" " if pile and #pile > 0 then return pile[#pile] end\n" " end\n" " return nil\n" "end\n" "\n" "local function try_move_to_foundation(fi)\n" " local s = game.vars.selected\n" " if not s then return false end\n" " local c = selected_first_card()\n" " if not c then return false end\n" "\n" " -- Only single-card moves to foundation\n" " if s.src == \"tableau\" and s.idx ~= #game.vars.tableau[s.col] then\n" " return false\n" " end\n" " if s.src == \"foundation\" then\n" " return false\n" " end\n" "\n" " local pile = game.vars.foundations[fi]\n" " if not can_place_on_foundation(c, pile) then\n" " return false\n" " end\n" "\n" " if s.src == \"waste\" then\n" " game.vars.waste[#game.vars.waste] = nil\n" " else\n" " local t = game.vars.tableau[s.col]\n" " t[#t] = nil\n" " reveal_tableau_top(s.col)\n" " end\n" "\n" " pile[#pile + 1] = c\n" " clear_selection()\n" " return true\n" "end\n" "\n" "local function try_move_to_tableau(col)\n" " local s = game.vars.selected\n" " if not s then return false end\n" " local c = selected_first_card()\n" " if not c then return false end\n" "\n" " local target = nil\n" " local tdst = game.vars.tableau[col]\n" " if #tdst > 0 then target = tdst[#tdst] end\n" " if not can_place_on_tableau(c, target) then\n" " return false\n" " end\n" "\n" " if s.src == \"waste\" then\n" " game.vars.waste[#game.vars.waste] = nil\n" " tdst[#tdst + 1] = c\n" " elseif s.src == \"foundation\" then\n" " local p = game.vars.foundations[s.idx]\n" " p[#p] = nil\n" " tdst[#tdst + 1] = c\n" " else\n" " if s.col == col then return false end\n" " local moved = take_from_tableau(s.col, s.idx)\n" " append_cards(tdst, moved)\n" " reveal_tableau_top(s.col)\n" " end\n" "\n" " clear_selection()\n" " return true\n" "end\n" "\n" "local function draw_card_outline(x, y)\n" " renderer.line(x + 2, y, x + CARD_W - 3, y, true, 1)\n" " renderer.line(x + 2, y + CARD_H - 1, x + CARD_W - 3, y + CARD_H - 1, true, 1)\n" " renderer.line(x, y + 2, x, y + CARD_H - 3, true, 1)\n" " renderer.line(x + CARD_W - 1, y + 2, x + CARD_W - 1, y + CARD_H - 3, true, 1)\n" " renderer.pixel(x + 1, y + 1, true)\n" " renderer.pixel(x + CARD_W - 2, y + 1, true)\n" " renderer.pixel(x + 1, y + CARD_H - 2, true)\n" " renderer.pixel(x + CARD_W - 2, y + CARD_H - 2, true)\n" "end\n" "\n" "local function draw_card_back(x, y)\n" " -- Face-down cards are outline-only for the desired aesthetic.\n" " draw_card_outline(x, y)\n" "end\n" "\n" "local function draw_card_face(c, x, y)\n" " draw_card_outline(x, y)\n" " local rank = rank_text(c.r)\n" " local scale = 1\n" " local rw, rh = label_metrics(rank, scale)\n" " local icon_scale = 1\n" " local icon_w = 7 * icon_scale\n" " local icon_h = 7 * icon_scale\n" " local gap = 1\n" " local lw = rw + gap + icon_w\n" " local lh = math.max(rh, icon_h)\n" " local pad_x = 3\n" " local pad_y = 1\n" "\n" " local top_text_y = y - math.floor(lh / 2)\n" " local left_inset = 4\n" " renderer.rect(x + left_inset, top_text_y - pad_y, lw + pad_x, lh + pad_y + 1, false, true)\n" " renderer.text_scaled(x + left_inset + 1, top_text_y + math.floor((lh - rh) / 2), rank, true, scale)\n" " draw_suit_icon(x + left_inset + 1 + rw + gap, top_text_y + math.floor((lh - icon_h) / 2), c.s, icon_scale)\n" "\n" " local bot_text_y = (y + CARD_H - 1) - math.floor(lh / 2)\n" " local right_inset = 4\n" " local bx = x + CARD_W - lw - pad_x - right_inset\n" " renderer.rect(bx, bot_text_y - pad_y, lw + pad_x, lh + pad_y + 1, false, true)\n" " renderer.text_scaled(bx + 1, bot_text_y + math.floor((lh - rh) / 2), rank, true, scale)\n" " draw_suit_icon(bx + 1 + rw + gap, bot_text_y + math.floor((lh - icon_h) / 2), c.s, icon_scale)\n" "end\n" "\n" "local function draw_card(c, x, y)\n" " if c.up then\n" " draw_card_face(c, x, y)\n" " else\n" " draw_card_back(x, y)\n" " end\n" "end\n" "\n" "local function draw_selected_highlight(x, y)\n" " renderer.rect(x - 1, y - 1, CARD_W + 2, CARD_H + 2, true, false)\n" "end\n" "\n" "local function draw_terminal_chrome()\n" " -- Outer frame\n" " renderer.rect(1, 1, game.width() - 2, game.height() - 2, true, false)\n" " -- Title bar\n" " renderer.rect(2, 2, game.width() - 4, 16, true, false)\n" " renderer.text(math.floor(game.width() / 2) - 27, 6, \"Solitaire\", true)\n" "\n" " -- Window controls (monochrome circles)\n" " renderer.circle(10, 10, 3, true, false)\n" " renderer.circle(20, 10, 3, true, false)\n" " renderer.circle(30, 10, 3, true, false)\n" "end\n" "\n" "local function draw_top_row()\n" " -- Stock\n" " local sx, sy = stock_rect()\n" " if #game.vars.stock > 0 then\n" " draw_card_back(sx, sy)\n" " else\n" " draw_card_outline(sx, sy)\n" " end\n" "\n" " -- Waste\n" " local wx, wy = waste_rect()\n" " local wc = game.vars.waste[#game.vars.waste]\n" " if wc then draw_card_face(wc, wx, wy) else draw_card_outline(wx, wy) end\n" "\n" " -- Foundations\n" " for i = 1, 4 do\n" " local fx, fy = foundation_rect(i)\n" " local pile = game.vars.foundations[i]\n" " local c = pile[#pile]\n" " if c then\n" " draw_card_face(c, fx, fy)\n" " else\n" " draw_card_outline(fx, fy)\n" " end\n" " end\n" "end\n" "\n" "local function draw_tableau()\n" " for col = 1, 7 do\n" " local x = tableau_x(col)\n" " local t = game.vars.tableau[col]\n" "\n" " if #t == 0 then\n" " draw_card_outline(x, TAB_Y)\n" " else\n" " for i = 1, #t do\n" " local y = TAB_Y + (i - 1) * FAN_DOWN\n" " local c = t[i]\n" " draw_card(c, x, y)\n" "\n" " -- Make stacked cards opaque; only top card is fully visible.\n" " if i < #t then\n" " local next_y = TAB_Y + i * FAN_DOWN\n" " local cut_h = (y + CARD_H) - next_y\n" " if cut_h > 0 then\n" " renderer.rect(x - 2, next_y - 5, CARD_W + 4, cut_h + 10, false, true)\n" " end\n" " end\n" " end\n" " end\n" " end\n" "end\n" "\n" "local function draw_selection()\n" " local s = game.vars.selected\n" " if not s then return end\n" "\n" " if s.src == \"waste\" then\n" " local x, y = waste_rect()\n" " draw_selected_highlight(x, y)\n" " elseif s.src == \"foundation\" then\n" " local x, y = foundation_rect(s.idx)\n" " draw_selected_highlight(x, y)\n" " elseif s.src == \"tableau\" then\n" " local x = tableau_x(s.col)\n" " local y = TAB_Y + (s.idx - 1) * FAN_DOWN\n" " draw_selected_highlight(x, y)\n" " end\n" "end\n" "\n" "local function can_selected_move_to_foundation(fi)\n" " local s = game.vars.selected\n" " if not s then return false end\n" " if s.src == \"foundation\" then return false end\n" "\n" " local c = selected_first_card()\n" " if not c then return false end\n" "\n" " -- Only a single top tableau card or waste card can go to foundation.\n" " if s.src == \"tableau\" and s.idx ~= #game.vars.tableau[s.col] then\n" " return false\n" " end\n" "\n" " return can_place_on_foundation(c, game.vars.foundations[fi])\n" "end\n" "\n" "local function can_selected_move_to_tableau(col)\n" " local s = game.vars.selected\n" " if not s then return false end\n" "\n" " local c = selected_first_card()\n" " if not c then return false end\n" "\n" " if s.src == \"tableau\" and s.col == col then\n" " return false\n" " end\n" "\n" " local tdst = game.vars.tableau[col]\n" " local target = nil\n" " if #tdst > 0 then target = tdst[#tdst] end\n" " return can_place_on_tableau(c, target)\n" "end\n" "\n" "local function draw_down_arrow(cx, y)\n" " renderer.line(cx - 3, y, cx, y + 4, true, 1)\n" " renderer.line(cx + 3, y, cx, y + 4, true, 1)\n" "end\n" "\n" "local function draw_up_arrow(cx, y)\n" " renderer.line(cx - 3, y + 4, cx, y, true, 1)\n" " renderer.line(cx + 3, y + 4, cx, y, true, 1)\n" "end\n" "\n" "local function draw_move_hints()\n" " if not game.vars.selected then return end\n" "\n" " -- Tableau destinations: down arrows above each target stack.\n" " for col = 1, 7 do\n" " if can_selected_move_to_tableau(col) then\n" " local x = tableau_x(col)\n" " draw_down_arrow(x + math.floor(CARD_W / 2), TAB_Y - 7)\n" " end\n" " end\n" "\n" " -- Foundation destinations: up arrows under each target foundation.\n" " for i = 1, 4 do\n" " if can_selected_move_to_foundation(i) then\n" " local fx, fy = foundation_rect(i)\n" " draw_up_arrow(fx + math.floor(CARD_W / 2), fy + CARD_H + 2)\n" " end\n" " end\n" "end\n" "\n" "local function handle_touch(x, y)\n" " -- Stock click: draw from stock or recycle waste\n" " do\n" " local sx, sy, sw, sh = stock_rect()\n" " if point_in(x, y, sx, sy, sw, sh) then\n" " clear_selection()\n" " if #game.vars.stock > 0 then\n" " local c = game.vars.stock[#game.vars.stock]\n" " game.vars.stock[#game.vars.stock] = nil\n" " c.up = true\n" " game.vars.waste[#game.vars.waste + 1] = c\n" " else\n" " while #game.vars.waste > 0 do\n" " local c = game.vars.waste[#game.vars.waste]\n" " game.vars.waste[#game.vars.waste] = nil\n" " c.up = false\n" " game.vars.stock[#game.vars.stock + 1] = c\n" " end\n" " end\n" " return true\n" " end\n" " end\n" "\n" " -- Foundation click: try move selected there, else select nothing\n" " for i = 1, 4 do\n" " local fx, fy, fw, fh = foundation_rect(i)\n" " if point_in(x, y, fx, fy, fw, fh) then\n" " if game.vars.selected then\n" " if try_move_to_foundation(i) then\n" " return true\n" " end\n" " if game.vars.selected.src == \"foundation\" and game.vars.selected.idx == i then\n" " clear_selection()\n" " return true\n" " end\n" " clear_selection()\n" " return true\n" " end\n" "\n" " if select_from_foundation(i) then\n" " return true\n" " end\n" "\n" " return true\n" " end\n" " end\n" "\n" " -- Waste click: select waste top\n" " do\n" " local wx, wy, ww, wh = waste_rect()\n" " if point_in(x, y, wx, wy, ww, wh) then\n" " if game.vars.selected and game.vars.selected.src == \"waste\" then\n" " clear_selection()\n" " else\n" " select_from_waste()\n" " end\n" " return true\n" " end\n" " end\n" "\n" " -- Tableau click: move selected onto column or select card/run\n" " for col = 1, 7 do\n" " local x0 = tableau_x(col)\n" " local t = game.vars.tableau[col]\n" "\n" " local hit = false\n" " local idx = nil\n" "\n" " if #t == 0 then\n" " if point_in(x, y, x0, TAB_Y, CARD_W, CARD_H) then\n" " hit = true\n" " end\n" " else\n" " -- Expanded hit area by fan depth, with index based on Y\n" " local y0 = TAB_Y\n" " local y1 = TAB_Y + (#t - 1) * FAN_DOWN + CARD_H\n" " if point_in(x, y, x0, y0, CARD_W, y1 - y0) then\n" " hit = true\n" " idx = math.floor((y - TAB_Y) / FAN_DOWN) + 1\n" " if idx < 1 then idx = 1 end\n" " if idx > #t then idx = #t end\n" " -- If clicked lower covered part, snap to nearest visible face-up boundary\n" " while idx < #t and (TAB_Y + idx * FAN_DOWN) > y do\n" " idx = idx - 1\n" " end\n" " end\n" " end\n" "\n" " if hit then\n" " if game.vars.selected then\n" " if try_move_to_tableau(col) then\n" " return true\n" " end\n" " end\n" "\n" " if #t > 0 then\n" " if game.vars.selected and game.vars.selected.src == \"tableau\" and game.vars.selected.col == col then\n" " local next_idx = next_tableau_selection(col, game.vars.selected.idx, idx)\n" " if next_idx then\n" " game.vars.selected = {src = \"tableau\", col = col, idx = next_idx}\n" " else\n" " clear_selection()\n" " end\n" " elseif t[idx] and t[idx].up then\n" " if not select_from_tableau(col, idx) then\n" " local next_idx = next_tableau_selection(col, nil, idx)\n" " if next_idx then\n" " game.vars.selected = {src = \"tableau\", col = col, idx = next_idx}\n" " else\n" " clear_selection()\n" " end\n" " end\n" " else\n" " clear_selection()\n" " end\n" " else\n" " clear_selection()\n" " end\n" " return true\n" " end\n" " end\n" "\n" " clear_selection()\n" " return true\n" "end\n" "\n" "local function check_win()\n" " for i = 1, 4 do\n" " if #game.vars.foundations[i] ~= 13 then\n" " return false\n" " end\n" " end\n" " return true\n" "end\n" "\n" "local function card_can_move_to_any_foundation(card)\n" " for i = 1, 4 do\n" " if can_place_on_foundation(card, game.vars.foundations[i]) then\n" " return true\n" " end\n" " end\n" " return false\n" "end\n" "\n" "local function card_can_move_to_any_tableau(card, src_col)\n" " for col = 1, 7 do\n" " if not src_col or col ~= src_col then\n" " local t = game.vars.tableau[col]\n" " local target = nil\n" " if #t > 0 then target = t[#t] end\n" " if can_place_on_tableau(card, target) then\n" " return true\n" " end\n" " end\n" " end\n" " return false\n" "end\n" "\n" "local function has_progress_move()\n" " -- Any legal move from tableau runs/tops?\n" " for col = 1, 7 do\n" " local t = game.vars.tableau[col]\n" " for idx = 1, #t do\n" " if is_valid_tableau_start(col, idx) then\n" " local c = t[idx]\n" " if card_can_move_to_any_tableau(c, col) then\n" " return true\n" " end\n" " if idx == #t and card_can_move_to_any_foundation(c) then\n" " return true\n" " end\n" " end\n" " end\n" " end\n" "\n" " -- Any foundation top can move to tableau?\n" " for i = 1, 4 do\n" " local p = game.vars.foundations[i]\n" " if #p > 0 and card_can_move_to_any_tableau(p[#p], nil) then\n" " return true\n" " end\n" " end\n" "\n" " -- Any stock or waste card can eventually be played (draw-1 with recycle)?\n" " for i = 1, #game.vars.waste do\n" " local c = game.vars.waste[i]\n" " if card_can_move_to_any_foundation(c) or card_can_move_to_any_tableau(c, nil) then\n" " return true\n" " end\n" " end\n" " for i = 1, #game.vars.stock do\n" " local c = game.vars.stock[i]\n" " if card_can_move_to_any_foundation(c) or card_can_move_to_any_tableau(c, nil) then\n" " return true\n" " end\n" " end\n" "\n" " return false\n" "end\n" "\n" "local function recompute_end_state()\n" " game.vars.won = check_win()\n" " game.vars.lost = (not game.vars.won) and (not has_progress_move())\n" "end\n" "\n" "function init()\n" " setup_game()\n" " game.vars.won = false\n" " game.vars.lost = false\n" " recompute_end_state()\n" "end\n" "\n" "function update(event)\n" " if game.vars.won then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 then\n" " setup_game()\n" " game.vars.won = false\n" " game.vars.lost = false\n" " recompute_end_state()\n" " return true\n" " elseif event.type == INPUT.BUTTON_1 then\n" " game.exit()\n" " return false\n" " end\n" " return false\n" " end\n" "\n" " if game.vars.lost then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 then\n" " setup_game()\n" " game.vars.won = false\n" " game.vars.lost = false\n" " recompute_end_state()\n" " return true\n" " elseif event.type == INPUT.BUTTON_1 then\n" " game.exit()\n" " return false\n" " end\n" " return false\n" " end\n" "\n" " if event.type == INPUT.TOUCH_DOWN then\n" " local changed = handle_touch(event.x, event.y)\n" " recompute_end_state()\n" " return changed\n" " end\n" "\n" " if event.type == INPUT.BUTTON_0 then\n" " setup_game()\n" " game.vars.won = false\n" " game.vars.lost = false\n" " recompute_end_state()\n" " return true\n" " end\n" "\n" " if event.type == INPUT.BUTTON_1 then\n" " game.exit()\n" " return false\n" " end\n" "\n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" "\n" " draw_terminal_chrome()\n" " draw_top_row()\n" " draw_tableau()\n" " draw_move_hints()\n" " draw_selection()\n" "\n" " if game.vars.won then\n" " renderer.rect(75, 120, 250, 52, true, false)\n" " renderer.text(160, 136, \"YOU WIN\", true)\n" " renderer.text(112, 152, \"Tap: new B1:exit\", true)\n" " elseif game.vars.lost then\n" " renderer.rect(60, 120, 280, 52, true, false)\n" " renderer.text(150, 136, \"NO MOVES\", true)\n" " renderer.text(102, 152, \"Tap/B0: new B1:exit\", true)\n" " else\n" " renderer.text(8, game.height() - 12, \"B0:new B1:exit\", true)\n" " end\n" "end\n" ""; static const char tetris_lua_src[] = "-- NAME: Tetris\n" "-- DESC: Stack falling blocks, clear lines\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local GRID_WIDTH = 10\n" "local GRID_HEIGHT = 20\n" "local CELL_SIZE = 8\n" "local SPAWN_RATE = 30 -- Frames before piece drops\n" "\n" "-- Tetromino shapes (4 orientations each)\n" "local TETROMINOS = {\n" " -- I piece\n" " {\n" " {{0, 0}, {1, 0}, {2, 0}, {3, 0}},\n" " {{0, 0}, {0, 1}, {0, 2}, {0, 3}},\n" " {{0, 0}, {1, 0}, {2, 0}, {3, 0}},\n" " {{0, 0}, {0, 1}, {0, 2}, {0, 3}}\n" " },\n" " -- O piece\n" " {\n" " {{0, 0}, {1, 0}, {0, 1}, {1, 1}},\n" " {{0, 0}, {1, 0}, {0, 1}, {1, 1}},\n" " {{0, 0}, {1, 0}, {0, 1}, {1, 1}},\n" " {{0, 0}, {1, 0}, {0, 1}, {1, 1}}\n" " },\n" " -- T piece\n" " {\n" " {{1, 0}, {0, 1}, {1, 1}, {2, 1}},\n" " {{1, 0}, {0, 1}, {1, 1}, {1, 2}},\n" " {{0, 1}, {1, 1}, {2, 1}, {1, 2}},\n" " {{1, 0}, {1, 1}, {2, 1}, {1, 2}}\n" " },\n" " -- S piece\n" " {\n" " {{1, 0}, {2, 0}, {0, 1}, {1, 1}},\n" " {{0, 0}, {0, 1}, {1, 1}, {1, 2}},\n" " {{1, 0}, {2, 0}, {0, 1}, {1, 1}},\n" " {{0, 0}, {0, 1}, {1, 1}, {1, 2}}\n" " },\n" " -- Z piece\n" " {\n" " {{0, 0}, {1, 0}, {1, 1}, {2, 1}},\n" " {{1, 0}, {0, 1}, {1, 1}, {0, 2}},\n" " {{0, 0}, {1, 0}, {1, 1}, {2, 1}},\n" " {{1, 0}, {0, 1}, {1, 1}, {0, 2}}\n" " },\n" " -- J piece\n" " {\n" " {{0, 0}, {0, 1}, {1, 1}, {2, 1}},\n" " {{1, 0}, {2, 0}, {1, 1}, {1, 2}},\n" " {{0, 1}, {1, 1}, {2, 1}, {2, 0}},\n" " {{1, 0}, {1, 1}, {0, 2}, {1, 2}}\n" " },\n" " -- L piece\n" " {\n" " {{2, 0}, {0, 1}, {1, 1}, {2, 1}},\n" " {{1, 0}, {1, 1}, {1, 2}, {2, 2}},\n" " {{0, 1}, {1, 1}, {2, 1}, {0, 0}},\n" " {{0, 0}, {1, 0}, {1, 1}, {1, 2}}\n" " }\n" "}\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.score = 0\n" " game.vars.level = 1\n" " game.vars.lines = 0\n" " \n" " -- Grid (0 = empty, 1 = filled)\n" " game.vars.grid = {}\n" " for y = 1, GRID_HEIGHT do\n" " game.vars.grid[y] = {}\n" " for x = 1, GRID_WIDTH do\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " \n" " -- Current piece\n" " game.vars.piece = nil\n" " game.vars.piece_x = 0\n" " game.vars.piece_y = 0\n" " game.vars.piece_type = 0\n" " game.vars.piece_rotation = 0\n" " \n" " -- Animation\n" " game.vars.frame_count = 0\n" " game.vars.clear_rows = {}\n" " game.vars.clearing = false\n" " game.vars.score_submit_pending = false\n" " game.vars.score_submitted = 0\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Tetris initialized\")\n" "end\n" "\n" "function set_game_over()\n" " if game.vars.state ~= STATE_GAME_OVER then\n" " game.vars.state = STATE_GAME_OVER\n" " game.vars.score_submitted = game.vars.score\n" " game.vars.score_submit_pending = true\n" " end\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " -- Handle input\n" " if event.type == INPUT.TOUCH_DOWN then\n" " if event.x < game.width() / 2 then\n" " -- Left side: move left\n" " if can_move(game.vars.piece, game.vars.piece_x - 1, game.vars.piece_y, game.vars.piece_rotation) then\n" " game.vars.piece_x = game.vars.piece_x - 1\n" " end\n" " else\n" " -- Right side: move right\n" " if can_move(game.vars.piece, game.vars.piece_x + 1, game.vars.piece_y, game.vars.piece_rotation) then\n" " game.vars.piece_x = game.vars.piece_x + 1\n" " end\n" " end\n" " return true\n" " end\n" " \n" " -- Update physics on frame tick\n" " if event.type == INPUT.FRAME_TICK then\n" " game.vars.frame_count = game.vars.frame_count + 1\n" " \n" " if game.vars.clearing then\n" " -- Clear animation\n" " if game.vars.frame_count % 10 == 0 then\n" " clear_lines()\n" " game.vars.clearing = false\n" " end\n" " else\n" " -- Drop piece\n" " if game.vars.frame_count >= SPAWN_RATE then\n" " game.vars.frame_count = 0\n" " \n" " if can_move(game.vars.piece, game.vars.piece_x, game.vars.piece_y + 1, game.vars.piece_rotation) then\n" " game.vars.piece_y = game.vars.piece_y + 1\n" " else\n" " -- Lock piece\n" " lock_piece()\n" " \n" " -- Check for complete lines\n" " local complete = check_complete_lines()\n" " if #complete > 0 then\n" " game.vars.clear_rows = complete\n" " game.vars.clearing = true\n" " else\n" " spawn_piece()\n" " end\n" " end\n" " end\n" " end\n" " \n" " return true\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false) -- Black background\n" " \n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 20, game.height() / 2 - 30, \"TETRIS\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_GAME_OVER then\n" " -- Draw grid\n" " local start_x = 20\n" " local start_y = 15\n" " \n" " for y = 1, GRID_HEIGHT do\n" " for x = 1, GRID_WIDTH do\n" " if game.vars.grid[y][x] == 1 then\n" " renderer.rect(start_x + (x - 1) * CELL_SIZE, start_y + (y - 1) * CELL_SIZE, CELL_SIZE, CELL_SIZE, true, true)\n" " end\n" " end\n" " end\n" " \n" " -- Draw current piece\n" " if game.vars.piece then\n" " for _, block in ipairs(game.vars.piece) do\n" " local x = start_x + (game.vars.piece_x + block[1]) * CELL_SIZE\n" " local y = start_y + (game.vars.piece_y + block[2]) * CELL_SIZE\n" " renderer.rect(x, y, CELL_SIZE, CELL_SIZE, true, true)\n" " end\n" " end\n" " \n" " -- Draw score\n" " renderer.text_scaled(game.width() - 50, 10, \"Score: \" .. tostring(game.vars.score), true, 2)\n" " renderer.text_scaled(game.width() - 50, 20, \"Lines: \" .. tostring(game.vars.lines), true, 2)\n" " \n" " if state == STATE_GAME_OVER then\n" " renderer.text_scaled(game.width() / 2 - 40, game.height() / 2, \"GAME OVER\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function spawn_piece()\n" " game.vars.piece_type = math.random(1, #TETROMINOS)\n" " game.vars.piece_rotation = 1\n" " game.vars.piece = TETROMINOS[game.vars.piece_type][game.vars.piece_rotation]\n" " game.vars.piece_x = 3\n" " game.vars.piece_y = 0\n" " \n" " -- Check if game over\n" " if not can_move(game.vars.piece, game.vars.piece_x, game.vars.piece_y, game.vars.piece_rotation) then\n" " set_game_over()\n" " end\n" "end\n" "\n" "function lock_piece()\n" " if not game.vars.piece then return end\n" " \n" " for _, block in ipairs(game.vars.piece) do\n" " local x = game.vars.piece_x + block[1] + 1\n" " local y = game.vars.piece_y + block[2] + 1\n" " \n" " if y >= 1 and y <= GRID_HEIGHT and x >= 1 and x <= GRID_WIDTH then\n" " game.vars.grid[y][x] = 1\n" " end\n" " end\n" "end\n" "\n" "function can_move(piece, x, y, rotation)\n" " if not piece then return false end\n" " \n" " for _, block in ipairs(piece) do\n" " local grid_x = x + block[1] + 1\n" " local grid_y = y + block[2] + 1\n" " \n" " if grid_x < 1 or grid_x > GRID_WIDTH or grid_y < 1 or grid_y > GRID_HEIGHT then\n" " return false\n" " end\n" " \n" " if game.vars.grid[grid_y][grid_x] == 1 then\n" " return false\n" " end\n" " end\n" " \n" " return true\n" "end\n" "\n" "function check_complete_lines()\n" " local complete = {}\n" " \n" " for y = 1, GRID_HEIGHT do\n" " local full = true\n" " for x = 1, GRID_WIDTH do\n" " if game.vars.grid[y][x] == 0 then\n" " full = false\n" " break\n" " end\n" " end\n" " \n" " if full then\n" " table.insert(complete, y)\n" " end\n" " end\n" " \n" " return complete\n" "end\n" "\n" "function clear_lines()\n" " for _, y in ipairs(game.vars.clear_rows) do\n" " -- Remove line\n" " table.remove(game.vars.grid, y)\n" " -- Add empty line at top\n" " table.insert(game.vars.grid, 1, {})\n" " for x = 1, GRID_WIDTH do\n" " game.vars.grid[1][x] = 0\n" " end\n" " end\n" " \n" " game.vars.score = game.vars.score + (#game.vars.clear_rows * 100)\n" " game.vars.lines = game.vars.lines + #game.vars.clear_rows\n" " game.vars.clear_rows = {}\n" " \n" " spawn_piece()\n" "end\n" "\n" "function reset_game()\n" " game.vars.score = 0\n" " game.vars.level = 1\n" " game.vars.lines = 0\n" " game.vars.frame_count = 0\n" " game.vars.clearing = false\n" " game.vars.score_submit_pending = false\n" " \n" " -- Clear grid\n" " for y = 1, GRID_HEIGHT do\n" " for x = 1, GRID_WIDTH do\n" " game.vars.grid[y][x] = 0\n" " end\n" " end\n" " \n" " spawn_piece()\n" "end\n" ""; static const char tic_tac_toe_lua_src[] = "-- NAME: Tic-Tac-Toe\n" "-- DESC: Play vs AI opponent\n" "\n" "-- Game states\n" "local STATE_MENU = 0\n" "local STATE_PLAYING = 1\n" "local STATE_GAME_OVER = 2\n" "\n" "-- Game constants\n" "local GRID_SIZE = 3\n" "\n" "-- Calculate cell size based on screen size\n" "local function get_cell_size()\n" " -- Use smallest dimension to maintain square grid\n" " local min_dim = math.min(game.width(), game.height())\n" " local padding = math.floor(min_dim / 8)\n" " local available = min_dim - (padding * 2)\n" " local cell_size = math.floor(available / GRID_SIZE)\n" " return cell_size\n" "end\n" "\n" "local function get_grid_start_y()\n" " -- Center grid vertically\n" " local cell_size = get_cell_size()\n" " local grid_height = cell_size * GRID_SIZE\n" " return math.floor((game.height() - grid_height) / 2)\n" "end\n" "\n" "local function get_grid_start_x()\n" " -- Center grid horizontally\n" " local cell_size = get_cell_size()\n" " local grid_width = cell_size * GRID_SIZE\n" " return math.floor((game.width() - grid_width) / 2)\n" "end\n" "\n" "function init()\n" " game.vars.state = STATE_MENU\n" " game.vars.grid = {}\n" " game.vars.player = 1 -- 1 = X, 2 = O\n" " game.vars.ai = 2\n" " game.vars.game_over = false\n" " game.vars.winner = 0 -- 0 = ongoing, 1 = player wins, 2 = ai wins, 3 = draw\n" " \n" " -- Enable continuous updates\n" " game.set_frame_updates(true)\n" " \n" " print(\"Tic-Tac-Toe initialized\")\n" "end\n" "\n" "function update(event)\n" " local state = game.vars.state\n" " \n" " if state == STATE_MENU then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " reset_game()\n" " game.vars.state = STATE_PLAYING\n" " return true\n" " end\n" " \n" " elseif state == STATE_PLAYING then\n" " if event.type == INPUT.TOUCH_DOWN then\n" " local cell = get_cell_at(event.x, event.y)\n" " if cell and game.vars.grid[cell] == 0 then\n" " -- Player move\n" " game.vars.grid[cell] = game.vars.player\n" " \n" " -- Check win\n" " local winner = check_winner()\n" " if winner ~= 0 then\n" " if winner == game.vars.player then\n" " game.vars.winner = 1\n" " else\n" " game.vars.winner = 2\n" " end\n" " game.vars.state = STATE_GAME_OVER\n" " return true\n" " end\n" " \n" " -- Check draw\n" " if is_board_full() then\n" " game.vars.winner = 3\n" " game.vars.state = STATE_GAME_OVER\n" " return true\n" " end\n" " \n" " -- AI move\n" " local ai_move = find_best_move()\n" " game.vars.grid[ai_move] = game.vars.ai\n" " \n" " -- Check win\n" " winner = check_winner()\n" " if winner ~= 0 then\n" " if winner == game.vars.ai then\n" " game.vars.winner = 2\n" " end\n" " game.vars.state = STATE_GAME_OVER\n" " return true\n" " end\n" " \n" " -- Check draw\n" " if is_board_full() then\n" " game.vars.winner = 3\n" " game.vars.state = STATE_GAME_OVER\n" " return true\n" " end\n" " \n" " return true\n" " end\n" " end\n" " \n" " elseif state == STATE_GAME_OVER then\n" " if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then\n" " game.vars.state = STATE_MENU\n" " return true\n" " end\n" " end\n" " \n" " return false\n" "end\n" "\n" "function draw()\n" " renderer.clear(false)\n" " \n" " local state = game.vars.state\n" " local cell_size = get_cell_size()\n" " local start_x = get_grid_start_x()\n" " local start_y = get_grid_start_y()\n" " local cell_spacing = 2\n" " \n" " if state == STATE_MENU then\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 - 30, \"TIC-TAC-TOE\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, \"Play vs AI\", true, 2)\n" " renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 20, \"Tap to Start\", true, 2)\n" " \n" " elseif state == STATE_PLAYING or state == STATE_GAME_OVER then\n" " -- Draw grid\n" " for row = 0, GRID_SIZE - 1 do\n" " for col = 0, GRID_SIZE - 1 do\n" " local cell_idx = row * GRID_SIZE + col + 1\n" " local cell_x = start_x + col * (cell_size + cell_spacing)\n" " local cell_y = start_y + row * (cell_size + cell_spacing)\n" " \n" " -- Draw cell\n" " renderer.rect(cell_x, cell_y, cell_size, cell_size, true, false)\n" " \n" " -- Draw X or O\n" " local value = game.vars.grid[cell_idx]\n" " if value == 1 then\n" " -- Draw X\n" " renderer.line(cell_x + 2, cell_y + 2, cell_x + cell_size - 2, cell_y + cell_size - 2, true, 1)\n" " renderer.line(cell_x + cell_size - 2, cell_y + 2, cell_x + 2, cell_y + cell_size - 2, true, 1)\n" " elseif value == 2 then\n" " -- Draw O (convert center to integers)\n" " renderer.circle(math.floor(cell_x + cell_size / 2 + 0.5), math.floor(cell_y + cell_size / 2 + 0.5), math.floor(cell_size / 2 - 2 + 0.5), true, false)\n" " end\n" " end\n" " end\n" " \n" " if state == STATE_GAME_OVER then\n" " if game.vars.winner == 1 then\n" " renderer.text_scaled(game.width() / 2 - 30, 10, \"YOU WIN!\", true, 2)\n" " elseif game.vars.winner == 2 then\n" " renderer.text_scaled(game.width() / 2 - 30, 10, \"AI WINS!\", true, 2)\n" " else\n" " renderer.text_scaled(game.width() / 2 - 20, 10, \"DRAW!\", true, 2)\n" " end\n" " \n" " renderer.text_scaled(game.width() / 2 - 60, game.height() - 15, \"Tap to Menu\", true, 2)\n" " end\n" " end\n" "end\n" "\n" "function get_cell_at(x, y)\n" " local cell_size = get_cell_size()\n" " local start_x = get_grid_start_x()\n" " local start_y = get_grid_start_y()\n" " local cell_spacing = 2\n" " \n" " for row = 0, GRID_SIZE - 1 do\n" " for col = 0, GRID_SIZE - 1 do\n" " local cell_x = start_x + col * (cell_size + cell_spacing)\n" " local cell_y = start_y + row * (cell_size + cell_spacing)\n" " \n" " if x >= cell_x and x < cell_x + cell_size and\n" " y >= cell_y and y < cell_y + cell_size then\n" " return row * GRID_SIZE + col + 1\n" " end\n" " end\n" " end\n" " \n" " return nil\n" "end\n" "\n" "function check_winner()\n" " -- Check rows\n" " for row = 0, GRID_SIZE - 1 do\n" " local val = game.vars.grid[row * GRID_SIZE + 1]\n" " if val ~= 0 then\n" " local match = true\n" " for col = 1, GRID_SIZE - 1 do\n" " if game.vars.grid[row * GRID_SIZE + col + 1] ~= val then\n" " match = false\n" " break\n" " end\n" " end\n" " if match then return val end\n" " end\n" " end\n" " \n" " -- Check columns\n" " for col = 0, GRID_SIZE - 1 do\n" " local val = game.vars.grid[col + 1]\n" " if val ~= 0 then\n" " local match = true\n" " for row = 1, GRID_SIZE - 1 do\n" " if game.vars.grid[row * GRID_SIZE + col + 1] ~= val then\n" " match = false\n" " break\n" " end\n" " end\n" " if match then return val end\n" " end\n" " end\n" " \n" " -- Check diagonals\n" " local val = game.vars.grid[1]\n" " if val ~= 0 then\n" " if game.vars.grid[5] == val and game.vars.grid[9] == val then\n" " return val\n" " end\n" " end\n" " \n" " val = game.vars.grid[3]\n" " if val ~= 0 then\n" " if game.vars.grid[5] == val and game.vars.grid[7] == val then\n" " return val\n" " end\n" " end\n" " \n" " return 0\n" "end\n" "\n" "function is_board_full()\n" " for i = 1, 9 do\n" " if game.vars.grid[i] == 0 then\n" " return false\n" " end\n" " end\n" " return true\n" "end\n" "\n" "function find_best_move()\n" " local best_score = -1000\n" " local best_move = nil\n" " \n" " for i = 1, 9 do\n" " if game.vars.grid[i] == 0 then\n" " game.vars.grid[i] = game.vars.ai\n" " local score = minimax(0, false)\n" " game.vars.grid[i] = 0\n" " \n" " if score > best_score then\n" " best_score = score\n" " best_move = i\n" " end\n" " end\n" " end\n" " \n" " return best_move or 5 -- Fallback to center\n" "end\n" "\n" "function minimax(depth, is_maximizing)\n" " local winner = check_winner()\n" " \n" " if winner == game.vars.ai then return 10 - depth end\n" " if winner == game.vars.player then return depth - 10 end\n" " if is_board_full() then return 0 end\n" " \n" " if is_maximizing then\n" " local best_score = -1000\n" " for i = 1, 9 do\n" " if game.vars.grid[i] == 0 then\n" " game.vars.grid[i] = game.vars.ai\n" " local score = minimax(depth + 1, false)\n" " game.vars.grid[i] = 0\n" " best_score = math.max(best_score, score)\n" " end\n" " end\n" " return best_score\n" " else\n" " local best_score = 1000\n" " for i = 1, 9 do\n" " if game.vars.grid[i] == 0 then\n" " game.vars.grid[i] = game.vars.player\n" " local score = minimax(depth + 1, true)\n" " game.vars.grid[i] = 0\n" " best_score = math.min(best_score, score)\n" " end\n" " end\n" " return best_score\n" " end\n" "end\n" "\n" "function reset_game()\n" " game.vars.grid = {}\n" " for i = 1, 9 do\n" " game.vars.grid[i] = 0\n" " end\n" " game.vars.winner = 0\n" "end\n" ""; typedef struct { const char* name; const char* desc; const char* src; } PicoGame; static const PicoGame pico_games[] = { {"2048", "Merge tiles to reach 2048", game_2048_lua_src}, {"Air Hockey", "Fast-paced 2-player hockey", air_hockey_lua_src}, {"Asteroids", "Destroy asteroids, avoid collisions", asteroids_lua_src}, {"Bouncing Ball", "Physics demo with state management", ball_lua_src}, {"Breakout", "Break bricks with bouncing ball and paddle", breakout_lua_src}, {"Touch Counter", "Simple tap counter demo", counter_lua_src}, {"Flappy Bird", "Tap to flap, avoid pipes", flappy_bird_lua_src}, {"Lunar Lander", "Land safely with limited fuel", lunar_lander_lua_src}, {"Memory Match", "Find matching pairs", memory_match_lua_src}, {"Pacman", "Simplified pacman with digital tile movement", pacman_lua_src}, {"Pong", "Classic two-player Pong game", pong_lua_src}, {"Simon Says", "Repeat the color sequence", simon_says_lua_src}, {"Snake Game", "Classic snake with state machine", snake_lua_src}, {"Solitaire", "Klondike-style solitaire", solitaire_lua_src}, {"Tetris", "Stack falling blocks, clear lines", tetris_lua_src}, {"Tic-Tac-Toe", "Play vs AI opponent", tic_tac_toe_lua_src}, }; static const int pico_games_count = sizeof(pico_games)/sizeof(pico_games[0]);