VibeGame-8B / code /scripts /create_teacher_batch_b.py
khursheed's picture
Release pipeline source, tests, notebook, and licenses
ae36cfb verified
Raw History Blame Contribute Delete
79.2 kB
#!/usr/bin/env python3
"""Materialize 32 original in-session Codex-authored games; no model/API call.
This is authorship tooling, not a claim of executed Godot validation. Admission
requires the separate Linux engine import and full 60-second runtime check.
"""
import hashlib
import json
from pathlib import Path
import sys
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from vibegame.project import parse_project, project_sha256
PROJECT = '''config_version=5
[application]
config/name="%s"
run/main_scene="res://main.tscn"
[display]
window/size/viewport_width=960
window/size/viewport_height=640
[rendering]
renderer/rendering_method="gl_compatibility"
environment/defaults/default_clear_color=Color(0.035, 0.047, 0.09, 1)
'''
SCENE = '''[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://main.gd" id="1"]
[node name="Game" type="Node2D"]
script = ExtResource("1")
'''
HELPERS = '''
func text_at(s: String, p: Vector2, size: int = 22, color: Color = Color.WHITE) -> void:
\tdraw_string(ThemeDB.fallback_font, p, s, HORIZONTAL_ALIGNMENT_LEFT, -1, size, color)
func backdrop(title: String, controls: String) -> void:
\tdraw_rect(Rect2(0, 0, 960, 88), Color("121d35"))
\ttext_at(title, Vector2(24, 35), 27, Color("5ef2d0"))
\ttext_at(controls, Vector2(24, 68), 17, Color("c1cfe8"))
'''
GAMES = {}
GAMES[21] = ("Four Floor Courier", '''extends Node2D
var people: Array[Dictionary] = []
var cabin: float = 520.0
var remaining: float = 100.0
var delivered: int = 0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
people.clear()
for i in range(8):
people.append({"floor": i % 4, "dest": (i % 4 + 1 + i / 4) % 4, "state": 0})
cabin = 520.0
remaining = 100.0
delivered = 0
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
remaining -= dt
cabin = clampf(cabin + Input.get_axis("ui_up", "ui_down") * 170.0 * dt, 160, 520)
for floor in range(4):
if absf(cabin - (520.0 - floor * 120.0)) < 9.0:
for p in people:
if p["state"] == 1 and p["dest"] == floor:
p["state"] = 2
delivered += 1
var onboard: int = 0
for p in people:
if p["state"] == 1:
onboard += 1
for p in people:
if p["state"] == 0 and p["floor"] == floor and onboard < 2:
p["state"] = 1
onboard += 1
if delivered == 8:
outcome = "All eight passengers delivered! R: new shift"
elif remaining <= 0:
outcome = "Shift ended before all deliveries. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("FOUR FLOOR COURIER", "Up / Down: elevator | Automatic pickup and drop-off | Capacity 2 | R: restart")
for floor in range(4):
var y: float = 520.0 - floor * 120.0
draw_line(Vector2(90, y + 22), Vector2(750, y + 22), Color("46617d"), 3)
text_at("FLOOR %d" % (floor + 1), Vector2(760, y), 20)
draw_rect(Rect2(447, 115, 86, 452), Color("30455f"), false, 3)
draw_rect(Rect2(452, cabin - 44, 76, 66), Color("5ef2d0"), false, 4)
var seat: int = 0
for i in range(people.size()):
var p: Dictionary = people[i]
if p["state"] == 2:
continue
var pos: Vector2 = Vector2(180 + (i / 4) * 75, 520 - int(p["floor"]) * 120)
if p["state"] == 1:
pos = Vector2(468 + seat * 32, cabin)
seat += 1
draw_circle(pos, 12, Color("ffcd6b"))
text_at(str(int(p["dest"]) + 1), pos + Vector2(-6, -20), 20)
text_at("Delivered %d / 8 Time %d" % [delivered, ceili(remaining)], Vector2(28, 606))
if outcome != "":
text_at(outcome, Vector2(170, 110), 23)
''')
GAMES[22] = ("Counterweight", '''extends Node2D
var balls: Array[float] = [-100.0, 0.0, 100.0]
var speeds: Array[float] = [10.0, -14.0, 6.0]
var weight: float = 0.0
var angle: float = 0.0
var spin: float = 0.0
var timer: float = 30.0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
balls = [-100.0, 0.0, 100.0]
speeds = [10.0, -14.0, 6.0]
weight = 0.0
angle = 0.0
spin = 0.0
timer = 30.0
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
timer -= dt
weight = clampf(weight + Input.get_axis("ui_left", "ui_right") * 160.0 * dt, -195, 195)
var torque: float = (balls[0] + balls[1] + balls[2] + weight * 3.0) * 0.0007
spin += (torque - angle * 0.5 - spin * 1.5) * dt
angle = clampf(angle + spin * dt, -0.6, 0.6)
for i in range(3):
speeds[i] += (sin(angle) * 220.0 - speeds[i] * 0.08) * dt
balls[i] += speeds[i] * dt
if absf(balls[i]) > 220:
outcome = "A ball fell! Move the counterweight earlier. R: retry"
if timer <= 0 and outcome == "":
outcome = "Balanced for thirty seconds! R: play again"
queue_redraw()
func point(x: float, y: float = 0.0) -> Vector2:
return Vector2(480, 350) + Vector2(x, y).rotated(angle)
func _draw() -> void:
backdrop("COUNTERWEIGHT", "Left / Right: move the gold weight | Keep all three balls aboard for 30 seconds | R: restart")
draw_colored_polygon(PackedVector2Array([Vector2(450, 460), Vector2(510, 460), Vector2(480, 350)]), Color("46617d"))
draw_line(point(-230), point(230), Color("c1cfe8"), 12)
for i in range(3):
draw_circle(point(balls[i], -20), 14, Color.from_hsv(i * 0.2 + 0.45, 0.7, 1.0))
draw_circle(point(weight, 28), 18, Color("ffcd6b"))
text_at("Time left %.1f Plank tilt %.1f degrees" % [maxf(timer, 0), rad_to_deg(angle)], Vector2(180, 530))
if outcome != "":
text_at(outcome, Vector2(130, 580), 23)
''')
GAMES[23] = ("Two Pan Kitchen", '''extends Node2D
var heat: Array[float] = [0.0, 0.0]
var cooking: Array[bool] = [false, false]
var plates: int = 0
var mistakes: int = 0
var time_left: float = 60.0
var message: String = "Click a cold pan to begin. Click again to serve."
var outcome: String = ""
func pan_rect(i: int) -> Rect2:
return Rect2(190 + i * 340, 170, 220, 230)
func reset() -> void:
heat = [0.0, 0.0]
cooking = [false, false]
plates = 0
mistakes = 0
time_left = 60.0
outcome = ""
message = "Click a cold pan to begin. Click again to serve."
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and event.keycode == KEY_R:
reset()
if outcome != "":
return
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
for i in range(2):
if pan_rect(i).has_point(event.position):
if not cooking[i]:
cooking[i] = true
elif heat[i] >= 65 and heat[i] <= 85:
plates += 1
message = "Perfectly served!"
cooking[i] = false
heat[i] = 0
else:
mistakes += 1
message = "Too cold or too hot!"
cooking[i] = false
heat[i] = 0
func _process(dt: float) -> void:
if outcome == "":
time_left -= dt
for i in range(2):
if cooking[i]:
heat[i] += (20.0 + i * 7.0) * dt
if heat[i] >= 100:
mistakes += 1
cooking[i] = false
heat[i] = 0
message = "Burned!"
if plates >= 6:
outcome = "Six plates served. Kitchen complete!"
elif mistakes >= 3 or time_left <= 0:
outcome = "Kitchen closed. R: try another shift"
queue_redraw()
func _draw() -> void:
backdrop("TWO PAN KITCHEN", "Click pan: start / serve | Serve between 65 and 85 degrees | Six plates, fewer than 3 mistakes | R: restart")
for i in range(2):
var r: Rect2 = pan_rect(i)
draw_rect(r, Color("23344c"))
draw_circle(r.position + Vector2(110, 90), 67, Color("ff875b") if cooking[i] else Color("718199"))
text_at("PAN %d" % (i + 1), r.position + Vector2(65, 95))
draw_rect(Rect2(r.position + Vector2(10, 174), Vector2(200, 26)), Color("142037"))
draw_rect(Rect2(r.position + Vector2(140, 174), Vector2(40, 26)), Color("25855f"))
draw_line(r.position + Vector2(10 + heat[i] * 2, 170), r.position + Vector2(10 + heat[i] * 2, 205), Color.WHITE, 4)
text_at("%.0f degrees" % heat[i], r.position + Vector2(43, 225))
text_at("Plates %d / 6 Mistakes %d / 3 Time %d" % [plates, mistakes, ceili(maxf(0, time_left))], Vector2(220, 470))
text_at(message, Vector2(180, 520))
text_at(outcome, Vector2(170, 575), 25, Color("ffcd6b"))
''')
GAMES[24] = ("Echo Pads", '''extends Node2D
var sequence: Array[int] = [0, 2]
var showing: bool = true
var show_clock: float = -0.8
var response: int = 0
var flash: int = -1
var flash_time: float = 0.0
var outcome: String = ""
func reset() -> void:
sequence = [0, 2]
showing = true
show_clock = -0.8
response = 0
flash = -1
outcome = ""
func pad(i: int) -> Rect2:
return Rect2(200 + (i % 2) * 300, 160 + (i / 2) * 175, 260, 145)
func press(i: int) -> void:
if showing or outcome != "":
return
flash = i
flash_time = 0.25
if i != sequence[response]:
outcome = "Wrong pad. R: listen to a new round"
return
response += 1
if response == sequence.size():
if sequence.size() == 8:
outcome = "Eight-note sequence remembered! R: replay"
else:
sequence.append(randi_range(0, 3))
showing = true
show_clock = -1.0
response = 0
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_R:
reset()
for i in range(4):
if event.keycode == KEY_1 + i:
press(i)
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
for i in range(4):
if pad(i).has_point(event.position):
press(i)
func _process(dt: float) -> void:
if outcome == "" and showing:
show_clock += dt
var index: int = floori(show_clock / 0.8)
flash = -1
if index >= sequence.size():
showing = false
elif index >= 0 and fmod(show_clock, 0.8) < 0.5:
flash = sequence[index]
elif not showing:
flash_time -= dt
if flash_time <= 0:
flash = -1
queue_redraw()
func _draw() -> void:
backdrop("ECHO PADS", "Watch the flashes, then repeat at any speed | Click pads or press 1 / 2 / 3 / 4 | R: restart")
for i in range(4):
draw_rect(pad(i), Color.from_hsv(i * 0.23, 0.7, 1.0 if flash == i else 0.35))
text_at(str(i + 1), pad(i).position + Vector2(116, 90), 46)
text_at("WATCH" if showing else "YOUR TURN - no timing requirement", Vector2(230, 125), 25)
text_at("Sequence length %d / 8 Entered %d" % [sequence.size(), response], Vector2(240, 555))
text_at(outcome, Vector2(180, 610), 23, Color("ffcd6b"))
''')
GAMES[25] = ("Crane Stack", '''extends Node2D
var stack: Array[Rect2] = []
var crane: float = 180.0
var direction: float = 1.0
var falling: bool = false
var package_pos: Vector2 = Vector2.ZERO
var velocity: float = 0.0
var outcome: String = ""
func reset() -> void:
stack.clear()
crane = 180
direction = 1
falling = false
outcome = ""
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_R:
reset()
if event.keycode == KEY_SPACE and not falling and outcome == "":
falling = true
package_pos = Vector2(crane - 58, 130)
velocity = 0
func _process(dt: float) -> void:
if outcome == "":
if not falling:
crane += direction * (190 + stack.size() * 23) * dt
if crane < 120 or crane > 840:
direction *= -1
crane = clampf(crane, 120, 840)
else:
velocity += 570 * dt
package_pos.y += velocity * dt
var target: float = 550 - stack.size() * 52
if package_pos.y + 52 >= target:
package_pos.y = target - 52
var overlap: float = 116
if not stack.is_empty():
overlap = minf(package_pos.x + 116, stack[-1].end.x) - maxf(package_pos.x, stack[-1].position.x)
if package_pos.x < 350 or package_pos.x + 116 > 610 or overlap < 78:
outcome = "Unstable placement! Stay inside the outline and overlap. R: retry"
else:
stack.append(Rect2(package_pos, Vector2(116, 52)))
if stack.size() == 6:
outcome = "Six stable packages! Tower complete. R: replay"
falling = false
queue_redraw()
func _draw() -> void:
backdrop("CRANE STACK", "Space: release package | Stay inside the tower and overlap the previous box | R: restart")
draw_rect(Rect2(350, 208, 260, 344), Color("5ef2d0"), false, 3)
draw_line(Vector2(80, 550), Vector2(880, 550), Color("c1cfe8"), 4)
draw_line(Vector2(100, 115), Vector2(860, 115), Color("46617d"), 5)
for i in range(stack.size()):
draw_rect(stack[i], Color.from_hsv(i * 0.1, 0.6, 0.95))
draw_rect(stack[i], Color.WHITE, false, 2)
if outcome == "":
var pos: Vector2 = package_pos if falling else Vector2(crane - 58, 130)
draw_rect(Rect2(pos, Vector2(116, 52)), Color("ffcd6b"))
if not falling:
draw_line(Vector2(crane, 115), Vector2(crane, 130), Color.WHITE, 3)
text_at("Stable placements %d / 6" % stack.size(), Vector2(310, 590))
text_at(outcome, Vector2(75, 625), 20)
''')
GAMES[26] = ("Trail Territory", '''extends Node2D
const W: int = 14
const H: int = 10
const STEP: int = 38
var owned: Dictionary = {}
var trail: Array[Vector2i] = []
var player: Vector2i = Vector2i(2, 5)
var enemy: Vector2i = Vector2i(11, 5)
var move_clock: float = 0.0
var enemy_clock: float = 0.0
var time_left: float = 90.0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
owned.clear()
trail.clear()
for y in range(H):
for x in range(3):
owned[Vector2i(x, y)] = true
player = Vector2i(2, 5)
enemy = Vector2i(11, 5)
move_clock = 0
enemy_clock = 0
time_left = 90
outcome = ""
func inside(p: Vector2i) -> bool:
return p.x >= 0 and p.y >= 0 and p.x < W and p.y < H
func reconnect() -> void:
for p in trail:
owned[p] = true
trail.clear()
var reached: Dictionary = {enemy: true}
var queue: Array[Vector2i] = [enemy]
var cursor: int = 0
while cursor < queue.size():
var cell: Vector2i = queue[cursor]
cursor += 1
for direction in [Vector2i.LEFT, Vector2i.RIGHT, Vector2i.UP, Vector2i.DOWN]:
var next: Vector2i = cell + direction
if inside(next) and not owned.has(next) and not reached.has(next):
reached[next] = true
queue.append(next)
for y in range(H):
for x in range(W):
var cell: Vector2i = Vector2i(x, y)
if not reached.has(cell):
owned[cell] = true
if owned.size() >= 92:
outcome = "Territory secured! R: another expedition"
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
time_left -= dt
move_clock -= dt
var direction: Vector2i = Vector2i.ZERO
if Input.is_action_pressed("ui_left"):
direction = Vector2i.LEFT
elif Input.is_action_pressed("ui_right"):
direction = Vector2i.RIGHT
elif Input.is_action_pressed("ui_up"):
direction = Vector2i.UP
elif Input.is_action_pressed("ui_down"):
direction = Vector2i.DOWN
if move_clock <= 0 and direction != Vector2i.ZERO:
move_clock = 0.13
var next: Vector2i = player + direction
if inside(next):
if trail.has(next):
outcome = "You crossed your own trail. R: retry"
else:
player = next
if owned.has(player):
if not trail.is_empty():
reconnect()
else:
trail.append(player)
enemy_clock -= dt
if enemy_clock <= 0:
enemy_clock = 0.22
var directions: Array[Vector2i] = [Vector2i.LEFT, Vector2i.RIGHT, Vector2i.UP, Vector2i.DOWN]
var next: Vector2i = enemy + directions[randi_range(0, 3)]
if inside(next) and not owned.has(next):
enemy = next
if trail.has(enemy):
outcome = "Enemy cut the active trail! R: retry"
elif time_left <= 0:
outcome = "Time expired. R: retry"
queue_redraw()
func center(p: Vector2i) -> Vector2:
return Vector2(215, 155) + Vector2(p) * STEP + Vector2.ONE * STEP * 0.5
func _draw() -> void:
backdrop("TRAIL TERRITORY", "Arrows: step | Leave blue safety, draw a loop, reconnect | Avoid the red enemy | R: restart")
for y in range(H):
for x in range(W):
var p: Vector2i = Vector2i(x, y)
var color: Color = Color("287a94") if owned.has(p) else Color("182439")
if trail.has(p):
color = Color("ffcd6b")
draw_rect(Rect2(center(p) - Vector2.ONE * 18, Vector2(36, 36)), color)
draw_circle(center(enemy), 13, Color("ff6176"))
draw_circle(center(player), 11, Color.WHITE)
text_at("Claim %d / 92 tiles Time %d" % [owned.size(), ceili(maxf(0, time_left))], Vector2(240, 575))
text_at(outcome, Vector2(220, 620), 23)
''')
GAMES[27] = ("Charge Duel", '''extends Node2D
var hp: int = 5
var foe_hp: int = 5
var energy: int = 2
var foe_energy: int = 2
var rounds: int = 0
var report: String = "Choose an action. The opponent commits without seeing your choice."
var outcome: String = ""
var names: Array[String] = ["ATTACK", "BLOCK", "CHARGE"]
func reset() -> void:
hp = 5
foe_hp = 5
energy = 2
foe_energy = 2
rounds = 0
report = "Attack costs 1 energy. Block defeats attack. Charge restores 1."
outcome = ""
func button(i: int) -> Rect2:
return Rect2(150 + i * 230, 420, 200, 72)
func choose(action: int) -> void:
if outcome != "":
return
if action == 0 and energy == 0:
report = "No energy: block or charge first."
return
var rival: int = 2 if foe_energy == 0 else randi_range(0, 2)
rounds += 1
if action == 0:
energy -= 1
if rival == 0:
foe_energy -= 1
if action == 2:
energy = mini(energy + 1, 4)
if rival == 2:
foe_energy = mini(foe_energy + 1, 4)
if action == 0:
if rival == 1:
hp -= 1
else:
foe_hp -= 1
if rival == 0:
if action == 1:
foe_hp -= 1
else:
hp -= 1
report = "You: %s Rival: %s Round %d" % [names[action], names[rival], rounds]
if hp <= 0 and foe_hp <= 0:
outcome = "Mutual knockout! R: rematch"
elif foe_hp <= 0:
outcome = "You win the duel! R: rematch"
elif hp <= 0:
outcome = "Rival wins. R: rematch"
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_R:
reset()
for i in range(3):
if event.keycode == KEY_1 + i:
choose(i)
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
for i in range(3):
if button(i).has_point(event.position):
choose(i)
queue_redraw()
func _draw() -> void:
backdrop("CHARGE DUEL", "Click an action or press 1 / 2 / 3 | Attack beats charge; block counters attack | R: restart")
draw_circle(Vector2(280, 235), 70, Color("5ef2d0"))
draw_circle(Vector2(690, 235), 70, Color("ff6176"))
text_at("YOU", Vector2(252, 244), 25, Color("121d35"))
text_at("RIVAL", Vector2(650, 244), 25)
text_at("HP %d Energy %d / 4" % [hp, energy], Vector2(180, 345))
text_at("HP %d Energy %d / 4" % [foe_hp, foe_energy], Vector2(570, 345))
for i in range(3):
draw_rect(button(i), Color("334966"))
text_at("%d: %s" % [i + 1, names[i]], button(i).position + Vector2(18, 45))
text_at(report, Vector2(70, 550), 20)
text_at(outcome, Vector2(280, 610), 26, Color("ffcd6b"))
''')
GAMES[28] = ("Binary Wires", '''extends Node2D
var lamps: int = 0
var target: int = 5
var masks: Array[int] = [3, 6, 7]
var moves: int = 0
var puzzles: int = 0
var outcome: String = ""
func reset() -> void:
lamps = 0
target = 5
moves = 0
puzzles = 0
outcome = ""
func toggle(i: int) -> void:
if outcome != "":
return
lamps = lamps ^ masks[i]
moves += 1
if lamps == target:
puzzles += 1
if puzzles == 4:
outcome = "Four circuits repaired! R: restart"
else:
lamps = target
target = (target + 3) % 8
moves = 0
elif moves >= 6:
outcome = "Six moves used. Circuit locked! R: retry"
func switch_rect(i: int) -> Rect2:
return Rect2(150 + 240 * i, 390, 180, 75)
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_R:
reset()
for i in range(3):
if event.keycode == KEY_1 + i:
toggle(i)
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
for i in range(3):
if switch_rect(i).has_point(event.position):
toggle(i)
queue_redraw()
func _draw() -> void:
backdrop("BINARY WIRES", "Click switches or press 1 / 2 / 3 | Match the target in at most six toggles | R: restart")
text_at("TARGET", Vector2(45, 174), 22)
text_at("LAMPS", Vector2(45, 278), 22)
for j in range(3):
var x: float = 240 + 240 * j
draw_circle(Vector2(x, 165), 24, Color("5ef2d0") if target & (1 << j) else Color("26394e"))
text_at(str((target >> j) & 1), Vector2(x - 6, 172), 21, Color.WHITE)
draw_circle(Vector2(x, 265), 35, Color("ffcd6b") if lamps & (1 << j) else Color("26394e"))
text_at(str((lamps >> j) & 1), Vector2(x - 7, 273), 24, Color.WHITE)
for i in range(3):
for j in range(3):
if masks[i] & (1 << j):
draw_line(Vector2(240 + 240 * i, 390), Vector2(240 + 240 * j, 305), Color.from_hsv(i * 0.24, 0.5, 0.6), 2)
draw_rect(switch_rect(i), Color("334966"))
text_at("SWITCH %d" % (i + 1), switch_rect(i).position + Vector2(23, 45))
text_at("Repairs %d / 4 Moves %d / 6 Wires show affected lamps" % [puzzles, moves], Vector2(140, 535))
text_at(outcome, Vector2(250, 600), 25)
''')
GAMES[29] = ("Water Gates", '''extends Node2D
var opened: Array[bool] = [false, false]
var levels: Array[int] = [0, 0]
var drops: Array[Dictionary] = []
var spawn_clock: float = 0.0
var time_left: float = 65.0
var outcome: String = ""
const TARGET: int = 20
func reset() -> void:
opened = [false, false]
levels = [0, 0]
drops.clear()
spawn_clock = 0
time_left = 65
outcome = ""
func gate(i: int) -> Rect2:
return Rect2(270 + i * 320, 210, 100, 55)
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and event.keycode == KEY_R:
reset()
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT and outcome == "":
for i in range(2):
if gate(i).has_point(event.position):
opened[i] = not opened[i]
func _process(dt: float) -> void:
if outcome == "":
time_left -= dt
spawn_clock -= dt
if spawn_clock <= 0:
spawn_clock = 0.25
for i in range(2):
if opened[i]:
drops.append({"p": Vector2(320 + i * 320, 265), "v": 0.0, "tank": i})
for k in range(drops.size() - 1, -1, -1):
var d: Dictionary = drops[k]
d["v"] += 440.0 * dt
d["p"] += Vector2(0, float(d["v"]) * dt)
var i: int = d["tank"]
if d["p"].y >= 555 - levels[i] * 8:
levels[i] += 1
drops.remove_at(k)
if levels[i] > TARGET:
outcome = "A tank overflowed its marked level! R: retry"
if levels[0] == TARGET and levels[1] == TARGET and drops.is_empty() and not opened[0] and not opened[1]:
outcome = "Both tanks precisely filled! R: another run"
elif time_left <= 0 and outcome == "":
outcome = "Water service timed out. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("WATER GATES", "Click gates: open / close | Fill BOTH tanks to 20 drops | Close early: falling drops still count | R: restart")
draw_rect(Rect2(250, 112, 460, 65), Color("2588b5"))
text_at("WATER SOURCE", Vector2(380, 155))
for i in range(2):
var x: float = 320 + i * 320
draw_line(Vector2(x, 177), Vector2(x, 210), Color("6fbde8"), 12)
draw_rect(gate(i), Color("287b65") if opened[i] else Color("9e5263"))
text_at("OPEN" if opened[i] else "CLOSED", gate(i).position + Vector2(7, 36), 20)
draw_rect(Rect2(x - 100, 330, 200, 225), Color("182f49"), false, 4)
draw_rect(Rect2(x - 95, 555 - levels[i] * 8, 190, levels[i] * 8), Color("329fd2"))
draw_line(Vector2(x - 105, 395), Vector2(x + 105, 395), Color("ffcd6b"), 3)
text_at("%d / 20" % levels[i], Vector2(x - 35, 590))
for d in drops:
draw_circle(d["p"], 7, Color("79d7ff"))
text_at("Time %d" % ceili(maxf(0, time_left)), Vector2(25, 120), 20)
text_at(outcome, Vector2(190, 626), 23)
''')
GAMES[30] = ("Shuttle Platforms", '''extends Node2D
var player: Vector2 = Vector2(60, 465)
var vy: float = 0.0
var platforms: Array[Rect2] = []
var grounded: int = -2
var clock: float = 0.0
var carrying: bool = true
var lives: int = 3
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
player = Vector2(60, 465)
vy = 0
clock = 0
carrying = true
lives = 3
grounded = -2
outcome = ""
platforms = [Rect2(230, 430, 100, 16), Rect2(425, 360, 100, 16), Rect2(620, 430, 100, 16)]
func _physics_process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
clock += dt
for i in range(3):
var previous_x: float = platforms[i].position.x
platforms[i].position.x = 230 + i * 195 + sin(clock * 1.2 + i * 1.8) * 38
if grounded == i:
player.x += platforms[i].position.x - previous_x
if Input.is_action_just_pressed("ui_accept") and grounded != -1:
vy = -445
grounded = -1
player.x = clampf(player.x + Input.get_axis("ui_left", "ui_right") * 235 * dt, 0, 935)
var old_bottom: float = player.y + 35
vy += 900 * dt
player.y += vy * dt
grounded = -1
var surfaces: Array[Rect2] = platforms.duplicate()
surfaces.append(Rect2(0, 500, 155, 30))
surfaces.append(Rect2(815, 500, 145, 30))
if vy >= 0:
for i in range(surfaces.size()):
var r: Rect2 = surfaces[i]
if old_bottom <= r.position.y + 3 and player.y + 35 >= r.position.y and player.x + 25 > r.position.x and player.x < r.end.x:
player.y = r.position.y - 35
vy = 0
grounded = i if i < 3 else -2
if player.y > 650:
lives -= 1
player = Vector2(60 if carrying else 875, 465)
vy = 0
grounded = -2
if lives == 0:
outcome = "Three falls. R: try the delivery again"
if carrying and player.x > 870 and grounded == -2:
carrying = false
if not carrying and player.x < 85 and grounded == -2:
outcome = "Delivered and returned safely! R: new route"
queue_redraw()
func _draw() -> void:
backdrop("SHUTTLE PLATFORMS", "Left / Right: move | Space: jump | Deliver the box at right, then return left | R: restart")
draw_rect(Rect2(0, 500, 155, 140), Color("334966"))
draw_rect(Rect2(815, 500, 145, 140), Color("334966"))
for p in platforms:
draw_rect(p, Color("5ef2d0"))
draw_rect(Rect2(player, Vector2(25, 35)), Color("79bbff"))
if carrying:
draw_rect(Rect2(player + Vector2(3, -20), Vector2(20, 20)), Color("ffcd6b"))
else:
draw_rect(Rect2(898, 472, 28, 28), Color("ffcd6b"))
text_at("HOME", Vector2(35, 555), 20)
text_at("DEPOT", Vector2(845, 555), 20)
text_at("Lives %d | %s" % [lives, "Carry box to depot" if carrying else "Box delivered - return HOME"], Vector2(230, 125))
text_at(outcome, Vector2(260, 605), 24)
''')
GAMES[31] = ("Driveway Plow", '''extends Node2D
const W: int = 10
const H: int = 7
const CELL: int = 56
var snow: Dictionary = {}
var piles: Dictionary = {}
var player: Vector2i = Vector2i(4, 6)
var moves: int = 0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
snow.clear()
piles.clear()
for y in range(1, 6):
piles[Vector2i(0, y)] = 0
piles[Vector2i(9, y)] = 0
for x in [2, 3, 6, 7]:
snow[Vector2i(x, y)] = true
player = Vector2i(4, 6)
moves = 0
outcome = ""
func inside(p: Vector2i) -> bool:
return p.x >= 0 and p.y >= 0 and p.x < W and p.y < H
func step(direction: Vector2i) -> void:
if outcome != "":
return
var next: Vector2i = player + direction
if not inside(next) or piles.has(next):
return
if snow.has(next):
var chain: Array[Vector2i] = []
var end: Vector2i = next
while snow.has(end):
chain.append(end)
end += direction
if not inside(end):
return
if (end.y == 0 or end.y == 6) and (end.x == 4 or end.x == 5):
outcome = "Snow blocked the garage exit corridor. R: retry"
return
for i in range(chain.size() - 1, -1, -1):
var dest: Vector2i = chain[i] + direction
snow.erase(chain[i])
if piles.has(dest):
piles[dest] += 1
else:
snow[dest] = true
player = next
moves += 1
if snow.is_empty():
outcome = "Every driveway tile cleared; exit remains open! R: restart"
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_R:
reset()
elif event.keycode == KEY_LEFT:
step(Vector2i.LEFT)
elif event.keycode == KEY_RIGHT:
step(Vector2i.RIGHT)
elif event.keycode == KEY_UP:
step(Vector2i.UP)
elif event.keycode == KEY_DOWN:
step(Vector2i.DOWN)
queue_redraw()
func center(p: Vector2i) -> Vector2:
return Vector2(200, 155) + Vector2(p) * CELL + Vector2.ONE * 28
func _draw() -> void:
backdrop("DRIVEWAY PLOW", "Tap arrows: move and push snow | Push into green side piles | Keep the yellow exit open | R: restart")
for y in range(H):
for x in range(W):
var p: Vector2i = Vector2i(x, y)
var color: Color = Color("28394e")
if piles.has(p):
color = Color("26785e")
elif (y == 0 or y == 6) and (x == 4 or x == 5):
color = Color("827035")
draw_rect(Rect2(center(p) - Vector2.ONE * 27, Vector2(54, 54)), color)
if snow.has(p):
draw_circle(center(p), 21, Color("d5ebff"))
if piles.has(p):
text_at(str(piles[p]), center(p) + Vector2(-6, 7), 19)
draw_rect(Rect2(center(player) - Vector2(17, 17), Vector2(34, 34)), Color("ff955b"))
text_at("Snow tiles left %d / 20 Moves %d" % [snow.size(), moves], Vector2(270, 585))
text_at(outcome, Vector2(145, 625), 21)
''')
GAMES[32] = ("Shepherd Gate", '''extends Node2D
var sheep: Array[Vector2] = []
var secured: Array[bool] = []
var shepherd: Vector2 = Vector2(160, 340)
var time_left: float = 90.0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
sheep = [Vector2(240, 235), Vector2(360, 295), Vector2(270, 415), Vector2(410, 440), Vector2(460, 215)]
secured = [false, false, false, false, false]
shepherd = Vector2(160, 340)
time_left = 90
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
time_left -= dt
shepherd = get_global_mouse_position()
shepherd.x = clampf(shepherd.x, 35, 660)
shepherd.y = clampf(shepherd.y, 125, 575)
# The marked entrance is reserved for sheep: shepherd stays outside it.
if shepherd.x > 595 and shepherd.y > 265 and shepherd.y < 415:
shepherd.x = 595
for i in range(sheep.size()):
if secured[i]:
continue
var velocity: Vector2 = Vector2.ZERO
var away: Vector2 = sheep[i] - shepherd
if away.length() < 145:
velocity += away.normalized() * (145 - away.length()) * 1.1
for j in range(sheep.size()):
if i != j and not secured[j]:
var separation: Vector2 = sheep[i] - sheep[j]
if separation.length() < 38:
velocity += separation.normalized() * 35
var next: Vector2 = sheep[i] + velocity.limit_length(110) * dt
next.y = clampf(next.y, 140, 555)
next.x = maxf(next.x, 50)
if next.x > 680 and (next.y < 285 or next.y > 395):
next.x = 680
if next.x >= 690 and next.y >= 285 and next.y <= 395:
secured[i] = true
next = Vector2(750 + (i % 2) * 85, 230 + (i / 2) * 80)
sheep[i] = next
var count: int = 0
for done in secured:
if done:
count += 1
if count == sheep.size():
outcome = "Every sheep penned; gate corridor clear! R: replay"
elif time_left <= 0:
outcome = "Time ran out. Approach from behind each sheep. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("SHEPHERD GATE", "Mouse: shepherd repels nearby sheep | Herd them through the right-side gate | Keep corridor clear | R: restart")
draw_rect(Rect2(30, 120, 650, 465), Color("1a3b37"))
draw_rect(Rect2(700, 160, 220, 380), Color("285746"))
draw_rect(Rect2(595, 285, 105, 110), Color("746532"))
draw_line(Vector2(690, 120), Vector2(690, 278), Color("c1cfe8"), 8)
draw_line(Vector2(690, 402), Vector2(690, 585), Color("c1cfe8"), 8)
text_at("PEN", Vector2(775, 145))
var count: int = 0
for i in range(sheep.size()):
draw_circle(sheep[i], 16, Color.WHITE)
draw_circle(sheep[i] + Vector2(10, 0), 7, Color("68798b"))
if secured[i]:
count += 1
draw_circle(shepherd, 15, Color("ff9568"))
draw_arc(shepherd, 145, 0, TAU, 48, Color(1, 0.7, 0.4, 0.18), 1)
text_at("Penned %d / 5 Time %d" % [count, ceili(maxf(time_left, 0))], Vector2(220, 610))
text_at(outcome, Vector2(120, 108), 22)
''')
def main():
# Access only the explicitly assigned training prompt IDs; no blind file read.
wanted = {f"vg8b-teacher-v1-{i:03d}" for i in list(range(21, 33)) + list(range(65, 85))}
prompts = {}
with (ROOT / "data/teacher_prompts.jsonl").open() as handle:
for line in handle:
row = json.loads(line)
if row["id"] in wanted:
prompts[row["id"]] = row["instruction"]
if set(prompts) != wanted:
raise RuntimeError("Missing assigned training prompts")
rows, provenance = [], []
for number, (title, source) in sorted(GAMES.items()):
identity = f"vg8b-teacher-v1-{number:03d}"
files = {"project.godot": PROJECT % title, "main.tscn": SCENE, "main.gd": source + HELPERS}
output = json.dumps({"files": files}, ensure_ascii=False, separators=(",", ":"))
parse_project(output)
rows.append({"instruction": prompts[identity], "output": output})
provenance.append({"prompt_id": identity, "title": title, "project_sha256": project_sha256(files),
"output_sha256": hashlib.sha256(output.encode()).hexdigest(),
"gdscript_characters": len(files["main.gd"]), "static_contract_pass": True})
output_path = ROOT / "data/codex_teacher_batch_b.jsonl"
temporary = output_path.with_suffix(".tmp")
temporary.write_text("".join(json.dumps(row, ensure_ascii=False) + "\n" for row in rows))
temporary.replace(output_path)
report = {"authorship": "Original in-session Codex teacher authorship; not generated by the local 14B sampler.",
"source": "Independently implemented game mechanics responding to assigned training prompts 021–032 and 065–084.",
"license": "Apache-2.0", "assets": "Procedural Godot drawing and bundled default font only; no third-party game assets.",
"shared_boilerplate": "Canonical Godot project/scene and text drawing helpers follow the repository's original seeds.",
"blind_prompts_read": False, "engine_validation": "NOT RUN. Pending Linux import and full 60-second check; these are candidates, not admitted training data.",
"candidates_sha256": hashlib.sha256(output_path.read_bytes()).hexdigest(), "count": len(rows), "games": provenance}
(ROOT / "data/codex_teacher_batch_b_provenance.json").write_text(json.dumps(report, indent=2) + "\n")
print(json.dumps({"candidates": len(rows), "static_contract": "passed", "max_gdscript_characters": max(x["gdscript_characters"] for x in provenance), "engine_validation": "pending"}))
GAMES[65] = ("Landing Lines", '''extends Node2D
var planes: Array[Dictionary] = []
var zones: Array[Vector2] = [Vector2(770, 210), Vector2(770, 480)]
var selected: int = -1
var created: int = 0
var landed: int = 0
var spawn: float = 0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
planes.clear()
selected = -1
created = 0
landed = 0
spawn = 0
outcome = ""
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
reset()
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
if e.pressed:
selected = -1
for i in range(planes.size()):
if planes[i]["p"].distance_to(e.position) < 25:
selected = i
planes[i]["path"] = []
else:
selected = -1
if e is InputEventMouseMotion and selected >= 0 and selected < planes.size():
var path: Array = planes[selected]["path"]
if path.is_empty() or path[-1].distance_to(e.position) > 18:
path.append(e.position)
func _process(dt: float) -> void:
if outcome == "":
spawn -= dt
if spawn <= 0 and created < 8:
planes.append({"p": Vector2(50, 170 + (created % 2) * 320), "zone": created % 2, "path": []})
created += 1
spawn = 5.5
for i in range(planes.size() - 1, -1, -1):
var p: Dictionary = planes[i]
var path: Array = p["path"]
if not path.is_empty():
p["p"] = p["p"].move_toward(path[0], 85 * dt)
if p["p"].distance_to(path[0]) < 2:
path.pop_front()
else:
p["p"] += Vector2(23 * dt, 0)
if p["p"].distance_to(zones[p["zone"]]) < 24:
planes.remove_at(i)
selected = -1
landed += 1
elif p["p"].x > 950 or p["p"].y < 90 or p["p"].y > 630:
outcome = "Plane left the airspace! R: retry"
for i in range(planes.size()):
for j in range(i):
if planes[i]["p"].distance_to(planes[j]["p"]) < 27:
outcome = "Loss of separation! R: retry"
if landed == 8:
outcome = "Eight safe landings! R: another shift"
queue_redraw()
func _draw() -> void:
backdrop("LANDING LINES", "Drag from a plane to draw its route | Match landing-zone color | Keep planes separated | R: restart")
for i in range(2):
draw_circle(zones[i], 38, Color("286c90") if i == 0 else Color("806631"))
text_at(str(i + 1), zones[i] + Vector2(-8, 9), 28)
for p in planes:
var previous: Vector2 = p["p"]
for point in p["path"]:
draw_line(previous, point, Color("526d88"), 2)
previous = point
draw_circle(p["p"], 12, Color("79d7ff") if p["zone"] == 0 else Color("ffcd6b"))
text_at("Landed %d / 8" % landed, Vector2(35, 610))
text_at(outcome, Vector2(330, 610), 24)
''')
GAMES[66] = ("Six Plot Farm", '''extends Node2D
var plants: Array[Dictionary] = []
var water: int = 12
var harvest: int = 0
var wilted: int = 0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
plants.clear()
for i in range(6):
plants.append({"stage": 0, "moisture": 0.0, "growth": 0.0})
water = 12
harvest = 0
wilted = 0
outcome = ""
func plot(i: int) -> Rect2:
return Rect2(170 + (i % 3) * 215, 175 + (i / 3) * 185, 185, 155)
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
reset()
if outcome == "" and e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT:
for i in range(6):
if plot(i).has_point(e.position):
var p: Dictionary = plants[i]
if p["stage"] == 0:
p["stage"] = 1
p["moisture"] = 70.0
elif p["stage"] == 2:
p["stage"] = 3
harvest += 1
elif p["stage"] == 1 and water > 0:
p["moisture"] = minf(100, p["moisture"] + 55)
water -= 1
func _process(dt: float) -> void:
if outcome == "":
for p in plants:
if p["stage"] == 1:
p["moisture"] -= 8 * dt
p["growth"] += 6 * dt
if p["moisture"] <= 0:
p["stage"] = 4
wilted += 1
elif p["growth"] >= 100:
p["stage"] = 2
if harvest == 6:
outcome = "All six crops harvested! R: replant"
elif wilted > 0:
outcome = "A plant wilted. R: restart the farm"
queue_redraw()
func _draw() -> void:
backdrop("SIX PLOT FARM", "Click empty plot: plant | Click growing crop: spend water | Click gold crop: harvest | R: restart")
for i in range(6):
var p: Dictionary = plants[i]
var r: Rect2 = plot(i)
draw_rect(r, Color("684b38"))
if p["stage"] == 1 or p["stage"] == 2:
draw_circle(r.get_center() - Vector2(0, 14), 15 + p["growth"] * 0.2, Color("ffcd6b") if p["stage"] == 2 else Color("5ed27b"))
draw_rect(Rect2(r.position + Vector2(10, 115), Vector2(p["moisture"] * 1.65, 12)), Color("79d7ff"))
text_at("Growth %d%%" % int(p["growth"]), r.position + Vector2(22, 149), 17)
else:
text_at(["PLANT", "", "", "HARVESTED", "WILTED"][p["stage"]], r.position + Vector2(23, 80), 20)
text_at("Water %d / 12 Harvest %d / 6" % [water, harvest], Vector2(300, 570))
text_at(outcome, Vector2(250, 620), 24)
''')
GAMES[67] = ("Three Barrier Bankshot", '''extends Node2D
var barriers: Array[Rect2] = []
var ball: Vector2 = Vector2(125, 490)
var velocity: Vector2 = Vector2(210, -150)
var running: bool = false
var bounces: int = 0
var horizontal: bool = true
var outcome: String = ""
var timer: float = 0
func reset() -> void:
barriers.clear()
ball = Vector2(125, 490)
velocity = Vector2(210, -150)
running = false
bounces = 0
timer = 0
outcome = ""
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_SPACE and barriers.size() == 3 and outcome == "":
running = true
if e is InputEventMouseButton and e.pressed and not running:
if e.button_index == MOUSE_BUTTON_RIGHT:
horizontal = not horizontal
elif e.button_index == MOUSE_BUTTON_LEFT and barriers.size() < 3 and e.position.y > 160:
var size: Vector2 = Vector2(120, 18) if horizontal else Vector2(18, 120)
var rect: Rect2 = Rect2(e.position - size / 2, size)
if not rect.grow(25).has_point(ball) and not rect.grow(35).has_point(Vector2(785, 425)):
barriers.append(rect)
func _process(dt: float) -> void:
if running and outcome == "":
timer += dt
var previous: Vector2 = ball
ball += velocity * dt
if ball.x < 55 or ball.x > 905:
velocity.x *= -1
ball.x = clampf(ball.x, 55, 905)
bounces += 1
if ball.y < 155 or ball.y > 565:
velocity.y *= -1
ball.y = clampf(ball.y, 155, 565)
bounces += 1
for r in barriers:
if r.grow(9).has_point(ball) and not r.grow(9).has_point(previous):
if previous.x < r.position.x - 9 or previous.x > r.end.x + 9:
velocity.x *= -1
else:
velocity.y *= -1
ball = previous
bounces += 1
if ball.distance_to(Vector2(785, 425)) < 30:
outcome = "Target reached in %d bounces! R: rebuild" % bounces
elif bounces > 5 or timer > 25:
outcome = "Route failed. R: place a new layout"
queue_redraw()
func _draw() -> void:
backdrop("THREE BARRIER BANKSHOT", "Left click: place | Right click: rotate next barrier | Place three then Space: launch | R: restart")
draw_rect(Rect2(45, 145, 870, 430), Color("46617d"), false, 3)
draw_circle(Vector2(785, 425), 30, Color("287d60"))
for r in barriers:
draw_rect(r, Color("ffcd6b"))
draw_circle(ball, 9, Color.WHITE)
if not running:
draw_line(ball, ball + velocity.normalized() * 75, Color("79d7ff"), 3)
text_at("Barriers %d / 3 Bounces %d / 5 Next: %s" % [barriers.size(), bounces, "horizontal" if horizontal else "vertical"], Vector2(110, 122), 20)
text_at(outcome, Vector2(215, 618), 24)
''')
GAMES[68] = ("Merge To 128", '''extends Node2D
var board: Array[int] = []
var score: int = 0
var outcome: String = ""
func _ready() -> void:
reset()
func reset() -> void:
board.clear()
board.resize(16)
board.fill(0)
score = 0
outcome = ""
spawn()
spawn()
func spawn() -> void:
var empty: Array[int] = []
for i in range(16):
if board[i] == 0:
empty.append(i)
if not empty.is_empty():
board[empty[randi_range(0, empty.size() - 1)]] = 2
func slide(direction: int) -> void:
if outcome != "":
return
var before: Array[int] = board.duplicate()
for line in range(4):
var ids: Array[int] = []
for n in range(4):
var index: int = line * 4 + n
if direction == 1:
index = line * 4 + 3 - n
elif direction == 2:
index = n * 4 + line
elif direction == 3:
index = (3 - n) * 4 + line
ids.append(index)
var values: Array[int] = []
for index in ids:
if board[index] > 0:
values.append(board[index])
var merged: Array[int] = []
var n: int = 0
while n < values.size():
if n + 1 < values.size() and values[n] == values[n + 1]:
merged.append(values[n] * 2)
score += values[n] * 2
n += 2
else:
merged.append(values[n])
n += 1
for i in range(4):
board[ids[i]] = merged[i] if i < merged.size() else 0
if board != before:
spawn()
var possible: bool = board.has(0)
for y in range(4):
for x in range(4):
var i: int = y * 4 + x
if board[i] >= 128:
outcome = "128 reached! R: a new board"
if x < 3 and board[i] == board[i + 1]:
possible = true
if y < 3 and board[i] == board[i + 4]:
possible = true
if not possible and outcome == "":
outcome = "No legal moves. R: retry"
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_LEFT:
slide(0)
elif e.keycode == KEY_RIGHT:
slide(1)
elif e.keycode == KEY_UP:
slide(2)
elif e.keycode == KEY_DOWN:
slide(3)
queue_redraw()
func _draw() -> void:
backdrop("MERGE TO 128", "Arrow keys: slide | Equal neighbors merge once per move | Reach 128 | R: restart")
for i in range(16):
var p: Vector2 = Vector2(270 + (i % 4) * 108, 120 + (i / 4) * 108)
draw_rect(Rect2(p, Vector2(100, 100)), Color("273b55") if board[i] == 0 else Color.from_hsv(log(float(board[i])) * 0.06, 0.55, 0.9))
if board[i] > 0:
text_at(str(board[i]), p + Vector2(30, 61), 29)
text_at("Score %d" % score, Vector2(95, 160))
text_at(outcome, Vector2(280, 606), 25)
''')
GAMES[69] = ("Fragile Freight", '''extends Node2D
var cart: float = 110
var speed: float = 0
var cargo: float = 0
var cargo_speed: float = 0
var timer: float = 25
var outcome: String = ""
func reset() -> void:
cart = 110
speed = 0
cargo = 0
cargo_speed = 0
timer = 25
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
timer -= dt
var acceleration: float = Input.get_axis("ui_left", "ui_right") * 95 - speed * 0.15
speed = clampf(speed + acceleration * dt, -150, 150)
cart += speed * dt
cargo_speed += (-acceleration * 0.25 - cargo_speed * 0.85 - cargo * 0.2) * dt
cargo += cargo_speed * dt
if absf(cargo) > 65 or cart < 70:
outcome = "Cargo fell or cart left the road! R: retry"
elif cart >= 830 and absf(speed) < 28:
outcome = "Cargo delivered intact! R: drive again"
elif cart > 920 or timer <= 0:
outcome = "Missed the stopping zone! R: retry"
queue_redraw()
func _draw() -> void:
backdrop("FRAGILE FREIGHT", "Left / Right: accelerate or brake | Carry the loose ball into green zone and stop | R: restart")
draw_rect(Rect2(800, 370, 120, 150), Color("214f41"))
draw_line(Vector2(50, 500), Vector2(930, 500), Color("c1cfe8"), 5)
draw_rect(Rect2(cart - 70, 450, 140, 20), Color("79bbff"))
draw_circle(Vector2(cart - 45, 483), 16, Color("62758f"))
draw_circle(Vector2(cart + 45, 483), 16, Color("62758f"))
draw_circle(Vector2(cart + cargo, 432), 17, Color("ffcd6b"))
text_at("Speed %.0f Cargo offset %.0f Time %.1f" % [speed, cargo, maxf(timer, 0)], Vector2(240, 170))
text_at("DESTINATION", Vector2(795, 355), 18)
text_at(outcome, Vector2(240, 590), 25)
''')
GAMES[70] = ("One Thing Changed", '''extends Node2D
var objects: Array[Vector2] = []
var changed: int = 0
var stage: int = 0
var clock: float = 0
var solved: int = 0
var mistakes: int = 0
var outcome: String = ""
func _ready() -> void:
new_scene()
func new_scene() -> void:
objects.clear()
for i in range(6):
objects.append(Vector2(235 + (i % 3) * 230, 230 + (i / 3) * 210))
changed = randi_range(0, 5)
stage = 0
clock = 0
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
solved = 0
mistakes = 0
outcome = ""
new_scene()
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT and stage == 2 and outcome == "":
if e.position.distance_to(objects[changed]) < 40:
solved += 1
else:
mistakes += 1
if solved == 5:
outcome = "Five changes spotted! R: play again"
elif mistakes == 3:
outcome = "Three misses. R: look more closely"
else:
new_scene()
func _process(dt: float) -> void:
if outcome == "":
clock += dt
if stage == 0 and clock > 2.7:
stage = 1
clock = 0
elif stage == 1 and clock > 0.7:
objects[changed].x += 65 if changed % 2 == 0 else -65
stage = 2
queue_redraw()
func _draw() -> void:
backdrop("ONE THING CHANGED", "Memorize the scene | After the brief curtain, click the object that moved | R: restart")
text_at(["MEMORIZE", "CURTAIN", "WHICH OBJECT MOVED?"][stage], Vector2(330, 125), 25)
if stage != 1:
for i in range(objects.size()):
var color: Color = Color.from_hsv(i * 0.15, 0.65, 0.95)
if i % 2 == 0:
draw_circle(objects[i], 33, color)
else:
draw_rect(Rect2(objects[i] - Vector2.ONE * 31, Vector2.ONE * 62), color)
text_at(str(i + 1), objects[i] + Vector2(-7, 8), 25)
else:
draw_rect(Rect2(140, 160, 670, 360), Color("27344c"))
text_at("Found %d / 5 Misses %d / 3" % [solved, mistakes], Vector2(300, 565))
text_at(outcome, Vector2(280, 615), 25)
''')
GAMES[71] = ("Gentle Tension", '''extends Node2D
var angle: float = 0
var sweet: float = 0.45
var tension: float = 0
var opened: float = 0
var picks: int = 3
var outcome: String = ""
func reset() -> void:
angle = 0
sweet = randf_range(-1.0, 1.0)
tension = 0
opened = 0
picks = 3
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
angle = clampf(angle + Input.get_axis("ui_left", "ui_right") * dt, -1.2, 1.2)
if Input.is_action_pressed("ui_accept"):
tension = minf(1, tension + dt * 0.75)
if absf(angle - sweet) < 0.13:
opened += dt * tension * 0.6
elif tension > 0.62:
picks -= 1
tension = 0
opened = 0
else:
tension = maxf(0, tension - dt * 2.5)
if opened >= 1:
outcome = "Lock opened without force! R: another lock"
elif picks <= 0:
outcome = "All three picks broke. R: retry gently"
queue_redraw()
func _draw() -> void:
backdrop("GENTLE TENSION", "Left / Right: rotate pick | Hold Space gently to test and turn | Release to ease tension | R: restart")
draw_circle(Vector2(480, 345), 150, Color("52617a"))
draw_circle(Vector2(480, 345), 105, Color("24344c"))
var tip: Vector2 = Vector2(0, -160).rotated(angle)
draw_line(Vector2(480, 345), Vector2(480, 345) + tip, Color("ffcd6b"), 8)
draw_line(Vector2(480, 345), Vector2(480, 345) + Vector2(70, 0).rotated(opened * PI * 0.5), Color.WHITE, 12)
var near: bool = absf(angle - sweet) < 0.13
text_at("The cylinder yields!" if near and tension > 0 else "Probe lightly; resistance means the angle is wrong.", Vector2(235, 145), 21)
draw_rect(Rect2(300, 530, tension * 360, 20), Color("ff6176") if tension > 0.6 and not near else Color("5ef2d0"))
text_at("Tension Picks %d Open %d%%" % [picks, int(opened * 100)], Vector2(290, 585))
text_at(outcome, Vector2(250, 625), 23)
''')
GAMES[72] = ("Paper Airflow", '''extends Node2D
var fans: Array[Dictionary] = []
var plane: Vector2 = Vector2(125, 440)
var velocity: Vector2 = Vector2(65, 0)
var facing: int = 3
var running: bool = false
var timer: float = 0
var outcome: String = ""
var directions: Array[Vector2] = [Vector2.RIGHT, Vector2.DOWN, Vector2.LEFT, Vector2.UP]
func reset() -> void:
fans.clear()
plane = Vector2(125, 440)
velocity = Vector2(65, 0)
running = false
timer = 0
outcome = ""
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_SPACE and fans.size() == 2:
running = true
if e is InputEventMouseButton and e.pressed and not running:
if e.button_index == MOUSE_BUTTON_RIGHT:
facing = (facing + 1) % 4
elif e.button_index == MOUSE_BUTTON_LEFT and fans.size() < 2 and e.position.y > 150:
fans.append({"p": e.position, "direction": facing})
func _process(dt: float) -> void:
if running and outcome == "":
timer += dt
for fan in fans:
if plane.distance_to(fan["p"]) < 125:
velocity = velocity.move_toward(directions[fan["direction"]] * 95, 165 * dt)
plane += velocity * dt
if plane.distance_to(Vector2(790, 225)) < 35:
outcome = "Mail delivered by airflow! R: redesign"
elif plane.x < 30 or plane.x > 930 or plane.y < 125 or plane.y > 590 or timer > 18:
outcome = "Paper missed the mailbox. R: redesign fans"
queue_redraw()
func _draw() -> void:
backdrop("PAPER AIRFLOW", "Left click: place fan | Right click: rotate next fan | Place TWO then Space: launch | R: restart")
for fan in fans:
draw_arc(fan["p"], 125, 0, TAU, 48, Color("345068"), 2)
draw_circle(fan["p"], 20, Color("5ef2d0"))
draw_line(fan["p"], fan["p"] + directions[fan["direction"]] * 48, Color.WHITE, 5)
draw_rect(Rect2(760, 195, 60, 60), Color("ffcd6b"))
text_at("MAIL", Vector2(761, 185), 20)
draw_colored_polygon(PackedVector2Array([plane + Vector2(16, 0), plane + Vector2(-12, -9), plane + Vector2(-6, 0), plane + Vector2(-12, 9)]), Color.WHITE)
text_at("Fans %d / 2 Next direction: %s" % [fans.size(), ["RIGHT", "DOWN", "LEFT", "UP"][facing]], Vector2(270, 125), 20)
text_at(outcome, Vector2(230, 625), 25)
''')
GAMES[73] = ("Marble Bend", '''extends Node2D
var chain: Array[int] = [0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2]
var progress: float = 0
var next_color: int = 0
var shot: Vector2 = Vector2.ZERO
var shot_velocity: Vector2 = Vector2.ZERO
var active: bool = false
var removed: int = 0
var outcome: String = ""
var colors: Array[Color] = [Color("ff786e"), Color("79d7ff"), Color("ffcd6b")]
func reset() -> void:
chain = [0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2]
progress = 0
next_color = 0
active = false
removed = 0
outcome = ""
func path(t: float) -> Vector2:
return Vector2(150 + t, 255 + sin(t / 130.0) * 70)
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
reset()
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT and not active and outcome == "":
shot = Vector2(480, 540)
shot_velocity = (e.position - shot).normalized() * 450
active = true
func _process(dt: float) -> void:
if outcome == "":
progress += 7 * dt
if active:
shot += shot_velocity * dt
for i in range(chain.size()):
if shot.distance_to(path(progress + i * 31)) < 28:
chain.insert(i, next_color)
var left: int = i
var right: int = i
while left > 0 and chain[left - 1] == next_color:
left -= 1
while right + 1 < chain.size() and chain[right + 1] == next_color:
right += 1
if right - left + 1 >= 3:
removed += right - left + 1
for j in range(right - left + 1):
chain.remove_at(left)
next_color = (next_color + 1) % 3
active = false
break
if shot.y < 95 or shot.x < 10 or shot.x > 950:
active = false
if chain.is_empty():
outcome = "Chain cleared! R: replay"
elif progress + (chain.size() - 1) * 31 > 680:
outcome = "Marbles reached the drain. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("MARBLE BEND", "Click: launch the displayed marble toward the chain | Insert to make runs of three | R: restart")
for t in range(0, 680, 10):
draw_line(path(t), path(t + 10), Color("3c506a"), 4)
draw_circle(path(680), 26, Color("9e4259"))
for i in range(chain.size()):
draw_circle(path(progress + i * 31), 14, colors[chain[i]])
draw_circle(Vector2(480, 540), 23, colors[next_color])
if active:
draw_circle(shot, 13, colors[next_color])
text_at("Removed %d Remaining %d" % [removed, chain.size()], Vector2(290, 125))
text_at(outcome, Vector2(310, 610), 25)
''')
GAMES[74] = ("Moon Window", '''extends Node2D
var angle: float = 0.0
var target: float = 4.0
var width: float = 0.8
var wins: int = 0
var misses: int = 0
var pause: float = 0
var outcome: String = ""
func reset() -> void:
angle = 0
target = 4
width = 0.8
wins = 0
misses = 0
pause = 0
outcome = ""
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_SPACE and outcome == "" and pause <= 0:
var distance: float = absf(wrapf(angle - target, -PI, PI))
if distance < (width + 0.28) * 0.5:
wins += 1
width *= 0.77
target = fposmod(target + 2.1, TAU)
else:
misses += 1
pause = 0.45
if wins == 6:
outcome = "Six lunar alignments! R: replay"
elif misses == 3:
outcome = "Three missed windows. R: retry"
func _process(dt: float) -> void:
if outcome == "":
pause -= dt
if pause <= 0:
angle = fposmod(angle + (1.5 + wins * 0.22) * dt, TAU)
queue_redraw()
func _draw() -> void:
backdrop("MOON WINDOW", "Space: stop the moving lit sector while it overlaps the fixed gold sector | R: restart")
draw_circle(Vector2(480, 340), 156, Color("22334d"))
draw_arc(Vector2(480, 340), 150, target - width / 2, target + width / 2, 40, Color("ffcd6b"), 24)
draw_arc(Vector2(480, 340), 150, angle - 0.14, angle + 0.14, 20, Color("79d7ff"), 18)
text_at("ALIGN", Vector2(431, 350), 26)
text_at("Aligned %d / 6 Missed %d / 3" % [wins, misses], Vector2(300, 545))
text_at(outcome, Vector2(280, 610), 25)
''')
GAMES[75] = ("Torch Return", '''extends Node2D
var player: Vector2i = Vector2i(0, 4)
var treasures: Array[Vector2i] = [Vector2i(3, 3), Vector2i(7, 6), Vector2i(10, 4)]
var torch: float = 90
var outcome: String = ""
func reset() -> void:
player = Vector2i(0, 4)
treasures = [Vector2i(3, 3), Vector2i(7, 6), Vector2i(10, 4)]
torch = 90
outcome = ""
func wall(p: Vector2i) -> bool:
return p.x < 0 or p.y < 0 or p.x >= 12 or p.y >= 9 or (p.x % 3 == 2 and p.y != 1 and p.y != 7)
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed:
if e.keycode == KEY_R:
reset()
var direction: Vector2i = Vector2i.ZERO
if e.keycode == KEY_LEFT:
direction = Vector2i.LEFT
elif e.keycode == KEY_RIGHT:
direction = Vector2i.RIGHT
elif e.keycode == KEY_UP:
direction = Vector2i.UP
elif e.keycode == KEY_DOWN:
direction = Vector2i.DOWN
if outcome == "" and not wall(player + direction):
player += direction
treasures.erase(player)
if treasures.is_empty() and player == Vector2i(0, 4):
outcome = "Three treasures brought home! R: explore again"
func _process(dt: float) -> void:
if outcome == "":
torch -= dt
if torch <= 0:
outcome = "Torch exhausted. R: try a shorter route"
queue_redraw()
func _draw() -> void:
backdrop("TORCH RETURN", "Arrows: explore the dark grid | Collect three treasures, then return to entrance | R: restart")
for y in range(9):
for x in range(12):
var p: Vector2i = Vector2i(x, y)
var r: Rect2 = Rect2(180 + x * 48, 135 + y * 48, 46, 46)
if Vector2(p - player).length() <= 2.5:
draw_rect(r, Color("52617a") if wall(p) else Color("293e55"))
if treasures.has(p):
draw_circle(r.get_center(), 12, Color("ffcd6b"))
if p == Vector2i(0, 4):
draw_rect(r.grow(-8), Color("5ef2d0"), false, 3)
else:
draw_rect(r, Color("0a101b"))
draw_circle(Vector2(203, 158) + Vector2(player) * 48, 12, Color.WHITE)
text_at("Treasures %d / 3 Torch %.0f" % [3 - treasures.size(), maxf(torch, 0)], Vector2(300, 605))
text_at(outcome, Vector2(180, 115), 21)
''')
GAMES[76] = ("Four Piston Passage", '''extends Node2D
var ball: Vector2 = Vector2(180, 480)
var velocity: Vector2 = Vector2.ZERO
var pressure: Array[float] = [0.0, 0.0, 0.0, 0.0]
var corridor: Array[Rect2] = [Rect2(130, 415, 285, 130), Rect2(295, 235, 120, 310), Rect2(295, 235, 365, 120), Rect2(540, 125, 120, 230), Rect2(540, 125, 285, 110)]
var hits: int = 0
var cooldown: float = 0
var outcome: String = ""
var directions: Array[Vector2] = [Vector2.LEFT, Vector2.RIGHT, Vector2.UP, Vector2.DOWN]
var actions: Array[String] = ["ui_left", "ui_right", "ui_up", "ui_down"]
func reset() -> void:
ball = Vector2(180, 480)
velocity = Vector2.ZERO
pressure = [0.0, 0.0, 0.0, 0.0]
hits = 0
cooldown = 0
outcome = ""
func safe(p: Vector2) -> bool:
for offset in [Vector2(-12, 0), Vector2(12, 0), Vector2(0, -12), Vector2(0, 12)]:
var ok: bool = false
for r in corridor:
if r.has_point(p + offset):
ok = true
if not ok:
return false
return true
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
cooldown -= dt
for i in range(4):
pressure[i] = move_toward(pressure[i], 1.0 if Input.is_action_pressed(actions[i]) else 0.0, dt * 3)
velocity += directions[i] * pressure[i] * 250 * dt
velocity *= exp(-3 * dt)
var next: Vector2 = ball + velocity * dt
if safe(next):
ball = next
else:
velocity *= -0.3
if cooldown <= 0:
hits += 1
cooldown = 0.7
if ball.distance_to(Vector2(785, 180)) < 28:
outcome = "Ball delivered through all bends! R: replay"
elif hits >= 8:
outcome = "Eight pressure collisions. R: use gentler pulses"
queue_redraw()
func _draw() -> void:
backdrop("FOUR PISTON PASSAGE", "Hold arrows: independent directional pistons build pressure | Guide ball through the zigzag | R: restart")
for r in corridor:
draw_rect(r, Color("263e57"))
draw_circle(Vector2(785, 180), 28, Color("25855f"))
for i in range(4):
var origin: Vector2 = ball - directions[i] * (52 - pressure[i] * 20)
draw_line(origin - directions[i] * 22, origin, Color("ffcd6b"), 14)
draw_circle(ball, 12, Color.WHITE)
text_at("Wall strikes %d / 8" % hits, Vector2(60, 585))
text_at(outcome, Vector2(260, 625), 23)
''')
GAMES[77] = ("One Then Two", '''extends Node2D
var ball: Vector2 = Vector2(210, 430)
var velocity: Vector2 = Vector2.ZERO
var targets: Array[Vector2] = [Vector2(460, 300), Vector2(690, 330)]
var pockets: Array[Vector2] = [Vector2(110, 150), Vector2(850, 150), Vector2(110, 550), Vector2(850, 550)]
var order: int = 0
var dragging: bool = false
var drag_start: Vector2 = Vector2.ZERO
var shooting: bool = false
var shots: int = 0
var note: String = "Hit 1, then 2, then any corner pocket."
var outcome: String = ""
var contact: int = -1
func reset_ball() -> void:
ball = Vector2(210, 430)
velocity = Vector2.ZERO
order = 0
shooting = false
contact = -1
func fail_shot(reason: String) -> void:
note = reason + " Balls reset."
reset_ball()
if shots >= 5:
outcome = "Five shots exhausted. R: retry"
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
shots = 0
outcome = ""
reset_ball()
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT and outcome == "" and not shooting:
if e.pressed and e.position.distance_to(ball) < 30:
dragging = true
drag_start = e.position
elif not e.pressed and dragging:
dragging = false
velocity = (drag_start - e.position).limit_length(220) * 3
if velocity.length() > 25:
shooting = true
shots += 1
func _process(dt: float) -> void:
if shooting and outcome == "":
ball += velocity * dt
velocity *= exp(-0.16 * dt)
if ball.x < 120 or ball.x > 840:
velocity.x *= -1
ball.x = clampf(ball.x, 120, 840)
if ball.y < 160 or ball.y > 540:
velocity.y *= -1
ball.y = clampf(ball.y, 160, 540)
var touching: int = -1
for i in range(2):
if ball.distance_to(targets[i]) < 28:
touching = i
if contact != i:
if i != order:
fail_shot("Wrong ball order!")
break
order += 1
var normal: Vector2 = (ball - targets[i]).normalized()
velocity = velocity.bounce(normal)
ball = targets[i] + normal * 29
contact = touching
for pocket in pockets:
if ball.distance_to(pocket) < 30:
if order == 2:
outcome = "Correct order and pocket! R: replay"
else:
fail_shot("Pocketed before both contacts!")
if shooting and velocity.length() < 20:
fail_shot("Shot stopped short.")
queue_redraw()
func _draw() -> void:
backdrop("ONE THEN TWO", "Drag backward from cue ball, release to shoot | Hit numbered balls in order, then a pocket | R: restart")
draw_rect(Rect2(100, 140, 760, 420), Color("205945"))
for p in pockets:
draw_circle(p, 27, Color("101b26"))
for i in range(2):
draw_circle(targets[i], 16, Color("ffcd6b") if i == 0 else Color("ff786e"))
text_at(str(i + 1), targets[i] + Vector2(-6, 7), 20)
draw_circle(ball, 12, Color.WHITE)
if dragging:
draw_line(ball, ball + (drag_start - get_global_mouse_position()).limit_length(220), Color("79d7ff"), 3)
text_at("Contacts %d / 2 Shots %d / 5" % [order, shots], Vector2(300, 120), 20)
text_at(note if outcome == "" else outcome, Vector2(210, 612), 23)
''')
GAMES[78] = ("Falling Symbols", '''extends Node2D
var symbols: Array[String] = ["+", "X", "O", "#"]
var target: Array[int] = [0, 2, 1, 3]
var rows: Array[Dictionary] = []
var next: int = 0
var completed: int = 0
var misses: int = 0
var spawn: float = 0
var outcome: String = ""
func reset() -> void:
rows.clear()
next = 0
completed = 0
misses = 0
spawn = 0
outcome = ""
func cell(row: Dictionary, column: int) -> Rect2:
return Rect2(270 + column * 110, row["y"], 96, 46)
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
reset()
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT and outcome == "":
for row in rows:
for col in range(4):
if cell(row, col).has_point(e.position) and not row["used"].has(col):
if row["values"][col] == target[next]:
row["used"].append(col)
next += 1
if next == 4:
completed += 1
next = 0
else:
misses += 1
return
func _process(dt: float) -> void:
if outcome == "":
spawn -= dt
if spawn <= 0:
var values: Array[int] = [0, 1, 2, 3]
values.shuffle()
rows.append({"y": 175.0, "values": values, "used": []})
spawn = 3
for i in range(rows.size() - 1, -1, -1):
rows[i]["y"] += 40 * dt
if rows[i]["y"] > 550:
if rows[i]["used"].size() < 4:
misses += 1
rows.remove_at(i)
if completed >= 6:
outcome = "Six symbol sequences completed! R: replay"
elif misses >= 5:
outcome = "Five mistakes or escaped rows. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("FALLING SYMBOLS", "Read target left to right | Click the next required symbol in any falling row | R: restart")
for i in range(4):
draw_rect(Rect2(300 + i * 95, 100, 70, 50), Color("99763e") if i == next else Color("334966"))
text_at(symbols[target[i]], Vector2(322 + i * 95, 136), 30)
for row in rows:
for col in range(4):
draw_rect(cell(row, col), Color("203343") if row["used"].has(col) else Color("476587"))
if not row["used"].has(col):
text_at(symbols[row["values"][col]], cell(row, col).position + Vector2(37, 32), 27)
draw_line(Vector2(200, 597), Vector2(770, 597), Color("ff6176"), 3)
text_at("Sequences %d / 6 Misses %d / 5" % [completed, misses], Vector2(280, 625), 20)
text_at(outcome, Vector2(235, 575), 22)
''')
GAMES[79] = ("Corner Runner", '''extends Node2D
var distance: float = 0
var jump: float = 0
var tokens: Array[bool] = [false, false, false, false]
var outcome: String = ""
var obstacles: Array[float] = [220.0, 760.0, 1150.0, 1660.0]
func reset() -> void:
distance = 0
jump = 0
tokens = [false, false, false, false]
outcome = ""
func point(t: float) -> Vector2:
t = fposmod(t, 1840)
if t < 600:
return Vector2(180 + t, 190)
if t < 920:
return Vector2(780, 190 + t - 600)
if t < 1520:
return Vector2(780 - (t - 920), 510)
return Vector2(180, 510 - (t - 1520))
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_SPACE and jump <= 0:
jump = 0.65
func _process(dt: float) -> void:
if outcome == "":
distance += 175 * dt
jump = maxf(0, jump - dt)
var checkpoints: Array[float] = [0.0, 600.0, 920.0, 1520.0]
for i in range(4):
if absf(fposmod(distance - checkpoints[i] + 920, 1840) - 920) < 18:
tokens[i] = true
for obstacle in obstacles:
if absf(fposmod(distance - obstacle + 920, 1840) - 920) < 22 and jump < 0.1:
outcome = "Hit an obstacle! R: jump a little earlier"
if distance >= 1840 and not tokens.has(false):
outcome = "Four corner tokens and a clean lap! R: replay"
queue_redraw()
func _draw() -> void:
backdrop("CORNER RUNNER", "Automatic perimeter run | Space: jump inward over red obstacles | Collect four corner tokens | R: restart")
draw_rect(Rect2(180, 190, 600, 320), Color("52617a"), false, 7)
for t in obstacles:
draw_rect(Rect2(point(t) - Vector2.ONE * 15, Vector2.ONE * 30), Color("ff6176"))
var corners: Array[float] = [0.0, 600.0, 920.0, 1520.0]
for i in range(4):
if not tokens[i]:
draw_circle(point(corners[i]), 14, Color("ffcd6b"))
var p: Vector2 = point(distance)
if jump > 0:
p += (Vector2(480, 350) - p).normalized() * sin(jump / 0.65 * PI) * 75
draw_rect(Rect2(p - Vector2.ONE * 11, Vector2.ONE * 22), Color("5ef2d0"))
text_at("Lap %d%% Tokens %d / 4" % [int(minf(distance / 1840, 1) * 100), tokens.count(true)], Vector2(315, 140))
text_at(outcome, Vector2(220, 600), 24)
''')
GAMES[80] = ("Drifting Radio", '''extends Node2D
var settings: Array[float] = [0.25, 0.25]
var target: Array[float] = [0.5, 0.65]
var selected: int = -1
var clock: float = 0
var stable: float = 0
var outcome: String = ""
func reset() -> void:
settings = [0.25, 0.25]
clock = 0
stable = 0
outcome = ""
func slider(i: int) -> Rect2:
return Rect2(180, 430 + i * 90, 600, 35)
func adjust(p: Vector2) -> void:
if selected >= 0:
settings[selected] = clampf((p.x - 180) / 600, 0, 1)
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and e.keycode == KEY_R:
reset()
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
if e.pressed:
for i in range(2):
if slider(i).grow(14).has_point(e.position):
selected = i
adjust(e.position)
else:
selected = -1
if e is InputEventMouseMotion:
adjust(e.position)
func _process(dt: float) -> void:
if outcome == "":
clock += dt
target = [0.5 + sin(clock * 0.3) * 0.18, 0.5 + cos(clock * 0.19) * 0.15]
var error: float = absf(settings[0] - target[0]) + absf(settings[1] - target[1])
stable = minf(8, stable + dt) if error < 0.09 else maxf(0, stable - dt * 2)
if stable >= 8:
outcome = "Signal locked for eight seconds! R: retune"
elif clock > 90:
outcome = "Transmission ended. R: retry"
queue_redraw()
func _draw() -> void:
backdrop("DRIFTING RADIO", "Drag FREQUENCY and PHASE sliders | Steady the waveform and track its drift for eight seconds | R: restart")
var error: float = absf(settings[0] - target[0]) + absf(settings[1] - target[1])
var previous: Vector2 = Vector2(160, 280)
for i in range(101):
var x: float = i / 100.0
var y: float = sin(x * 30 + clock * error * 12) * error * 150 + sin(x * 10 + settings[1] * TAU) * 15
var point: Vector2 = Vector2(160 + x * 640, 280 + y)
if i > 0:
draw_line(previous, point, Color("5ef2d0") if error < 0.09 else Color("ff9568"), 3)
previous = point
for i in range(2):
draw_rect(slider(i), Color("334966"))
draw_circle(Vector2(180 + settings[i] * 600, 447 + i * 90), 17, Color("ffcd6b"))
var guidance: String = "raise" if settings[i] < target[i] - 0.03 else "lower" if settings[i] > target[i] + 0.03 else "near lock"
text_at(("FREQUENCY" if i == 0 else "PHASE") + " - " + guidance, Vector2(180, 416 + i * 90), 20)
text_at("Stable %.1f / 8 seconds" % stable, Vector2(340, 140))
text_at(outcome, Vector2(255, 613), 23)
''')
GAMES[81] = ("Three Plank Bridge", '''extends Node2D
var gaps: Array[int] = [3, 4, 5, 8, 9, 12, 13, 14]
var planks: Array[int] = []
var x: float = 105
var running: bool = false
var outcome: String = ""
func reset() -> void:
planks.clear()
x = 105
running = false
outcome = ""
func supported(cell: int) -> bool:
if not gaps.has(cell):
return true
for start in planks:
if cell >= start and cell < start + 3:
return true
return false
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
elif e.keycode == KEY_SPACE and outcome == "":
running = true
if e is InputEventMouseButton and e.pressed and not running and e.position.y > 270 and e.position.y < 520:
var cell: int = clampi(floori((e.position.x - 84) / 44), 0, 15)
if e.button_index == MOUSE_BUTTON_LEFT and planks.size() < 3:
planks.append(cell)
elif e.button_index == MOUSE_BUTTON_RIGHT:
for i in range(planks.size() - 1, -1, -1):
if cell >= planks[i] and cell < planks[i] + 3:
planks.remove_at(i)
break
func _process(dt: float) -> void:
if running and outcome == "":
x += 105 * dt
var cell: int = floori((x - 84) / 44)
if not supported(cell):
outcome = "Unsupported step! R: rebuild the bridge"
elif x >= 855:
outcome = "Bridge test passed within budget! R: rebuild"
queue_redraw()
func _draw() -> void:
backdrop("THREE PLANK BRIDGE", "Left click: place a three-tile plank starting there | Right click: remove | Space: test | R: restart")
for i in range(18):
var r: Rect2 = Rect2(84 + i * 44, 445, 44, 110)
if not gaps.has(i):
draw_rect(r, Color("46617d"))
else:
draw_rect(r, Color("142131"))
text_at(str(i), Vector2(97 + i * 44, 590), 16)
for start in planks:
draw_rect(Rect2(84 + start * 44, 433, 132, 12), Color("ffcd6b"))
draw_rect(Rect2(84 + start * 44, 433, 132, 12), Color("996b32"), false, 2)
draw_rect(Rect2(x - 10, 405, 20, 28), Color("5ef2d0"))
text_at("Budget: %d / 3 planks" % planks.size(), Vector2(335, 190), 25)
text_at("Cover every dark gap. Unsupported steps fail immediately.", Vector2(205, 250), 20)
text_at(outcome, Vector2(230, 625), 23)
''')
GAMES[82] = ("Five Card Skirmish", '''extends Node2D
var hp: int = 12
var enemy: int = 16
var energy: int = 3
var turn: int = 0
var intent: int = 0
var shield: int = 0
var note: String = "Choose a card; the previewed enemy action resolves next."
var outcome: String = ""
var names: Array[String] = ["STRIKE", "HEAVY", "SHIELD", "HEAL", "CHARGE"]
var costs: Array[int] = [1, 2, 1, 2, 0]
func reset() -> void:
hp = 12
enemy = 16
energy = 3
turn = 0
intent = 0
shield = 0
outcome = ""
func card(i: int) -> Rect2:
return Rect2(50 + i * 174, 390, 160, 155)
func play(i: int) -> void:
if outcome != "":
return
if energy < costs[i]:
note = "Not enough energy. Use CHARGE."
return
energy -= costs[i]
shield = 0
match i:
0: enemy -= 3
1: enemy -= 6
2: shield = 5
3: hp = mini(12, hp + 5)
4: energy = mini(6, energy + 3)
if enemy <= 0:
outcome = "Enemy defeated! R: a new skirmish"
return
if intent == 0:
hp -= maxi(0, 3 - shield)
note = "Enemy attacked for 3, reduced by this turn's shield."
elif intent == 1:
hp -= maxi(0, 5 - shield)
note = "Enemy used its previewed heavy attack."
else:
enemy = mini(16, enemy + 2)
note = "Enemy recovered 2 health."
turn += 1
intent = turn % 3
if hp <= 0:
outcome = "You were defeated. R: plan against the preview"
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed and not e.echo:
if e.keycode == KEY_R:
reset()
for i in range(5):
if e.keycode == KEY_1 + i:
play(i)
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT:
for i in range(5):
if card(i).has_point(e.position):
play(i)
queue_redraw()
func _draw() -> void:
backdrop("FIVE CARD SKIRMISH", "Click one of five cards or press 1–5 | Your action, then the previewed enemy turn | R: restart")
text_at("YOU: %d / 12 HP Energy %d / 6" % [hp, energy], Vector2(80, 165), 24)
text_at("ENEMY: %d / 16 HP" % enemy, Vector2(610, 165), 24)
text_at("NEXT ENEMY: " + ["Attack 3", "Heavy attack 5", "Recover 2 HP"][intent], Vector2(285, 245), 26, Color("ff9568"))
for i in range(5):
draw_rect(card(i), Color("3a526e"))
text_at(names[i], card(i).position + Vector2(14, 40), 22)
text_at("Cost %d" % costs[i], card(i).position + Vector2(17, 83), 20)
text_at(["3 damage", "6 damage", "Block 5", "Heal 5", "+3 energy"][i], card(i).position + Vector2(14, 125), 18)
text_at(note if outcome == "" else outcome, Vector2(125, 610), 23)
''')
GAMES[83] = ("Color Cargo Train", '''extends Node2D
var train: Vector2i = Vector2i(1, 5)
var direction: Vector2i = Vector2i.RIGHT
var wagons: Dictionary = {Vector2i(3, 5): 0, Vector2i(6, 2): 1, Vector2i(9, 6): 2}
var cargo: Array[int] = []
var target: Array[int] = [0, 1, 2]
var history: Array[Vector2i] = []
var clock: float = 0
var outcome: String = ""
var colors: Array[Color] = [Color("ff6176"), Color("79d7ff"), Color("ffcd6b")]
func reset() -> void:
train = Vector2i(1, 5)
direction = Vector2i.RIGHT
wagons = {Vector2i(3, 5): 0, Vector2i(6, 2): 1, Vector2i(9, 6): 2}
cargo.clear()
history.clear()
clock = 0
outcome = ""
func _input(e: InputEvent) -> void:
if e is InputEventKey and e.pressed:
if e.keycode == KEY_R:
reset()
var next: Vector2i = direction
if e.keycode == KEY_LEFT:
next = Vector2i.LEFT
elif e.keycode == KEY_RIGHT:
next = Vector2i.RIGHT
elif e.keycode == KEY_UP:
next = Vector2i.UP
elif e.keycode == KEY_DOWN:
next = Vector2i.DOWN
if next != -direction:
direction = next
func _process(dt: float) -> void:
if outcome == "":
clock += dt
if clock >= 0.35:
clock = 0
history.push_front(train)
if history.size() > 3:
history.pop_back()
train += direction
if train.x < 0 or train.x >= 12 or train.y < 0 or train.y >= 8:
outcome = "Train left the tracks! R: retry"
elif wagons.has(train):
cargo.append(wagons[train])
wagons.erase(train)
if cargo[-1] != target[cargo.size() - 1]:
outcome = "Wrong wagon order! R: reroute"
if train == Vector2i(10, 1):
outcome = "Matching train arrived! R: replay" if cargo == target else "Station rejected an incomplete sequence. R: retry"
queue_redraw()
func point(p: Vector2i) -> Vector2:
return Vector2(215, 162) + Vector2(p) * 45
func _draw() -> void:
backdrop("COLOR CARGO TRAIN", "Arrows: steer the moving train | Collect RED, BLUE, GOLD in order, then enter station S | R: restart")
for y in range(8):
for x in range(12):
draw_rect(Rect2(point(Vector2i(x, y)) - Vector2.ONE * 21, Vector2.ONE * 42), Color("26394e"), false, 1)
for p in wagons:
draw_rect(Rect2(point(p) - Vector2.ONE * 15, Vector2.ONE * 30), colors[wagons[p]])
draw_rect(Rect2(point(Vector2i(10, 1)) - Vector2.ONE * 20, Vector2.ONE * 40), Color("31785a"))
text_at("S", point(Vector2i(10, 1)) + Vector2(-7, 8), 24)
for i in range(mini(cargo.size(), history.size())):
draw_rect(Rect2(point(history[i]) - Vector2.ONE * 13, Vector2.ONE * 26), colors[cargo[i]])
draw_circle(point(train), 16, Color.WHITE)
text_at("Wagons %d / 3 TARGET: RED > BLUE > GOLD" % cargo.size(), Vector2(230, 555))
text_at(outcome, Vector2(210, 610), 23)
''')
GAMES[84] = ("Bubble Passage", '''extends Node2D
var bubble: Vector2 = Vector2(160, 570)
var air: float = 55
var walls: Array[Rect2] = [Rect2(20, 455, 395, 25), Rect2(445, 455, 495, 25), Rect2(20, 340, 625, 25), Rect2(675, 340, 265, 25), Rect2(20, 225, 305, 25), Rect2(335, 225, 605, 25)]
var outcome: String = ""
var radius: float = 16
func reset() -> void:
bubble = Vector2(160, 570)
air = 55
outcome = ""
func _process(dt: float) -> void:
if Input.is_physical_key_pressed(KEY_R):
reset()
if outcome == "":
var shrink: bool = Input.is_action_pressed("ui_accept")
radius = 4.0 if shrink else 16.0
air -= dt * (1.8 if shrink else 1.0)
var movement: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") * 175
var next: Vector2 = bubble + movement * dt
next.x = clampf(next.x, 25 + radius, 935 - radius)
next.y = minf(600 - radius, next.y)
var blocked: bool = false
for r in walls:
if r.grow(radius).has_point(next):
blocked = true
if not blocked:
bubble = next
if bubble.y < 130:
outcome = "Surface reached with air to spare! R: dive again"
elif air <= 0:
outcome = "Air exhausted. R: shrink only at narrow gates"
queue_redraw()
func _draw() -> void:
backdrop("BUBBLE PASSAGE", "Arrows: swim upward through the gates | Hold Space: shrink, using extra air | R: restart")
draw_rect(Rect2(20, 95, 920, 35), Color("276c86"))
text_at("SURFACE", Vector2(420, 120), 20)
for r in walls:
draw_rect(r, Color("46617d"))
draw_circle(bubble, radius, Color("79d7ff"))
draw_arc(bubble, radius, 0, TAU, 24, Color.WHITE, 2)
text_at("Air %.1f %s" % [maxf(air, 0), "SHRUNK" if radius < 10 else "NORMAL"], Vector2(30, 625), 22)
text_at(outcome, Vector2(320, 625), 22)
''')
if __name__ == "__main__":
main()