Source: site.view [edit]
Function name: makeTicTacToeMove
Arguments: board,turns,playerIs,playerMove,gameLevel
Description: Make a tic tac toe move. If playerMove specified, move that and then do a computer move. If playerMove = "?", just do computer move. If playerMove = nil, reset board.
Page type: webl
Render function:  
Module: global

Page source:

var computerIs;
if (playerIs == "O") then
   computerIs = "X"
else
   computerIs = "O"
end;
var mode = "Playing";
var computerShouldMove = true;
var grid;


var makeMove = fun (grid, move, piece)
  var r = move[0];
  var c = move[1];

  var newRow = grid[r];
  if (c == 0) then
     newRow = [ piece, grid[r][1], grid[r][2] ]
  elsif (c == 1) then
     newRow = [ grid[r][0], piece, grid[r][2] ]
  else
     newRow = [ grid[r][0], grid[r][1], piece ]
  end;

  if (r == 0) then
     return [ newRow, grid[1], grid[2] ]
  elsif (r == 1) then
     return [ grid[0], newRow, grid[2] ]
  else
     return [ grid[0], grid[1], newRow ]
  end;    
  return grid
end;
  
  

var checkWinner = fun (grid)

   // Horizontal
   if (grid[0][0] != "?") and (grid[0][0] == grid[0][1]) and (grid[0][1] == grid[0][2]) then
      return grid[0][0]
   elsif (grid[1][0] != "?") and (grid[1][0] == grid[1][1]) and (grid[1][1] == grid[1][2]) then
      return grid[1][0]
   elsif (grid[2][0] != "?") and (grid[2][0] == grid[2][1]) and (grid[2][1] == grid[2][2]) then
      return grid[2][0]
      
   // Vertical   
   elsif (grid[0][0] != "?") and (grid[0][0] == grid[1][0]) and (grid[1][0] == grid[2][0]) then
      return grid[0][0]
   elsif (grid[0][1] != "?") and (grid[0][1] == grid[1][1]) and (grid[1][1] == grid[2][1]) then
      return grid[0][1]
   elsif (grid[0][2] != "?") and (grid[0][2] == grid[1][2]) and (grid[1][2] == grid[2][2]) then
      return grid[0][2]
      
   // Diagonal
   elsif (grid[0][0] != "?") and (grid[0][0] == grid[1][1]) and (grid[1][1] == grid[2][2]) then
      return grid[0][0]
   elsif (grid[2][0] != "?") and (grid[2][0] == grid[1][1]) and (grid[1][1] == grid[0][2]) then
      return grid[2][0]
   end; 
   return "?"
end;
  
  
var movesLeft = fun (grid)

   var res = [];
   var i = 0;
   var j = 0;
   while (i < 3) do
     j = 0;
     while (j < 3) do
        if grid[i][j] == "?" then
           res = res + [ [i, j] ]
        end;
        j = j + 1
     end;
     i = i + 1;
   end;
   return res
end;
  

var pieceAt = fun (row, col, piecePositions)
   var pos = ToChar(65 + row) + ToString(col+1);
   every pp in piecePositions do
     if (pp.position == pos) then
        return pp.piece
     end
   end;
   return "?"
end;
  
var makePiecePositions = fun (grid)
  var piecePositions = [];
  var i = 0;
  while (i < 3) do
    var j = 0;
    while (j < 3) do
      if grid[i][j] != "?" then
         piecePositions = piecePositions + [ [. position = ToChar(65 + i) + ToString(j+1), piece = grid[i][j] .] ];
      end;
      j = j + 1
    end;
    i = i + 1
  end;
  return piecePositions
end;
  
var makeGrid = fun (piecePositions)
  var grid = [];
  var i = 0;
  
  while (i < 3) do
    var j = 0;
    var row = [];
    while (j < 3) do
      row = row + [pieceAt(i, j, piecePositions)];
      j = j + 1
    end;
    grid = grid + [ row ];
    i = i + 1
  end;
  return grid
end;   
  
var textRender = fun (grid)
   var str =   "   1 2 3\n";
   str = str + "A  " + grid[0][0] + " " + grid[0][1] + " " + grid[0][2] + "\n";
   str = str + "B  " + grid[1][0] + " " + grid[1][1] + " " + grid[1][2] + "\n";
   str = str + "C  " + grid[2][0] + " " + grid[2][1] + " " + grid[2][2] + "\n";
   return str
end;
  
var existsWinningMove = fun (ml)

   every move in ml do
     var testGrid = grid;
     testGrid = makeMove(grid, move, computerIs);
     if checkWinner(testGrid) != "?" then
        return move
     end;
     testGrid = grid;
     testGrid = makeMove(grid, move, playerIs);
     if checkWinner(testGrid) != "?" then
        return move
     end
   end;
   return nil
end;
  
var chooseComputerMove = fun (ml, gameLevel)

   var move = ml[Wub_RandomInt(Size(ml))];
   var gl = ToInt(gameLevel);
   if gl > 3 then
      var winningMove = existsWinningMove(ml);
      if winningMove != nil then
         move = winningMove
      elsif Size(ml) == 9 then
         move = [1,1]
      elsif Size(ml) == 8 then
         if grid[1][1] != "?" then
            var r = Wub_RandomInt(4);
            move = Select([[0,0],[0,2],[2,0],[2,2]], r, r+1)[0]
         end
      end
   end;
   return move
end;
  

var boardPiecePositions = (board.boardPiecePositions ? []);
if (turns == nil) then
   turns = [];
end;

grid = makeGrid(boardPiecePositions);

var ml = movesLeft(grid);

if playerMove != nil and Size(playerMove)==2 then
   var move = [ ToInt(playerMove[0])-65, ToInt(Select(playerMove,1,2))-1 ];
   var position = playerMove;
   if (move member ml) then                           
      grid = makeMove(grid, move, playerIs);
      turns = turns + [ [. toPiecePosition = [. position = position, piece = playerIs .] .] ];                           
      ml = movesLeft(grid);
   else
      board.message := "There's already a piece at that position.";
      computerShouldMove = false                           
   end                            
end;
  
var winner = checkWinner(grid);

if winner != "?" then
   board.message := "You win!";
   mode = "Done"
elsif playerMove == nil then // reset the board
   board.message := "OK, let's get started.  It's your turn.";
elsif ml == [] then
   board.message := "No moves left -- Draw!";
   mode = "Done"
elsif computerShouldMove then
   var move = chooseComputerMove(ml, gameLevel); 
   var position = ToChar(65+move[0]) + ToString(move[1]+1);
   grid = makeMove(grid, move, computerIs);
   winner = checkWinner(grid);
   turns = turns + [ [. toPiecePosition = [. position = position, piece = computerIs .] .] ];
   ml = movesLeft(grid);                          
   if winner != "?" then
      board.message := "I beat you this time...";
      mode = "Done"
   elsif ml == [] then
      board.message := "No moves left -- Draw!";
      mode = "Done"
   else 
      board.textRender := textRender(grid);
      board.boardPiecePositions := makePiecePositions(grid);
      board.message := "I moved: " + position;
   end;
end;
  
board.textRender := textRender(grid);
board.boardPiecePositions := makePiecePositions(grid);
[. turns = turns, board = board, playerIs=playerIs, status = mode, gameLevel = gameLevel .];