123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- local num_flashes = 7
- local function reset()
- -- new game
- digiline_send("display", "----**---- Tic-Tac-Toe ----**---- Waiting for players")
- for i = 1, 9 do
- digiline_send(tostring(i), "off#888")
- mem.stat[i] = false
- end
- mem.player[2] = nil
- mem.player[1] = nil
- mem.turn = 1
- mem.winner = nil
- mem.rst_ok = true
- mem.flash_counter = nil
- end
- local function won(turn)
- for i = 1, 8 do
- local line = mem.lines[i]
- if mem.stat[line:byte(1) - 48] == turn
- and mem.stat[line:byte(2) - 48] == turn
- and mem.stat[line:byte(3) - 48] == turn
- then
- return line
- end
- end
- return false
- end
- local function draw()
- return mem.stat[1] and mem.stat[2] and mem.stat[3]
- and mem.stat[4] and mem.stat[5] and mem.stat[6]
- and mem.stat[7] and mem.stat[8] and mem.stat[9]
- end
- if event.type == "program" then
- mem.stat = {}
- mem.player = {}
- mem.lines = { "123", "456", "789", "147", "258", "369", "159", "357" }
- reset()
- elseif event.type == "digiline" then
- local idx = event.channel:byte(1) - 48
- -- 0x52 = ASCII code of "R"
- if idx < 1 or idx > 9 or #event.channel > 1 or event.msg:byte(1) ~= 0x52
- or mem.winner or mem.stat[idx]
- then
- return -- not for us, or not rightclick, or game end, or cell occupied
- end
- if not mem.player[mem.turn] then
- mem.player[mem.turn] = event.msg:sub(3)
- elseif event.msg:sub(3) ~= mem.player[mem.turn] then
- return -- wrong player
- end
- -- give the player 30 seconds to think the move before allowing reset
- mem.rst_ok = false
- mem.stat[idx] = mem.turn
- digiline_send(tostring(idx), mem.turn == 1 and "on#f44" or "on#0f0")
- local winner_line = won(mem.turn)
- if winner_line then
- digiline_send("display", "Winner: " .. mem.player[mem.turn])
- mem.winner = mem.turn
- interrupt(999, "enable_reset")
- mem.flash_counter = num_flashes
- interrupt(0.5, "flash")
- for i = 1, 9 do
- if winner_line:byte(1) - 48 ~= i
- and winner_line:byte(2) - 48 ~= i
- and winner_line:byte(3) - 48 ~= i
- and mem.stat[i]
- then
- digiline_send(tostring(i), mem.stat[i] == 1 and "off#f44" or "off#0f0")
- end
- end
- elseif draw() then
- digiline_send("display", "It's a draw!")
- mem.winner = 0
- interrupt(0, "enable_reset")
- else
- mem.turn = 3 - mem.turn
- if not mem.player[mem.turn] then
- digiline_send("display", "Waiting for second player")
- else
- digiline_send("display", mem.player[mem.turn] .. " to play")
- end
- interrupt(30, "enable_reset")
- end
- elseif event.type == "on" then
- -- must be reset signal
- if mem.rst_ok then
- reset()
- end
- elseif event.type == "interrupt" then
- if event.iid == "enable_reset" then
- -- timer expired - the game can be reset
- mem.rst_ok = true
- elseif event.iid == "flash" then
- mem.flash_counter = mem.flash_counter - 1
- if mem.flash_counter == 0 then
- mem.flash_counter = nil
- interrupt(0, "enable_reset")
- return
- end
- interrupt(0.5, "flash")
- local turn_on, turn_off = "on#f44", "off#f44"
- if mem.winner == 2 then
- turn_on, turn_off = "on#0f0", "off#0f0"
- end
- local turn = mem.flash_counter % 2 == 1 and turn_on or turn_off
- local winner_line = won(mem.turn)
- for i = 1, 3 do
- digiline_send(tostring(winner_line:byte(i) - 48), turn)
- end
- end
- end
|