Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local curses = require "curses"
- local stdscr = curses.initscr ()
- local O = {false,false,false,false,false,false,false,false,false}
- local X = {false,false,false,false,false,false,false,false,false}
- local win = {{1,2,3},
- {4,5,6},
- {7,8,9},
- {1,4,7},
- {2,5,8},
- {3,6,9},
- {1,5,9},
- {3,5,7}}
- local rnd = math.random
- local max = math.max
- local add = table.insert
- local unpak = table.unpack
- local concat = table.concat
- local finished = false
- local function all(t1, t2)
- return t1[t2[1]] and t1[t2[2]] and t1[t2[3]]
- end
- local function any(t1, t2)
- local t = 0
- t = t + (t1[t2[1]] and 1 or 0)
- t = t + (t1[t2[2]] and 1 or 0)
- t = t + (t1[t2[3]] and 1 or 0)
- return t
- end
- local function randomChoice(args)
- return args[rnd(#args)]
- end
- local function checkWin(P)
- for _, w in pairs(win) do
- if all(P, w) then
- return true
- end
- end
- return false
- end
- local function displayOX()
- local map = {}
- for i = 1, 9, 3 do
- map[i] = O[i] and "[O]" or (X[i] and "[X]" or "[_]")
- map[i+1] = O[i+1] and "[O]" or (X[i+1] and "[X]" or "[_]")
- map[i+2] = O[i+2] and "[O]" or (X[i+2] and "[X]" or "[_]")
- stdscr:mvaddstr (((i-1)/3)+5, 30, map[i]..map[i+1]..map[i+2])
- end
- stdscr:mvaddstr (9, 20, "Choose position [1-9]: ")
- end
- local function reset()
- for i = 1, 9 do
- O[i], X[i] = false, false
- end
- stdscr:mvaddstr(11,32," ")
- end
- local function calSOX(o,x)
- local SO, SX = 0, 0
- local criticalMove = {}
- for _, w in pairs(win) do
- local cO = any(o,w)
- local cX = any(x,w)
- if cX == 0 then
- SO = SO + cO
- if cO == 2 then
- stdscr:mvaddstr(8,27,"critical {".. concat(w,",").."}")
- criticalMove = w
- end
- end
- if cO == 0 then
- SX = SX + cX
- end
- end
- return SO, SX, criticalMove
- end
- local function evalOX(o,x)
- local SO, SX, criticalMove =calSOX(o,x)
- return (1 + SX - SO), criticalMove
- end
- local function ai()
- local validMove = {true,true,true,true,true,true,true,true,true}
- for i = 1, 9 do
- validMove[i] = not (O[i] or X[i]) and validMove[i]
- end
- for _, w in pairs(win) do
- local cX = any(X,w)
- for _, v in pairs(w) do
- if cX == 2 and validMove[v] then
- return v
- end
- end
- end
- local V = {-100,-100,-100,-100,-100,-100,-100,-100,-100}
- for i, v in ipairs(validMove) do
- if v then
- local tempX, criticalMove = {unpak(X)}, {}
- tempX[i] = v
- V[i], criticalMove = evalOX(O,tempX)
- if #criticalMove > 0 then
- for _, c in pairs(criticalMove) do
- if validMove[c] then
- return c
- end
- end
- end
- end
- end
- local maxV = max(unpak(V))
- local imaxV = {}
- for i, v in pairs(V) do
- if v == maxV then
- add(imaxV,i)
- end
- end
- return randomChoice(imaxV)
- end
- local function main ()
- stdscr:clear ()
- stdscr:box (curses.ACS_VLINE, curses.ACS_HLINE)
- while true do
- ::input_here::
- local c = stdscr:getch () --print(c)
- if c > 48 and c < 58 then
- c = tonumber(string.char (c))
- if O[c] or X[c] then
- if not finished then
- stdscr:mvaddstr (9, 20, "Bad move: choose position [1-9]: ")
- end
- goto input_here
- else
- stdscr:mvaddstr (9, 20, " ")
- end
- elseif c == 13 then
- if finished then
- reset()
- finished = false
- displayOX()
- else
- stdscr:mvaddstr (9, 20, "Bad move: choose position [1-9]: ")
- end
- goto input_here
- elseif c == 27 then
- break
- else
- if not finished then
- stdscr:mvaddstr (9, 20, "Bad move: choose position [1-9]: ")
- end
- goto input_here
- end
- stdscr:mvaddstr(8,27," ")
- O[c] = true
- displayOX()
- local msg = " "
- local d = true
- for i = 1, 9 do
- d = (O[i] or X[i]) and d
- end
- if d then
- msg = "Draw"
- finished = true
- elseif checkWin(O) then
- msg = "O win"
- finished = true
- else
- X[ai()] = true
- displayOX()
- if checkWin(X) then
- msg = "X win"
- finished = true
- end
- end
- stdscr:mvaddstr(11,32,msg)
- stdscr:move(9,43)
- end
- curses.endwin ()
- end
- local function err (err)
- curses.endwin ()
- print "Caught an error:"
- print (debug.traceback (err, 2))
- os.exit (2)
- end
- xpcall (main, err)
Add Comment
Please, Sign In to add comment