Array.prototype.shuffle=function()
{
i=this.length;
if (i<2) return false;
do
{
zi=Math.floor(Math.random()*i);
t=this[zi];
this[zi]=this[--i];
this[i]=t;
}
while(i) return true;
}

help=['','Reversi, or Othello, is a strategy game. The dark pieces are yours, and the light pieces are the computer\'s. Making the first move, you must place a dark piece on the board, in such a position that there exists at least one straight (horizontal, vertical, or diagonal) line between your new piece and another dark piece, and with one or more contiguous light pieces between them. After placing your piece, all light pieces lying on a straight line between the new piece and any anchoring dark piece will turn over and are now dark. The object of the game is to have a majority of the pieces on the board, by turning over as many of the computer\'s pieces as possible.'];

function preload()
{
imgnr=0;
image=['bg.jpg','black.gif','white.gif','blank.gif','new.gif','pass.gif','undo.gif','help.gif','about.gif','mail.gif'];
picture=new Array(image.length);
for (i=0;i<image.length;i++)
{
picture[i]=new Image();
picture[i].onload=loadcheck;
picture[i].src=image[i];
}
}

function loadcheck()
{
imgnr++;
if (imgnr==image.length) setup();
}

function setup()
{
black="<img src=\"black.gif\" id=\"button\">";
white="<img src=\"white.gif\" id=\"button\">";
position=new Array();
pos=new Array();
moves=new Array();
step=0;
move=0;
nomove=0;
about=0;
for (i=1;i<9;i++) for (j=1;j<9;j++) position.push(i*10+j);
for (i=0;i<64;i++) pos[position[i]]="<img src=\"blank.gif\" id=\"button\" onclick=\"check("+[position[i]]+")\">";
pos[44]=white;
pos[45]=black;
pos[54]=black;
pos[55]=white;
message="Game ready.";
show();
}

function show()
{
score();
test();
about=0;
menu=black+white+"&nbsp;<img src=\"new.gif\" onclick=\"setup()\" id=\"button\" alt=\"Set up new game\" title=\"Set up new game\"><img src=\"pass.gif\" onclick=\"pass()\" id=\"button\" alt=\"Skip your move\" title=\"Skip your move\"><img src=\"undo.gif\" onclick=\"undo()\" id=\"button\" alt=\"Undo last move\" title=\"Undo last move\"><img src=\"help.gif\" onclick=\"showhelp()\" id=\"button\" alt=\"Toggle help on/off\" title=\"Toggle help on/off\"><img src=\"about.gif\" onclick=\"aboutus()\" id=\"button\" alt=\"About this game\" title=\"About this game\"><a href=\"mailto:thomas.weibel@bluewin.ch\" title=\"E-mail to the author\"><img src=\"mail.gif\" id=\"button\" border=\"0\" alt=\"E-mail to the author\"><\/a>";
display="<p id=\"title\">Reversi<\/p><table><tr><td>"+pos[11]+"<\/td><td>"+pos[12]+"<\/td><td>"+pos[13]+"<\/td><td>"+pos[14]+"<\/td><td>"+pos[15]+"<\/td><td>"+pos[16]+"<\/td><td>"+pos[17]+"<\/td><td>"+pos[18]+"<\/td><td id=\"space\" rowspan=\"8\"><\/td><td id=\"help\"rowspan=\"8\"><span>"+help[0]+"<\/span><\/td><\/tr><tr><td>"+pos[21]+"<\/td><td>"+pos[22]+"<\/td><td>"+pos[23]+"<\/td><td>"+pos[24]+"<\/td><td>"+pos[25]+"<\/td><td>"+pos[26]+"<\/td><td>"+pos[27]+"<\/td><td>"+pos[28]+"<\/td><\/tr><tr><td>"+pos[31]+"<\/td><td>"+pos[32]+"<\/td><td>"+pos[33]+"<\/td><td>"+pos[34]+"<\/td><td>"+pos[35]+"<\/td><td>"+pos[36]+"<\/td><td>"+pos[37]+"<\/td><td>"+pos[38]+"<\/td><\/tr><tr><td>"+pos[41]+"<\/td><td>"+pos[42]+"<\/td><td>"+pos[43]+"<\/td><td>"+pos[44]+"<\/td><td>"+pos[45]+"<\/td><td>"+pos[46]+"<\/td><td>"+pos[47]+"<\/td><td>"+pos[48]+"<\/td><\/tr><tr><td>"+pos[51]+"<\/td><td>"+pos[52]+"<\/td><td>"+pos[53]+"<\/td><td>"+pos[54]+"<\/td><td>"+pos[55]+"<\/td><td>"+pos[56]+"<\/td><td>"+pos[57]+"<\/td><td>"+pos[58]+"<\/td><\/tr><tr><td>"+pos[61]+"<\/td><td>"+pos[62]+"<\/td><td>"+pos[63]+"<\/td><td>"+pos[64]+"<\/td><td>"+pos[65]+"<\/td><td>"+pos[66]+"<\/td><td>"+pos[67]+"<\/td><td>"+pos[68]+"<\/td><\/tr><tr><td>"+pos[71]+"<\/td><td>"+pos[72]+"<\/td><td>"+pos[73]+"<\/td><td>"+pos[74]+"<\/td><td>"+pos[75]+"<\/td><td>"+pos[76]+"<\/td><td>"+pos[77]+"<\/td><td>"+pos[78]+"<\/td><\/tr><tr><td>"+pos[81]+"<\/td><td>"+pos[82]+"<\/td><td>"+pos[83]+"<\/td><td>"+pos[84]+"<\/td><td>"+pos[85]+"<\/td><td>"+pos[86]+"<\/td><td>"+pos[87]+"<\/td><td>"+pos[88]+"<\/td><\/tr><\/table><p id=\"copyright\">&copy; 2010 twb<\/p><p>"+message+"<\/p><p id=\"menu\">"+menu+"<\/p><p id=\"numblack\">"+score1+"<\/p><p id=\"numwhite\">"+score2+"<\/p>";
document.getElementById('screen').innerHTML=display;
}

function check(a)
{
if (message!="Thinking...")
{
flag=0;
moves[step]=new Array();
dir=[11,10,9,1,-1,-9,-10,-11];
dir.shuffle();
message="Invalid move!";
for (i=0;i<8;i++)
{
if (a==0) {calc(); break;}
else if (pos[a-dir[i]]==white)
{
if (pos[a-dir[i]*2]==black)
{
for (j=0;j<2;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
else if (pos[a-dir[i]*2]==white&&pos[a-dir[i]*3]==black)
{
for (j=0;j<3;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
else if (pos[a-dir[i]*2]==white&&pos[a-dir[i]*3]==white&&pos[a-dir[i]*4]==black)
{
for (j=0;j<4;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
else if (pos[a-dir[i]*2]==white&&pos[a-dir[i]*3]==white&&pos[a-dir[i]*4]==white&&pos[a-dir[i]*5]==black)
{
for (j=0;j<5;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
else if (pos[a-dir[i]*2]==white&&pos[a-dir[i]*3]==white&&pos[a-dir[i]*4]==white&&pos[a-dir[i]*5]==white&&pos[a-dir[i]*6]==black)
{
for (j=0;j<6;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
else if (pos[a-dir[i]*2]==white&&pos[a-dir[i]*3]==white&&pos[a-dir[i]*4]==white&&pos[a-dir[i]*5]==white&&pos[a-dir[i]*6]==white&&pos[a-dir[i]*7]==black)
{
for (j=0;j<7;j++) {moves[step].push(a-dir[i]*j,pos[a-dir[i]*j]); pos[a-dir[i]*j]=black;}
if (flag==0) calc();
}
}
}
show();
}
}

function score()
{
blanks=new Array();
for (i=0;i<64;i++) if (pos[position[i]]!=black&&pos[position[i]]!=white) blanks.push(position[i]);
blanks.shuffle();
scorewhite=0;
scoreblack=0;
for (i=0;i<64;i++)
{
if (pos[position[i]]==black) scoreblack++;
if (pos[position[i]]==white) scorewhite++;
if (scoreblack<10) score1="&nbsp;"+scoreblack; else score1=scoreblack;
if (scorewhite<10) score2="&nbsp;"+scorewhite; else score2=scorewhite;
}
}

function calc()
{
flag=1;
step++;
moves[step]=new Array();
message="Thinking...";
setTimeout('calculate()',2000);
}

function calculate()
{
move=0;

//Prefer corners (8-3)

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==black&&pos[blanks[0]-dir[i]*6]==black&&pos[blanks[0]-dir[i]*7]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(8);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==black&&pos[blanks[0]-dir[i]*6]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(7);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(6);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(5);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(4);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==white&&(blanks[0]==11||blanks[0]==18||blanks[0]==81||blanks[0]==88)&&(move==0||move==blanks[0]))
turn(3);
cycle();
}

//Prefer numerical advantage (8-7)

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==black&&pos[blanks[0]-dir[i]*6]==black&&pos[blanks[0]-dir[i]*7]==white&&(move==0||move==blanks[0]))
turn(8);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==black&&pos[blanks[0]-dir[i]*6]==white&&(move==0||move==blanks[0]))
turn(7);
cycle();
}

//Avoid ceding corners (6-3)

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==white&&blanks[0]!=12&&blanks[0]!=17&&blanks[0]!=21&&blanks[0]!=22&&blanks[0]!=27&&blanks[0]!=28&&blanks[0]!=71&&blanks[0]!=72&&blanks[0]!=77&&blanks[0]!=78&&blanks[0]!=82&&blanks[0]!=87&&(move==0||move==blanks[0]))
turn(6);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==white&&blanks[0]!=12&&blanks[0]!=17&&blanks[0]!=21&&blanks[0]!=22&&blanks[0]!=27&&blanks[0]!=28&&blanks[0]!=71&&blanks[0]!=72&&blanks[0]!=77&&blanks[0]!=78&&blanks[0]!=82&&blanks[0]!=87&&(move==0||move==blanks[0]))
turn(5);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==white&&blanks[0]!=12&&blanks[0]!=17&&blanks[0]!=21&&blanks[0]!=22&&blanks[0]!=27&&blanks[0]!=28&&blanks[0]!=71&&blanks[0]!=72&&blanks[0]!=77&&blanks[0]!=78&&blanks[0]!=82&&blanks[0]!=87&&(move==0||move==blanks[0]))
turn(4);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==white&&blanks[0]!=12&&blanks[0]!=17&&blanks[0]!=21&&blanks[0]!=22&&blanks[0]!=27&&blanks[0]!=28&&blanks[0]!=71&&blanks[0]!=72&&blanks[0]!=77&&blanks[0]!=78&&blanks[0]!=82&&blanks[0]!=87&&(move==0||move==blanks[0]))
turn(3);
cycle();
}

//Prefer numerical advantage (6-3)

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==black&&pos[blanks[0]-dir[i]*5]==white&&(move==0||move==blanks[0]))
turn(6);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==black&&pos[blanks[0]-dir[i]*4]==white&&(move==0||move==blanks[0]))
turn(5);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==black&&pos[blanks[0]-dir[i]*3]==white&&(move==0||move==blanks[0]))
turn(4);
cycle();
}

for (k=0;k<blanks.length;k++)
{
for (i=0;i<8;i++)
if (pos[blanks[0]-dir[i]]==black&&pos[blanks[0]-dir[i]*2]==white&&(move==0||move==blanks[0]))
turn(3);
cycle();
}

step++;
moves[step]=new Array();
if (move==0&&nomove==0) message="Can't make a move. Your turn.";
else if (nomove==1&&scoreblack>scorewhite) message="No more moves: You win!";
else if (nomove==1&&scorewhite>scoreblack) message="No more moves: You lose!";
else if (nomove==1&&scoreblack==scorewhite) message="No more moves: Deuce!";
else message="Your turn.";
show();
}

function cycle()
{
blanks.push(blanks[0]);
blanks.shift();
}

function turn(c)
{
for (j=0;j<c;j++) 
{
moves[step].push(blanks[0]-dir[i]*j,pos[blanks[0]-dir[i]*j]);
pos[blanks[0]-dir[i]*j]=white;
move=blanks[0];
nomove=0;
}
}

function pass()
{
nomove=1;
if (step!=0&&move==0&&scoreblack>scorewhite) message="No more moves: You win!";
else if (step!=0&&move==0&&scorewhite>scoreblack) message="No more moves: You lose!";
else if (step!=0&&move==0&&scoreblack==scorewhite) message="No more moves: Deuce!";
else if (blanks.length!=0&&scoreblack!=0&&scorewhite!=0) check(0);
show();
}

function test()
{
if (about==1) message="Reversi 1.1 by www.thomasweibel.ch";
else if ((blanks.length==0&&scoreblack>scorewhite)||scorewhite==0) message="Game over: You win!";
else if ((blanks.length==0&&scorewhite>scoreblack)||scoreblack==0) message="Game over: You lose!";
else if (blanks.length==0&&score2==score1) message="Game over: Deuce!"
}

function undo()
{
undo2();
setTimeout('undo2()',500);
}

function undo2()
{
if (moves.length-1>0)
{
for (i=0;i<moves[step-1].length;i++)
{
pos[moves[step-1][moves[step-1].length-2*(i+1)]]=moves[step-1][moves[step-1].length-(2*(i+1)-1)];
}
step--;
moves.length--;
message="Move undone.";
}
else message="Undo not possible!";
show();
}

function showhelp()
{
help.reverse();
show();
}

function aboutus()
{
about=1;
show();
}
