// (C)2008 Julio Di Egidio
// http://julio.diegidio.name
// mailto:julio@diegidio.name

var jde_3t_boardCellState={e:"E",x:"X",o:"O"};var jde_3t_boardState={moveX:"MVX",moveO:"MVO",winX:"WNX",winO:"WNO",draw:"DRW"};jde_3t_boardState.isMove=function(boardState){return boardState===this.moveX||boardState===this.moveO;};jde_3t_boardState.isWin=function(boardState){return boardState===this.winX||boardState===this.winO;};jde_3t_boardState.isDraw=function(boardState){return boardState===this.draw;};function jde_3t_BoardCoord(row,col){this.row=row;this.col=col;}jde_3t_BoardCoord.prototype.toIdx=function(){return this.col+3*this.row;};jde_3t_BoardCoord.parse=function(boardCoord){if(typeof(boardCoord)==="undefined"||boardCoord===null||isNaN(boardCoord.row=Math.round(boardCoord.row))||isNaN(boardCoord.col=Math.round(boardCoord.col))||boardCoord.row<0||boardCoord.row>2||boardCoord.col<0||boardCoord.col>2){return jde_ge_noValue;}return new jde_3t_BoardCoord(boardCoord.row,boardCoord.col);};jde_3t_BoardCoord.getBuilderName=function(boardCoord){return"new jde_3t_BoardCoord("+(boardCoord.row)+", "+(boardCoord.col)+")";};function jde_3t_BoardWinCoords(winCoords){var getBoardCoord=function(idx){return new jde_3t_BoardCoord(winCoords[idx].row,winCoords[idx].col);};var boardWinCoords=[];for(var i=0;i<winCoords.length;i++){boardWinCoords[i]=getBoardCoord(i);}return boardWinCoords;}function jde_3t_BoardMove(boardState,boardCoord){this.boardState=boardState;this.boardCoord=boardCoord;}function jde_3t_Board(){if(typeof(jde_ge_noValue)==="undefined"){return null;}var _cells=[],_state=jde_ge_noValue,_winCoords=jde_ge_noValue,_moves=[];for(var i=0;i<9;i++){_cells[i]=jde_ge_noValue;}function StateRC(R,C){this.r=R;this.c=C;}function StateBag(state,RCs){this.state=state;this.RCs=RCs;}function getNextStateBag(){var rcToIdx=function(r,c){return c+3*r;};var found;var RCs=[];var winCtrlCells=[];winCtrlCells[0]=_cells[rcToIdx(0,0)];winCtrlCells[1]=_cells[rcToIdx(1,1)];winCtrlCells[2]=_cells[rcToIdx(2,2)];found=false;for(var r=0;1&&r<3;r++){if(winCtrlCells[r]!==jde_3t_boardCellState.e){var cell_r_0=_cells[rcToIdx(r,0)];var cell_r_1=_cells[rcToIdx(r,1)];var cell_r_2=_cells[rcToIdx(r,2)];if(cell_r_0===cell_r_1&&cell_r_1===cell_r_2){RCs[RCs.length]=new StateRC(r,NaN);found=true;}}}for(var c=0;1&&c<3;c++){if(winCtrlCells[c]!==jde_3t_boardCellState.e){var cell_0_c=_cells[rcToIdx(0,c)];var cell_1_c=_cells[rcToIdx(1,c)];var cell_2_c=_cells[rcToIdx(2,c)];if(cell_0_c===cell_1_c&&cell_1_c===cell_2_c){RCs[RCs.length]=new StateRC(NaN,c);found=true;}}}if(1){if(winCtrlCells[1]!==jde_3t_boardCellState.e){var cell_0_0=_cells[rcToIdx(0,0)];var cell_1_1=_cells[rcToIdx(1,1)];var cell_2_2=_cells[rcToIdx(2,2)];if(cell_0_0===cell_1_1&&cell_1_1===cell_2_2){RCs[RCs.length]=new StateRC(1,1);found=true;}var cell_0_2=_cells[rcToIdx(0,2)];var cell_2_0=_cells[rcToIdx(2,0)];if(cell_0_2===cell_1_1&&cell_1_1===cell_2_0){RCs[RCs.length]=new StateRC(NaN,NaN);found=true;}}}if(found){return new StateBag(_state===jde_3t_boardState.moveX?jde_3t_boardState.winX:jde_3t_boardState.winO,RCs);}found=true;for(var r=0;found&&r<3;r++){for(var c=0;found&&c<3;c++){var cell_r_c=_cells[rcToIdx(r,c)];found=cell_r_c!==jde_3t_boardCellState.e;}}if(found){return new StateBag(jde_3t_boardState.draw);}return new StateBag(_state===jde_3t_boardState.moveX?jde_3t_boardState.moveO:jde_3t_boardState.moveX);}function fillWinCoords(RCs){_winCoords=[];for(var idx=0;idx<RCs.length;idx++){var R=RCs[idx].r,C=RCs[idx].c;for(var i=0;i<3;i++){var winCoord;if(isNaN(R)&&isNaN(C)){winCoord=new jde_3t_BoardCoord(i,2-i);}else if(isNaN(R)){winCoord=new jde_3t_BoardCoord(i,C);}else if(isNaN(C)){winCoord=new jde_3t_BoardCoord(R,i);}else{winCoord=new jde_3t_BoardCoord(i,i);}var found=false;for(var j=0;!found&&j<_winCoords.length;j++){found=winCoord.row===_winCoords[j].row&&winCoord.col===_winCoords[j].col;}if(!found){_winCoords[_winCoords.length]=winCoord;}}}}this.reset=function(){for(var i=0;i<9;i++){_cells[i]=jde_3t_boardCellState.e;}_state=jde_3t_boardState.moveX;_winCoords=jde_ge_noValue;_moves.length=0;};this.move=function(boardCoord){if(!jde_3t_boardState.isMove(_state)){return jde_ge_noValue;}boardCoord=jde_3t_BoardCoord.parse(boardCoord);if(boardCoord===jde_ge_noValue){return jde_ge_noValue;}var idx=boardCoord.toIdx();if(_cells[idx]!==jde_3t_boardCellState.e){return jde_ge_noValue;}_moves[_moves.length]=new jde_3t_BoardMove(_state,boardCoord);_cells[idx]=_state===jde_3t_boardState.moveX?jde_3t_boardCellState.x:jde_3t_boardCellState.o;var nextBag=getNextStateBag();_state=nextBag.state;if(jde_3t_boardState.isWin(_state)){fillWinCoords(nextBag.RCs);}return _state;};this.undo=function(){if(_moves.length===0){return jde_ge_noValue;}var boardMove=_moves[_moves.length-1];var idx=boardMove.boardCoord.toIdx();_cells[idx]=jde_3t_boardCellState.e;_state=boardMove.boardState;_winCoords=jde_ge_noValue;_moves.length-=1;return _state;};this.getCells=function(){var boardCells=[];for(var i=0;i<9;i++){boardCells[i]=_cells[i];}return boardCells;};this.getCell=function(boardCoord){boardCoord=jde_3t_BoardCoord.parse(boardCoord);if(boardCoord===jde_ge_noValue){return jde_ge_noValue;}var idx=boardCoord.toIdx();return _cells[idx];};this.getState=function(){return _state;};this.getLastMove=function(){if(_moves.length===0){return jde_ge_noValue;}return _moves[_moves.length-1];};this.getWinCoords=function(){if(_winCoords===jde_ge_noValue){return jde_ge_noValue;}return new jde_3t_BoardWinCoords(_winCoords);};}