content: property OMask : missing value
  property XMask : missing value
  property winningNumbers : {7, 56, 73, 84, 146, 273, 292, 448}
  property difficulty : missing value
  
  repeat
     set OMask to 0
     set XMask to 0
  
     if button returned of (display dialog "Who should start?" buttons {"I shoud", "CPU"}) = "CPU" then set OMask to npcGet()
     set difficulty to button returned of (display dialog "Please choose your difficulty" buttons {"Hard", "Normal"})
  
     repeat
         set XMask to XMask + 2 ^ (nGet() - 1)
         if winnerForMask(XMask) or OMask + XMask = 511 then exit repeat
         set OMask to npcGet()
         if winnerForMask(OMask) or OMask + XMask = 511 then exit repeat
     end repeat
  
     if winnerForMask(OMask) then
         set msg to "CPU Wins!"
     else if winnerForMask(XMask) then
         set msg to "You WON!!!"
     else
         set msg to "It's a draw"
     end if
  
     display dialog msg & return & return & drawGrid() & return & return & "Do you want to play again?"
  end repeat
  
  on nGet()
     set theMessage to "It's your turn Player 1, please fill in the number for X" & return & return & drawGrid()
     repeat
         set value to text returned of (display dialog theMessage default answer "")
         if (offset of value in "123456789") is not 0 then
             if not positionIsUsed(value as integer) then exit repeat
         end if
     end repeat
     return value as integer
  end nGet
  
  on npcGet()
     --first get the free positions
     set freeSpots to {}
     repeat with s from 1 to 9
         if not positionIsUsed(s) then set end of freeSpots to 2 ^ (s - 1)
     end repeat
     --second check if 1 move can make the CPU win
     repeat with spot in freeSpots
         if winnerForMask(OMask + spot) then return OMask + spot
     end repeat
  
     if difficulty is "Hard" and OMask is 0 then
         if XMask = 1 or XMask = 4 then return 2
         if XMask = 64 or XMask = 256 then return 128
     end if
     --third check if a user can make make it win (defensive) place it on position
     repeat with spot in freeSpots
         if winnerForMask(XMask + spot) then return OMask + spot
     end repeat
  
     --fourth check if CPU can win in two moves
     repeat with spot1 in freeSpots
         repeat with spot2 in freeSpots
             if winnerForMask(OMask + spot1 + spot2) then return OMask + spot2
         end repeat
     end repeat
     --fifth check if player can win in two moves
     repeat with spot1 in freeSpots
         repeat with spot2 in reverse of freeSpots
             if winnerForMask(XMask + spot1 + spot2) then return OMask + spot1
         end repeat
     end repeat
     --at last pick a random spot
     if XMask + OMask = 0 and difficulty = "Hard" then return 1
  
     return OMask + (some item of freeSpots)
  end npcGet
  
  on winnerForMask(mask)
     repeat with winLine in winningNumbers
         if BWAND(winLine, mask) = contents of winLine then return true
     end repeat
     return false
  end winnerForMask
  
  on drawGrid()
     set grid to ""
     repeat with o from 0 to 8
         if BWAND(OMask, 2 ^ o) = 2 ^ o then
             set grid to grid & "O"
         else if BWAND(XMask, 2 ^ o) = 2 ^ o then
             set grid to grid & "X"
         else
             set grid to grid & o + 1
         end if
         if o is in {2, 5} then set grid to grid & return
     end repeat
     return grid
  end drawGrid
  
  on positionIsUsed(pos)
     return BWAND(OMask + XMask, 2 ^ (pos - 1)) = 2 ^ (pos - 1)
  end positionIsUsed
  
  on BWAND(n1, n2)
     set theResult to 0
     repeat with o from 0 to 8
         if (n1 mod 2) = 1 and (n2 mod 2) = 1 then set theResult to theResult + 2 ^ o
         set {n1, n2} to {n1 div 2, n2 div 2}
     end repeat
     return theResult as integer
  end BWAND
  