📖 Scripting Guide
Your bot is a Lua script that returns "rock", "paper", or "scissors".
Here's everything you need to write a winning strategy.
🎯 The Basics
Your script receives a game table and must return a valid move:
-- Simplest possible bot: always plays rock
return "rock" That's it! But to win, you'll want to use the game context:
-- Use the round number to mix it up
if game.round % 3 == 1 then
return "rock"
elseif game.round % 3 == 2 then
return "paper"
else
return "scissors"
end🎮 The game Table
Your script has access to these variables:
| Field | Type | Description |
|---|---|---|
game.round | number | Current round (1–100) |
game.my_history | table | Your previous moves (strings) |
game.their_history | table | Opponent's previous moves (strings) |
-- Counter the opponent's last move
if game.round == 1 then
return "rock"
end
local last = game.their_history[#game.their_history]
if last == "rock" then return "paper"
elseif last == "scissors" then return "rock"
else return "scissors"
end🧰 Lua Cheatsheet
Variables
local x = 10 -- number
local name = "hello" -- string
local flag = true -- boolean
local list = {1, 2, 3} -- table (array) Conditionals
if x > 5 then
-- do something
elseif x == 3 then
-- another thing
else
-- fallback
end Loops
-- Count loop
for i = 1, 10 do
print(i)
end
-- Loop over a table
for i, value in ipairs(list) do
print(i, value)
end Tables (arrays & maps)
local t = {"rock", "paper", "scissors"}
print(#t) -- length: 3
print(t[1]) -- "rock" (1-indexed!)
-- Key-value map
local scores = {rock = 0, paper = 0}
scores.rock = scores.rock + 1 Functions
local function counter(move)
if move == "rock" then return "paper"
elseif move == "scissors" then return "rock"
else return "scissors"
end
end
return counter(game.their_history[#game.their_history] or "rock") Math & Random
math.random() -- float 0.0–1.0
math.random(3) -- integer 1, 2, or 3
math.max(1, 5, 3) -- 5
math.min(1, 5, 3) -- 1
math.floor(3.7) -- 3 String Operations
string.len("hello") -- 5
string.sub("hello", 1, 3) -- "hel"
"rock" == "rock" -- true💡 Strategy Ideas
- Random: Pick a random move each round — hard to predict!
- Counter: Beat whatever they played last round
- Pattern detection: Track their move frequencies and counter the most common
- Mixed strategy: Play randomly but weight towards countering their favorite move
- Markov chain: Predict their next move based on transitions between their moves
-- Frequency counter: play the counter to their most common move
local counts = {rock = 0, paper = 0, scissors = 0}
for _, move in ipairs(game.their_history) do
counts[move] = counts[move] + 1
end
local most_common = "rock"
for move, count in pairs(counts) do
if count > counts[most_common] then
most_common = move
end
end
-- Counter the most common
if most_common == "rock" then return "paper"
elseif most_common == "scissors" then return "rock"
else return "scissors"
end⚠️ Rules & Limits
- Scripts must return
"rock","paper", or"scissors" - Max 100,000 instructions per round (no infinite loops)
- Max 10KB script size
- No file/network/OS access — sandbox only
- Available globals:
math,string,table,pairs,ipairs,type,tostring,tonumber,select,unpack,pcall - If your script errors or returns an invalid move, you forfeit that round
🐛 Reading Error Messages
When your script has a bug, the test runner shows an error like:
💥 line 5: syntax error near 'if' What the parts mean
| Part | Meaning |
|---|---|
line 5 | The line number in your script where the error was found |
syntax error near 'if' | What went wrong — Lua found something unexpected near if |
Common errors
| Error | Cause | Fix |
|---|---|---|
syntax error near 'X' | Unexpected token — usually a missing then, end, or typo | Check the line above for missing keywords |
'end' expected | An if, for, or function block wasn't closed | Add the missing end |
attempt to index a nil value | Accessing a field on something that doesn't exist | Check variable names and that tables are populated |
attempt to call a nil value | Calling a function that doesn't exist | Check spelling; some globals are removed in the sandbox |
Script timeout: exceeded maximum instructions | Infinite loop or very long computation | Add a loop exit condition or simplify logic |
Tips
- Errors often point to the line after the actual mistake — check the line above too
- Use the Test button frequently as you write — catch errors early
- If your script returns an invalid move (not rock/paper/scissors), you'll see a ⚠️ warning instead of an error
🔗 Learn More
- Lua 5.4 Reference Manual — Official docs
- Programming in Lua — Free online book (1st edition)
- Learn Lua in Y Minutes — Quick interactive overview
- Learn Lua in 15 Minutes — Concise crash course
- Codecademy Lua Docs — Beginner-friendly reference