Create: Computing AgesBrass Docs
Built-in programs

pong

network pong for two

Runs on Mini+ Minicomputer and newer · 142 lines
Type this at the prompt of a computer to copy it onto the medium:
Terminal
> examples pong
> edit pong

The program

pong
-- PONG for two players on two computers linked by data cable, radio
-- modems or Wi-Fi. First computer: pong host   Second one: pong join
-- Up/down arrows (or W/S) move your paddle. First to 5 wins. Ctrl+T quits.
-- The host moves the ball and sends the whole state 10 times a second;
-- the other computer only sends its paddle.
local mode = arg[1]
if mode ~= "host" and mode ~= "join" then
  print("Usage: pong host   or   pong join")
  return
end
local W, H, PAD, WIN = 40, 15, 4, 5  -- field, paddle height, winning score
local me = {y = 6}
local other = {y = 6}
local left, right = me, other  -- the host plays on the left
if mode == "join" then left, right = other, me end
local ball = {x = 20, y = 8, dx = 1, dy = 1, wait = 10}
local score = {left = 0, right = 0}
local peer = nil
local running = true

-- 1. Find the other player
if mode == "host" then
  print("Waiting for a player (pong join)...")
  while peer == nil do
    local m = net.receive()
    if m.channel == "pong" and m.data == "join" then
      peer = m.sender
      net.send(peer, "hello", "pong")
    end
  end
else
  print("Looking for a game (pong host)...")
  while peer == nil do
    net.broadcast("join", "pong")
    local m = net.receive(1)  -- nil after 1 second without message
    if m and m.channel == "pong" and m.data == "hello" then peer = m.sender end
  end
end

-- 2. The ball: only the host moves it
function serve(dir)
  ball.x = W // 2
  ball.y = H // 2
  ball.dx = dir
  if math.random(2) == 1 then ball.dy = 1 else ball.dy = -1 end
  ball.wait = 10  -- one second before the serve
end

function hit(paddle, y)
  return y >= paddle.y and y < paddle.y + PAD
end

function step()
  if ball.wait > 0 then
    ball.wait = ball.wait - 1
    return
  end
  local nx = ball.x + ball.dx
  local ny = ball.y + ball.dy
  if ny < 1 or ny > H then  -- bounce on the walls
    ball.dy = -ball.dy
    ny = ball.y + ball.dy
  end
  if nx == 1 and hit(left, ny) then
    ball.dx = 1
    nx = ball.x + 1
  elseif nx == W and hit(right, ny) then
    ball.dx = -1
    nx = ball.x - 1
  elseif nx < 1 then
    score.right = score.right + 1
    serve(1)
    return
  elseif nx > W then
    score.left = score.left + 1
    serve(-1)
    return
  end
  ball.x = nx
  ball.y = ny
end

-- 3. Drawing, on both computers
function draw()
  term.clear()
  term.set_fg(term.colors.yellow)
  term.set_cursor(W // 2 - 2, 1)
  term.write(score.left .. " - " .. score.right)
  term.set_fg(term.colors.white)
  term.set_cursor(1, 2)
  term.write(string.rep("=", W + 2))
  term.set_cursor(1, H + 3)
  term.write(string.rep("=", W + 2))
  for i = 0, PAD - 1 do
    term.set_cursor(2, left.y + 2 + i)
    term.write("#")
    term.set_cursor(W + 1, right.y + 2 + i)
    term.write("#")
  end
  term.set_fg(term.colors.orange)
  term.set_cursor(ball.x + 1, ball.y + 2)
  term.write("O")
  term.set_fg(term.colors.white)
end

-- 4. The game loop: keys, messages, and a timer every 0.1 s
local timer = os.start_timer(0.1)
while running do
  local e = os.pull_event()  -- any event
  if e.name == "key" or e.name == "char" then
    local k = e.key or e.char
    if (k == "up" or k == "w" or k == "z") and me.y > 1 then me.y = me.y - 1 end
    if (k == "down" or k == "s") and me.y < H - PAD + 1 then me.y = me.y + 1 end
    if mode == "join" then net.send(peer, {y = me.y}, "pong") end
  elseif e.name == "message" and e.sender == peer and type(e.data) == "table" then
    local d = e.data
    other.y = d.y
    if mode == "join" then  -- the host sends the whole state
      ball.x = d.bx
      ball.y = d.by
      score.left = d.sl
      score.right = d.sr
    end
  elseif e.name == "timer" and e.id == timer then
    timer = os.start_timer(0.1)
    if mode == "host" then
      step()
      net.send(peer, {y = me.y, bx = ball.x, by = ball.y, sl = score.left, sr = score.right}, "pong")
    end
    draw()
    if score.left >= WIN or score.right >= WIN then running = false end
  end
end

term.set_cursor(1, H + 4)
local mine = score.left
if mode == "join" then mine = score.right end
if mine >= WIN then
  print("You win!")
else
  print("You lose!")
end