SciQuest_csp

MCTS fork, Othello

Apr 1st, 2012
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.67 KB | None | 0 0
  1. Othello = class()
  2. --unfinished, typed in scite, do not use, etc
  3.  
  4. player = 0
  5. empty = 0.5
  6. ai = 1
  7.  
  8. up = vec2(0,1)
  9. down = -up
  10. right = vec2(1,0)
  11. left = -right
  12. directions = { right, right+up, up, up+left, left, left+down, down, down+right }
  13.  
  14. zero = vec2(0,0)
  15.  
  16. function Othello:init(x,y)
  17.     self.turn = player
  18.     self.gameOver = false
  19.     self.winner = empty
  20.     self.size = vec2(x,y)
  21.  
  22.     self.pieces = {}
  23.     self.pieces = make2dTable(self.pieces, self.size, empty)
  24.     mid = vec2(math.floor(self.size.x /2), math.floor(self.size.y /2))
  25.     self.pieces[mid.x][mid.y] = self.turn
  26.     self.pieces[mid.x+1][mid.y+1] = self.turn
  27.     self.pieces[mid.x+1][mid.y] = (self.turn+1)%2
  28.     self.pieces[mid.x][mid.y+1] = (self.turn+1)%2
  29.  
  30.     
  31.     self.moves = { {}, {} } 
  32.     self.potential = vec2(0,0)
  33.     self.last = nil
  34.     
  35.     self:updateAvailableMoves(ai)
  36.     self:updateAvailableMoves(player)
  37. end
  38.  
  39. function Othello:copy(orig)
  40.     self.turn = orig.turn
  41.     self.gameOver = orig.gameOver
  42.     self.winner = orig.winner
  43.     self.size = orig.size
  44.     
  45.     self.pieces = {}
  46.     for i,c in pairs(orig.pieces) do
  47.         local temp = {}
  48.         for k,v in pairs(c) do
  49.             table.insert(temp, k)
  50.         end
  51.         table.insert(self.pieces, temp)
  52.     end
  53.     
  54.     self:updateAvailableMoves(ai)
  55.     self:updateAvailableMoves(player)
  56. end
  57.  
  58. function Othello:draw()
  59.     bgColor = white
  60.     if self.turn == player then 
  61.         bgColor = color(red.r/2, red.g/2, red.b/2)
  62.     else
  63.         bgColor = color(blue.r/2, blue.g/2, blue.b/2)
  64.     end
  65.     background(bgColor)
  66.     
  67.     dx = WIDTH / self.size.x
  68.     dy = HEIGHT / self.size.y
  69.     ellipseMode(CORNERS)
  70.     for i,c in pairs(self.pieces) do
  71.         for j,r in pairs(self.pieces[i]) do
  72.             pushMatrix()
  73.             translate((i-1)*dx, (j-1)*dy)
  74.             if self.pieces[i][j] == player then fill(red)
  75.             elseif self.pieces[i][j] == ai then fill(blue)
  76.             else fill(gray) end
  77.             ellipse(0,0, dx,dy)
  78.             popMatrix()
  79.         end
  80.     end
  81. end
  82.  
  83. function Othello:resetChain()
  84.     self.potential.x = 0
  85.     self.potential.y = 0
  86.     self.last = nil
  87. end
  88.  
  89. function Othello:countChain(i,j)
  90.     if i < 1 or self.size.x < i then return 
  91.     elseif j < 1 or self.size.y < j then return end
  92.  
  93.     if self.potential.x == 0 then
  94.         if self.pieces[i][j] == empty then
  95.             self:resetChain()
  96.         end
  97.     else
  98.         if last == nil then
  99.             if self.pieces[i][j] == empty then
  100.                 self.potential = vec2(i,j)
  101.                 self.last = nil
  102.             else
  103.                 self.last = self.pieces[i][j]
  104.             end
  105.         elseif self.last == self.pieces[i][j] then
  106.             -- do nothing
  107.         elseif self.pieces[i][j] == empty then 
  108.             self:resetChain()
  109.         else
  110. table.insert(self.moves[1+((last+1)%2)], vec2(potential.x, potential.y))
  111.             self:resetChain()
  112.         end
  113.     end
  114. end
  115.  
  116. function make2dTable(myTable, size, default)
  117.     for i = 1, size.x do
  118.         local temp = {}
  119.         for j = 1, size.y do
  120.             table.insert(temp, j, default)
  121.         end
  122.         table.insert(myTable, i, temp)
  123.     end
  124.     return myTable
  125. end
  126.  
  127. function Othello:nextTurn()
  128.     self.turn = (self.turn+1)%2
  129.     if #self.moves[self.turn+1] == 0 then
  130.         self.turn = (self.turn+1)%2
  131.     end
  132. end
  133.  
  134. function Othello:move(x,y)
  135.    -- print("in move")
  136.     --print(x.." "..y)
  137.     for i,move in pairs(self.moves[self.turn+1]) do
  138.         if self.moves[self.turn+1][i].x == x then
  139.             if self.moves[self.turn+1][i].y == y then
  140.             -- if statement broken up for space constraints
  141.                 self.pieces[x][y] = self.turn
  142.                 --print(self.turn)
  143.                 self:flipStones(x,y,self.turn,(self.turn+1)%2)
  144.             
  145.                 self.turn = (self.turn+1)%2
  146.                 self:updateAvailableMoves(self.turn)
  147.                 return
  148.             end
  149.         end
  150.     end
  151.     print("error: move ("..x..","..y..") not valid?")
  152.    -- self:printValid()
  153. end
  154.  
  155. function Othello:printValid()
  156.     self:updateAvailableMoves(player)
  157.     self:updateAvailableMoves(ai)
  158.     print("turn is "..self.turn)
  159.     for n = 0,1 do
  160.         print("valid moves for player "..n.." are:")
  161.         for k,v in pairs(self.moves[n+1]) do
  162.             print(v)
  163.         end
  164.     end
  165. end
  166.  
  167. function Othello:touched(t)
  168.     pos = vec2(0,0)
  169.     pos.x = math.ceil(self.size.x * t.x/WIDTH)
  170.     pos.y = math.ceil(self.size.y * t.y/HEIGHT)
  171.     if self.pieces[pos.x][pos.y] == empty then
  172.         self:move(pos.x,pos.y)     
  173.     else
  174.         print("error: location already occupied.")
  175.     end
  176. end
  177.  
  178. function Othello:allStones(side)
  179.     local found = {}
  180.     for i,c in pairs(self.pieces) do
  181.         for j,p in pairs(self.pieces[i]) do
  182.             if p == side then table.insert(found,vec2(i,j)) end
  183.         end
  184.     end
  185.     return found
  186. end
  187.  
  188. function Othello:updateAvailableMoves(side)
  189.     --print("updating")
  190.     local otherSide = (side+1)%2
  191.     self.moves[side+1] = {}
  192.     local myStones = self:allStones(side)
  193.     for k,stone in pairs(myStones) do
  194.         --print("im checking a stone")
  195.         for dirNum,direction in pairs(directions) do 
  196.             --print("checking direction...")
  197.             --print(direction)
  198.             self.last = nil
  199.             found = nil
  200.             i = stone.x
  201.             j = stone.
  202.             while (found == nil) do
  203.                 i = i + direction.x
  204.                 j = j + direction.y
  205.                 found = self:countChain2(i, j, side, otherSide)
  206.             end
  207.             if found then 
  208.                 --print("got one")
  209.                 table.insert(self.moves[side+1], vec2(i,j))
  210.             end
  211.         end
  212.     end
  213. end
  214.  
  215. -- return false := chain definitely not found
  216. -- return nil := chain ongoing
  217. -- return true := chain found
  218. function Othello:countChain2(i,j, side, otherSide)
  219.     if not self:validCoords(i,j) then return false end
  220.     if self.last == nil then 
  221.         if self.pieces[i][j] == otherSide then 
  222.             self.last = otherSide
  223.             return nil
  224.         else 
  225.             return false
  226.         end
  227.     else
  228.         if self.pieces[i][j] == empty then return true end
  229.         if self.pieces[i][j] == otherSide then return nil end
  230.         return false
  231.     end
  232. end
  233.  
  234. function Othello:flipStones(x,y,side,otherSide)
  235.     --print("in flip")
  236.     --print(side)
  237.     for dirNum,direction in pairs(directions) do
  238.         local stonesToFlip = {}
  239.         local keepOn = true
  240.         local i = x + direction.x
  241.         local j = y + direction.y
  242.         local doFlip = false
  243.         while self:validCoords(i,j) and keepOn do
  244.             if self.pieces[i][j] == side then 
  245.                 keepOn = false
  246.                 doFlip = true
  247.             end
  248.             if self.pieces[i][j] == empty then 
  249.                 keepOn = false
  250.             end
  251.             
  252.             if keepOn then 
  253.                 table.insert(stonesToFlip, vec2(i,j))
  254.                 i = i + direction.x
  255.                 j = j + direction.y
  256.             end
  257.         end
  258.         if doFlip then
  259.             for k,v in pairs(stonesToFlip) do
  260.                 --print(v)
  261.                 --print(i.." ij "..j)
  262.                 self.pieces[v.x][v.y] = side
  263.             end
  264.        --     stonesToFlip = {}
  265.         end
  266.     end
  267. end
  268.  
  269. function Othello:validCoords(i,j)
  270.     if (0<i and i<=self.size.x and 0<j and j<=self.size.y) then
  271.         return true
  272.     else 
  273.         return false
  274.     end
  275. end
  276.  
  277. function Othello:randomMove()
  278.     local myMove = math.random(#self.moves[self.turn+1])
  279.    -- print("in randommove")
  280.   --  print(myMove)
  281.    -- print(#self.moves[self.turn+1])
  282.   --  print(self.moves[self.turn+1][myMove].x .." ".. self.moves[self.turn+1][myMove].y)
  283.     self:move(self.moves[self.turn+1][myMove].x, self.moves[self.turn+1][myMove].y)
  284. end
  285.  
  286. function Othello:positionStrength()
  287.     local score = {0,0}
  288.     for i,c in pairs(self.pieces) do
  289.         for j,p in pairs(c) do
  290.             if p == player then
  291.                 score[player+1] = score[player+1] + 1
  292.             elseif p == ai then 
  293.                 score[ai+1] = score[ai+1] + 1
  294.             end
  295.         end
  296.     end
  297.     return score[ai+1] / (score[player+1] + score[ai+1])
  298. end
  299.  
  300. function Othello:gameOver()
  301.     if self.gameOver then return true end
  302.     if (#self.moves[self.turn+1] == 0) then
  303.         self.gameOver = true
  304.         local str = self:positionStrength()
  305.         if str < 0.5 then 
  306.             self.winner = player 
  307.         elseif 0.5 < str then 
  308.             self.winner = ai
  309.         else 
  310.             self.winner = tie 
  311.         end
  312.     end
  313.     return self.gameOver
  314. end
  315.  
  316. --[[
  317. -------
  318. R------
  319. B--RB--
  320. R--BR--
  321. BRRRR-B
  322. BBBRB-R
  323. --]]
Advertisement
Add Comment
Please, Sign In to add comment