-- NAME: 2048 -- DESC: Merge tiles to reach 2048 -- Game states local STATE_MENU = 0 local STATE_PLAYING = 1 local STATE_GAME_OVER = 2 local STATE_WIN = 3 -- Game constants local GRID_SIZE = 4 -- Calculate tile size based on screen size local function get_tile_size() -- Use available space with padding local padding = math.floor(game.width() / 8) local available = game.width() - (padding * 2) local tile_size = math.floor(available / GRID_SIZE) return tile_size end local function get_grid_start_x() local tile_size = get_tile_size() local grid_width = tile_size * GRID_SIZE return math.floor((game.width() - grid_width) / 2) end local function get_grid_start_y() return 30 end function init() game.vars.state = STATE_MENU game.vars.score = 0 -- Grid (4x4, 0 = empty) game.vars.grid = {} for y = 1, GRID_SIZE do game.vars.grid[y] = {} for x = 1, GRID_SIZE do game.vars.grid[y][x] = 0 end end game.vars.moved = false game.vars.won = false -- Enable continuous updates game.set_frame_updates(true) print("2048 initialized") end function update(event) local state = game.vars.state if state == STATE_MENU then if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then reset_game() game.vars.state = STATE_PLAYING return true end elseif state == STATE_PLAYING then if event.type == INPUT.TOUCH_DOWN then -- Determine swipe direction local direction = get_swipe_direction(event.x, event.y) if direction then game.vars.moved = false move_tiles(direction) if game.vars.moved then spawn_tile() -- Check win/lose if has_tile(2048) then if not game.vars.won then game.vars.state = STATE_WIN game.vars.won = true end end if not can_move() then game.vars.state = STATE_GAME_OVER end return true end end end elseif state == STATE_WIN then if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then -- Can continue playing or go to menu if event.y < game.height() / 2 then game.vars.state = STATE_PLAYING else game.vars.state = STATE_MENU end return true end elseif state == STATE_GAME_OVER then if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then game.vars.state = STATE_MENU return true end end return false end function draw() renderer.clear(false) local state = game.vars.state local tile_size = get_tile_size() local start_x = get_grid_start_x() local start_y = get_grid_start_y() if state == STATE_MENU then renderer.text(game.width() / 2 - 15, game.height() / 2 - 30, "2048", true) renderer.text(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true) elseif state == STATE_PLAYING or state == STATE_WIN or state == STATE_GAME_OVER then -- Draw grid for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do local tile_x = start_x + (x - 1) * tile_size local tile_y = start_y + (y - 1) * tile_size local value = game.vars.grid[y][x] if value == 0 then -- Empty tile renderer.rect(tile_x, tile_y, tile_size, tile_size, true, false) else -- Filled tile renderer.rect(tile_x, tile_y, tile_size, tile_size, true, true) -- Draw value (simplified) local text = tostring(value) if string.len(text) <= 2 then renderer.text(tile_x + 2, tile_y + 2, text, false) else renderer.text(tile_x + 1, tile_y + 2, text, false) end end end end -- Draw score renderer.text(10, 10, "Score: " .. tostring(game.vars.score), true) if state == STATE_WIN then renderer.text(game.width() / 2 - 30, game.height() / 2 - 20, "YOU WIN!", true) renderer.text(game.width() / 2 - 60, game.height() / 2, "Tap up: Continue", true) renderer.text(game.width() / 2 - 50, game.height() / 2 + 15, "Tap down: Menu", true) end if state == STATE_GAME_OVER then renderer.text(game.width() / 2 - 40, game.height() / 2, "GAME OVER", true) renderer.text(game.width() / 2 - 30, game.height() / 2 + 15, "Score: " .. tostring(game.vars.score), true) renderer.text(game.width() / 2 - 60, game.height() / 2 + 30, "Tap to Menu", true) end end end function get_swipe_direction(x, y) -- Simple tap-based direction (could be enhanced with swipe tracking) local mid_x = game.width() / 2 local mid_y = game.height() / 2 local dx = x - mid_x local dy = y - mid_y if math.abs(dx) > math.abs(dy) then if dx > 0 then return "right" end return "left" else if dy > 0 then return "down" end return "up" end end function move_tiles(direction) local old_grid = {} for y = 1, GRID_SIZE do old_grid[y] = {} for x = 1, GRID_SIZE do old_grid[y][x] = game.vars.grid[y][x] end end if direction == "left" then move_left() elseif direction == "right" then move_right() elseif direction == "up" then move_up() elseif direction == "down" then move_down() end -- Check if grid changed for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do if old_grid[y][x] ~= game.vars.grid[y][x] then game.vars.moved = true return end end end end function move_left() for y = 1, GRID_SIZE do -- Compact local row = {} for x = 1, GRID_SIZE do if game.vars.grid[y][x] ~= 0 then table.insert(row, game.vars.grid[y][x]) end end -- Merge local i = 1 while i < #row do if row[i] == row[i + 1] then row[i] = row[i] * 2 game.vars.score = game.vars.score + row[i] table.remove(row, i + 1) end i = i + 1 end -- Fill back for x = 1, GRID_SIZE do if x <= #row then game.vars.grid[y][x] = row[x] else game.vars.grid[y][x] = 0 end end end end function move_right() for y = 1, GRID_SIZE do local row = {} for x = GRID_SIZE, 1, -1 do if game.vars.grid[y][x] ~= 0 then table.insert(row, game.vars.grid[y][x]) end end local i = 1 while i < #row do if row[i] == row[i + 1] then row[i] = row[i] * 2 game.vars.score = game.vars.score + row[i] table.remove(row, i + 1) end i = i + 1 end for x = GRID_SIZE, 1, -1 do if GRID_SIZE - x + 1 <= #row then game.vars.grid[y][x] = row[GRID_SIZE - x + 1] else game.vars.grid[y][x] = 0 end end end end function move_up() for x = 1, GRID_SIZE do local col = {} for y = 1, GRID_SIZE do if game.vars.grid[y][x] ~= 0 then table.insert(col, game.vars.grid[y][x]) end end local i = 1 while i < #col do if col[i] == col[i + 1] then col[i] = col[i] * 2 game.vars.score = game.vars.score + col[i] table.remove(col, i + 1) end i = i + 1 end for y = 1, GRID_SIZE do if y <= #col then game.vars.grid[y][x] = col[y] else game.vars.grid[y][x] = 0 end end end end function move_down() for x = 1, GRID_SIZE do local col = {} for y = GRID_SIZE, 1, -1 do if game.vars.grid[y][x] ~= 0 then table.insert(col, game.vars.grid[y][x]) end end local i = 1 while i < #col do if col[i] == col[i + 1] then col[i] = col[i] * 2 game.vars.score = game.vars.score + col[i] table.remove(col, i + 1) end i = i + 1 end for y = GRID_SIZE, 1, -1 do if GRID_SIZE - y + 1 <= #col then game.vars.grid[y][x] = col[GRID_SIZE - y + 1] else game.vars.grid[y][x] = 0 end end end end function spawn_tile() local empty = {} for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do if game.vars.grid[y][x] == 0 then table.insert(empty, {x = x, y = y}) end end end if #empty > 0 then local pos = empty[math.random(1, #empty)] game.vars.grid[pos.y][pos.x] = math.random() > 0.9 and 4 or 2 end end function has_tile(value) for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do if game.vars.grid[y][x] == value then return true end end end return false end function can_move() -- Check if any empty tiles for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do if game.vars.grid[y][x] == 0 then return true end end end -- Check if any merges possible for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do local val = game.vars.grid[y][x] if x < GRID_SIZE and game.vars.grid[y][x + 1] == val then return true end if y < GRID_SIZE and game.vars.grid[y + 1][x] == val then return true end end end return false end function reset_game() game.vars.score = 0 game.vars.won = false for y = 1, GRID_SIZE do for x = 1, GRID_SIZE do game.vars.grid[y][x] = 0 end end spawn_tile() spawn_tile() end