Nqueens.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. love.window.setMode(150, 40) -- Input box
  2. love.keyboard.setKeyRepeat(true)
  3. local bit = require 'bit'
  4. -- Validation function for numeric input
  5. local function numeric(t)
  6. return type(t) == "string" and t >= "0" and t <= "9"
  7. end
  8. -- Validation function for UTF-8 text input
  9. local function text(t)
  10. local L, U, b2, b3, b4 = #t, t:byte(1, 4)
  11. if L <= 1 then
  12. return U and U < 128
  13. end
  14. -- Check correctness of bit encoding and length
  15. if b2 < 128 or b2 > 191
  16. or L ~= 2 and (b3 < 128 or b3 > 191)
  17. or L == 2 and (U < 0xC2 or U > 0xDF)
  18. or L == 3 and (U < 0xE0 or U > 0xEF)
  19. or L == 4 and (U < 0xF0 or U > 0xF4 or b4 < 128 or b4 > 191)
  20. then
  21. return false
  22. end
  23. -- Basic encoding/length validation test passed - decode the bits
  24. U = bit.lshift(U - 192, 6) + (b2 - 128)
  25. if L >= 3 then
  26. U = bit.lshift(U - 0x800, 6) + (b3 - 128)
  27. if L >= 4 then
  28. U = bit.lshift(U - 0x10000, 6) + (b4 - 128)
  29. end
  30. end
  31. if L == 3 and U < 0x800 or L == 4 and U < 0x10000 -- overlong
  32. or U > 0x10FFFD -- out of range
  33. or U >= 0xD800 and U <= 0xDFFF -- surrogate
  34. or U >= 0xFDD0 and U <= 0xFDEF -- invalid range
  35. then
  36. return false
  37. end
  38. local low = bit.band(U, 0xFFFF)
  39. return low ~= 0xFFFE and low ~= 0xFFFF
  40. end
  41. -- Input function that allows entering any text:
  42. local function simpleInput(x, y, maxlen, validFn)
  43. local r_save, g_save, b_save, a_save = love.graphics.getColor()
  44. local font = love.graphics.getFont()
  45. local H = font:getHeight()
  46. local W = font:getWidth("M") -- hopefully the thickest letter in the font
  47. local str = ''
  48. repeat
  49. poll()
  50. love.graphics.setColor(love.graphics.getBackgroundColor())
  51. love.graphics.rectangle("fill", x, y, (maxlen + 1) * W, H)
  52. love.graphics.setColor(r_save, g_save, b_save, a_save)
  53. love.graphics.print(str .. "_", x, y)
  54. local ret, k = peek.keypressed()
  55. local t = ""
  56. if peek.textinput() then
  57. ret, t = peek.textinput()
  58. end
  59. if k == "escape" then
  60. quit()
  61. end
  62. if k == "backspace" and str ~= "" then
  63. str = str:sub(1, -2)
  64. elseif validFn(t) then
  65. str = str .. t
  66. end
  67. if #str > maxlen then
  68. str = str:sub(1, maxlen)
  69. end
  70. until k == 'kpenter' or k == 'return'
  71. love.graphics.setColor(r_save, g_save, b_save, a_save)
  72. return str
  73. end
  74. do
  75. local text = "Enter N (4-16): "
  76. love.graphics.print(text, 20, 10)
  77. local w = love.graphics.getFont():getWidth(text)
  78. repeat
  79. N = tonumber(simpleInput(w + 20, 10, 2, numeric))
  80. until N and N >= 4 and N <= 16
  81. end
  82. local size = 40
  83. love.window.setMode((N + 1) * size, (N + 1.5) * size, {vsync = false})
  84. -- Work around problem where a new keypress event is sent to the new window
  85. -- if it was pressed, by ignoring the keypressed events for 1 frame
  86. wait.update() -- wait for this update
  87. wait.update() -- wait for the *next* uppate
  88. local img = love.graphics.newImage('queen-black-40x40.png')
  89. local function clear(x, y)
  90. if (x + y) % 2 == 1 then
  91. love.graphics.setColor(0, 0, 0)
  92. else
  93. love.graphics.setColor(255, 255, 255)
  94. end
  95. love.graphics.rectangle("fill", x*size, y*size, size, size)
  96. love.graphics.setColor(255, 255, 255)
  97. end
  98. -- Set origin to top left of board
  99. love.graphics.translate(size/2, size)
  100. -- Draw border
  101. love.graphics.rectangle("fill", -4, -4, N*size+8, N*size+8)
  102. for y = 0, N-1 do
  103. for x = 0, N-1 do
  104. clear(x, y)
  105. end
  106. end
  107. local board = {}
  108. local nSolutions = 0
  109. local function printSolution()
  110. for i = 1, N do
  111. print(("*"):rep(board[i]) .. "Q" .. ("*"):rep(N - 1 - board[i]))
  112. end
  113. print(("-"):rep(N))
  114. nSolutions = nSolutions + 1
  115. -- Erase background before printing
  116. for i = 1, 3 do
  117. love.graphics.setColor(love.graphics.getBackgroundColor())
  118. love.graphics.rectangle("fill", 10, -30, N*size, 14)
  119. sleep(0.2)
  120. love.graphics.setColor(255, 255, 255)
  121. love.graphics.print("Number of solutions: " .. nSolutions, 10, -30)
  122. sleep(0.2)
  123. end
  124. pause(1.5)
  125. end
  126. love.graphics.print("Number of solutions: 0", 10, -30)
  127. local function tryQueen(row)
  128. for x = 0, N - 1 do
  129. love.graphics.draw(img, x*size, row*size)
  130. pause(0)
  131. local failed = false
  132. for i = 1, row do
  133. if board[i] == x or board[i] - x == row - (i - 1) or x - board[i] == row - (i - 1) then
  134. failed = true
  135. break
  136. end
  137. end
  138. if not failed then
  139. board[row + 1] = x
  140. if row == N - 1 then
  141. printSolution()
  142. else
  143. tryQueen(row + 1)
  144. end
  145. end
  146. clear(x, row)
  147. end
  148. end
  149. tryQueen(0)
  150. love.graphics.setColor(255, 0, 0)
  151. love.graphics.print("No more solutions\nPress a key", 10, 40)
  152. print("No more solutions")
  153. wait.keypressed()
  154. quit()