tic-tac-toe.lua 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. local num_flashes = 7
  2. local function reset()
  3. -- new game
  4. digiline_send("display", "----**---- Tic-Tac-Toe ----**---- Waiting for players")
  5. for i = 1, 9 do
  6. digiline_send(tostring(i), "off#888")
  7. mem.stat[i] = false
  8. end
  9. mem.player[2] = nil
  10. mem.player[1] = nil
  11. mem.turn = 1
  12. mem.winner = nil
  13. mem.rst_ok = true
  14. mem.flash_counter = nil
  15. end
  16. local function won(turn)
  17. for i = 1, 8 do
  18. local line = mem.lines[i]
  19. if mem.stat[line:byte(1) - 48] == turn
  20. and mem.stat[line:byte(2) - 48] == turn
  21. and mem.stat[line:byte(3) - 48] == turn
  22. then
  23. return line
  24. end
  25. end
  26. return false
  27. end
  28. local function draw()
  29. return mem.stat[1] and mem.stat[2] and mem.stat[3]
  30. and mem.stat[4] and mem.stat[5] and mem.stat[6]
  31. and mem.stat[7] and mem.stat[8] and mem.stat[9]
  32. end
  33. if event.type == "program" then
  34. mem.stat = {}
  35. mem.player = {}
  36. mem.lines = { "123", "456", "789", "147", "258", "369", "159", "357" }
  37. reset()
  38. elseif event.type == "digiline" then
  39. local idx = event.channel:byte(1) - 48
  40. -- 0x52 = ASCII code of "R"
  41. if idx < 1 or idx > 9 or #event.channel > 1 or event.msg:byte(1) ~= 0x52
  42. or mem.winner or mem.stat[idx]
  43. then
  44. return -- not for us, or not rightclick, or game end, or cell occupied
  45. end
  46. if not mem.player[mem.turn] then
  47. mem.player[mem.turn] = event.msg:sub(3)
  48. elseif event.msg:sub(3) ~= mem.player[mem.turn] then
  49. return -- wrong player
  50. end
  51. -- give the player 30 seconds to think the move before allowing reset
  52. mem.rst_ok = false
  53. mem.stat[idx] = mem.turn
  54. digiline_send(tostring(idx), mem.turn == 1 and "on#f44" or "on#0f0")
  55. local winner_line = won(mem.turn)
  56. if winner_line then
  57. digiline_send("display", "Winner: " .. mem.player[mem.turn])
  58. mem.winner = mem.turn
  59. interrupt(999, "enable_reset")
  60. mem.flash_counter = num_flashes
  61. interrupt(0.5, "flash")
  62. for i = 1, 9 do
  63. if winner_line:byte(1) - 48 ~= i
  64. and winner_line:byte(2) - 48 ~= i
  65. and winner_line:byte(3) - 48 ~= i
  66. and mem.stat[i]
  67. then
  68. digiline_send(tostring(i), mem.stat[i] == 1 and "off#f44" or "off#0f0")
  69. end
  70. end
  71. elseif draw() then
  72. digiline_send("display", "It's a draw!")
  73. mem.winner = 0
  74. interrupt(0, "enable_reset")
  75. else
  76. mem.turn = 3 - mem.turn
  77. if not mem.player[mem.turn] then
  78. digiline_send("display", "Waiting for second player")
  79. else
  80. digiline_send("display", mem.player[mem.turn] .. " to play")
  81. end
  82. interrupt(30, "enable_reset")
  83. end
  84. elseif event.type == "on" then
  85. -- must be reset signal
  86. if mem.rst_ok then
  87. reset()
  88. end
  89. elseif event.type == "interrupt" then
  90. if event.iid == "enable_reset" then
  91. -- timer expired - the game can be reset
  92. mem.rst_ok = true
  93. elseif event.iid == "flash" then
  94. mem.flash_counter = mem.flash_counter - 1
  95. if mem.flash_counter == 0 then
  96. mem.flash_counter = nil
  97. interrupt(0, "enable_reset")
  98. return
  99. end
  100. interrupt(0.5, "flash")
  101. local turn_on, turn_off = "on#f44", "off#f44"
  102. if mem.winner == 2 then
  103. turn_on, turn_off = "on#0f0", "off#0f0"
  104. end
  105. local turn = mem.flash_counter % 2 == 1 and turn_on or turn_off
  106. local winner_line = won(mem.turn)
  107. for i = 1, 3 do
  108. digiline_send(tostring(winner_line:byte(i) - 48), turn)
  109. end
  110. end
  111. end