var g = "game";
function zeig_cont(w)
{
 if(g != "")
  document.getElementById(g).style.visibility = "hidden";
 document.getElementById(w).style.visibility = "visible";
 g = w;
}

// JavaScript Othello Game
// Copyright (c) 2000, 2001 Kelly Yancey <kbyanc@posi.net>
// All rights reserved.
//
// Redistribution and use in source form, with or without modification, is
// permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer,
//    without modification, immediately at the beginning of the file.
// 2. All advertising materials mentioning features or use of this software
//    must display the following acknowledgement:
//      This product includes software developed by Kelly Yancey
//    and a reference to the URL http://www.posi.net/software/othello/
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// picture numbers
var        EMPTY = 0;                // empty square
var        WHITE = 1;                // white piece
var        BLACK = 2;                // black piece
var        WHITETRANS = 3;                // white transparent cursor piece
var        BLACKTRANS = 4;                // black transparent cursor piece
var        NUMBASE = 5;                // beginning of numeric pictures

// size of the pictures used to represent pieces (all pictures must be the same size)
var        piecewidth = 40;
var        pieceheight = 40;

// size of the board
var        width = 8;
var        height = 8;

// player settings
var        human = BLACK;
var        showcursor = true;        // display cursor showing user where they can go
var        showflips = false;        // display counts showing how many pieces they can flip by putting a piece in a given square

// AI settings
var        weightsquares = 1;        // whether AI prefers squares that yield higher flip counts
var        edgesensitive = 1;        // whether AI is sensitive to the importance of edge squares

// user-supplied expression to evaluate at the end of each round.
var        roundhook = "";

// some internal global variables
var        picture = new Array();
var        board = new Array(width);
var        score = new Array();
var        turn = BLACK;
var        AI_timerID;


var     lastlookup = 0;
function lookup(name) {
// routine to get image number by name
// optimized for the case where we lookup successive images
    for(i = lastlookup; i < document.images.length; i++)
        if(document.images[i].name == name) { lastlookup = i; return(i); }
    for(i = 0; i < lastlookup; i++)
        if(document.images[i].name == name) { lastlookup = i; return(i); }
    return(-1);
}

function piece(imagename) {
// object definition for 'piece' type
    this.imagenum = lookup(imagename);
    this.player = EMPTY;
    // how many pieces each player could flip by taking this square
    this.flips = new Array();
    this.flips[WHITE] = 0;
    this.flips[BLACK] = 0;
    // how valuable this location is to each player
    this.value = new Array();
    this.value[WHITE] = 0;
    this.value[BLACK] = 0;
}

function LoadPieceImage(picnum, pictureURL) {
// routine to associated the given picture with a picture number.
    picture[picnum] = new Image();
    picture[picnum].src = pictureURL;
}

function SetPieceImage(x, y, src) {
// routine to set the image associated with the given piece
    if(document.images[board[x][y].imagenum].src != src) {
        // we explicitely check to see if we are changing the image source to prevent
        // unnecessary redrawing of images which do not change
        document.images[board[x][y].imagenum].src = src;
    }
}

function _InitializeBoard(color) {
	var str = '';
// routine to initialize the state of the game and draw the board
    // build the board array
    for(x = 0; x < width; x++)
        board[x] = new Array (height);
    str += '<table style="background-color:#000" cellpadding="0" cellspacing="1" border="0" cols="' + width + '" rows="' + height + '">';
    for(y = 0; y < height; y++) {
        document.write('<tr>');
        for(x = 0; x < width; x++) {
            // place initial pieces
            if((x == 3 && y == 3) || (x == 4 && y == 4)) player = WHITE;
            else if((x == 3 && y == 4) || (x == 4 && y == 3)) player = BLACK;
            else player = EMPTY;

            str += '<td style="background-color:' + color + '" width="' + piecewidth + '" height="' + pieceheight + '"><a href="javascript:void(0);" onclick="PutPiece(' + x + ', ' + y + ')" onmouseover="CheckPutPiece(' + x + ', ' + y + ')" onmouseout="RestorePiece(' + x + ', ' + y + ')"  if(document.all) onfocus="this.blur()"><img name="c[' + x + ',' + y + ']" src="' + picture[player].src + '" height="' + pieceheight + '" width="' + piecewidth + '"></a></td>';
            board[x][y] = new piece('c[' + x + ',' + y + ']');
            board[x][y].player = player;
        }

        str += '</tr>';
    }
    str +='</table>';


    // initialize scores
    score[WHITE] = 2;
    score[BLACK] = 2;
    return str;
}

function InitializeBoard(color) {
// routine to initialize the state of the game and draw the board
    // build the board array
    for(x = 0; x < width; x++)
        board[x] = new Array (height);
    document.write('<table style="background-color:#000" cellpadding="0" cellspacing="1" border="0" cols="' + width + '" rows="' + height + '">');
    for(y = 0; y < height; y++) {
        document.write('<tr>');
        for(x = 0; x < width; x++) {
            // place initial pieces
            if((x == 3 && y == 3) || (x == 4 && y == 4)) player = WHITE;
            else if((x == 3 && y == 4) || (x == 4 && y == 3)) player = BLACK;
            else player = EMPTY;

            document.write('<td style="background-color:' + color + '" width="' + piecewidth + '" height="' + pieceheight + '"><a href="javascript:void(0);" onclick="PutPiece(' + x + ', ' + y + ')" onmouseover="CheckPutPiece(' + x + ', ' + y + ')" onmouseout="RestorePiece(' + x + ', ' + y + ')"  if(document.all) onfocus="this.blur()"><img name="c[' + x + ',' + y + ']" src="' + picture[player].src + '" height="' + pieceheight + '" width="' + piecewidth + '"></a></td>');
            board[x][y] = new piece('c[' + x + ',' + y + ']');
            board[x][y].player = player;
        }

        document.writeln('</tr>');
    }
    document.write('</table>');


    // initialize scores
    score[WHITE] = 2;
    score[BLACK] = 2;
}

function ResetBoard() {
// routine to reset all of the pieces on the board

    // cancel any pending AI task
    if(AI_timerID != undefined) {
        clearTimeout(AI_timerID);
        AI_timerID = undefined;
    }

    // reset the board
    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            board[x][y].player = EMPTY;
            SetPieceImage(x, y, picture[EMPTY].src);
        }
    }

    // reset scores
    score[WHITE] = 0;
    score[BLACK] = 0;

    // put initial pieces back on the board
    RawPutPiece(3, 3, WHITE);
    RawPutPiece(4, 4, WHITE);
    RawPutPiece(3, 4, BLACK);
    RawPutPiece(4, 3, BLACK);

    turn = BLACK;
    if(turnhook != "") eval(turnhook);
}

function NumFlips(x, y, player) {
    var deltax, deltay, distance;
    var posx, posy;
    var count = 0;

    for(deltay = -1; deltay <= 1; deltay++) {
        for(deltax = -1; deltax <= 1; deltax++) {
            for(distance = 1;; distance++) {
                posx = x + (distance * deltax);
                posy = y + (distance * deltay);
                // stop if we go off the board
                if(posx < 0 || posx >= width || posy < 0 || posy >= height)
                    break;
                // stop when we reach an empty square
                if(board[posx][posy].player == EMPTY)
                    break;
                // only update the flip count when we reach another of the
                // player's pieces
                if(board[posx][posy].player == player) {
                    count += distance - 1;
                    break;
                }
            }
        }
    }
    return(count);
}

function CalcFlipCounts() {
    var x, y;

    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            board[x][y].flips[WHITE] = 0;
            board[x][y].flips[BLACK] = 0;

            if(board[x][y].player != EMPTY) continue;

            board[x][y].flips[WHITE] = NumFlips(x, y, WHITE);
            board[x][y].flips[BLACK] = NumFlips(x, y, BLACK);
        }
    }
}

function RawPutPiece(x, y, player) {
    var other = OtherPlayer(player);
    if(board[x][y].player == other) score[other]--;

    board[x][y].player = player;
    SetPieceImage(x, y, picture[player].src);
    score[player]++;
}

function FlipPieces(x, y, player) {
    var deltax, deltay, distance;
    var posx, posy;
    var count = 0;

    // put a piece down at the desired location
    RawPutPiece(x, y, player);

    for(deltay = -1; deltay <= 1; deltay++) {
        for(deltax = -1; deltax <= 1; deltax++) {
            for(distance = 1;; distance++) {
                posx = x + (distance * deltax);
                posy = y + (distance * deltay);
                // stop if we go off the board
                if(posx < 0 || posx >= width || posy < 0 || posy >= height)
                    break;
                // stop when we reach an empty square
                if(board[posx][posy].player == EMPTY)
                    break;
                if(board[posx][posy].player == player) {
                    // backtrack, flipping pieces
                    for(distance--; distance > 0; distance--) {
                        posx = x + (distance * deltax);
                        posy = y + (distance * deltay);
                        RawPutPiece(posx, posy, player);
                    }
                    break;
                }
            }
        }
    }
    return(count);
}

function AnyMoves(player) {
    var x, y;

    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            if(board[x][y].player != EMPTY) continue;
            if(NumFlips(x, y, player) > 0) return(true);
        }
    }
    return(false);
}

function CanPutPiece(x, y, player) {
// determine whether the player can put a piece at the given position
    if(turn != player)
        return(false);
    if(board[x][y].player != EMPTY)
        return(false);
    return(NumFlips(x, y, player) > 0);
}

function CheckPutPiece(x, y) {
    var over;

    if(overhook != "") eval(overhook);

    if(! showcursor) return;
    if(! CanPutPiece(x, y, human)) return;

    if(human == WHITE) over = WHITETRANS;
    else over = BLACKTRANS;

    SetPieceImage(x, y, picture[over].src);
}

function RestorePiece(x, y) {
    if(showflips && RawShowFlipCount(x, y, human)) return;
    SetPieceImage(x, y, picture[board[x][y].player].src);
}

function PutPiece(x, y) {
    if(! CanPutPiece(x, y, human)) return;

    FlipPieces(x, y, human);
    DoneTurn();
}

function RawShowFlipCount(x, y, player) {
    var flips;
    if(board[x][y].player != EMPTY) return(false);
    if((flips = board[x][y].flips[player]) == 0) return(false);
    SetPieceImage(x, y, picture[NUMBASE + flips].src);
    return(true);
}

function ShowFlipCounts(player) {
    var x, y;

    CalcFlipCounts();
    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            RawShowFlipCount(x, y, player);
        }
    }
}

function HideFlipCounts() {
    var x, y;

    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            if(board[x][y].player == EMPTY)
                SetPieceImage(x, y, picture[EMPTY].src);
        }
    }
}

function OtherPlayer(player) {
    return((player == WHITE)? BLACK: WHITE);
}

function DoneTurn() {
    var moves = AnyMoves(turn);

    if(turnhook != "") eval(turnhook);

    turn = OtherPlayer(turn);

    // check whether the new player has any moves
    if(! AnyMoves(turn)) {
        if(! moves) return(GameOver());

        // XXX inform user the player has no move

        // and switch players again
        turn = OtherPlayer(turn);
    }

    // add a slight delay before the computer takes it's turn so game feels
    // "warmer"; when computer is playing itself, add larger delay so user
    // can watch
    if(turn != human) {
        HideFlipCounts();
        AI_timerID = setTimeout("OthelloAI(" + turn + ")", human == EMPTY? 1000: 150);
    }
    else if(showflips)
        ShowFlipCounts(human);
}

function Rate(x, y, player) {
    var rating;

    if(board[x][y].player != EMPTY) return(0);
    if(x < 0 || x >= width || y < 0 || y >= height) return(0);

    rating = board[x][y].flips[player];

    if(! weightsquares)
        rating = (rating > 0)? 1: 0;

    if(edgesensitive && rating > 0) {
        // increase all non-zero weightings by 3 so we have room
        // to wait 'less ideal' squares below the baseline
        rating += 10;

        // raise edge ratings 4 points, corners are raised 8
        if(x == 0 || x == width - 1) rating += 4;
        if(y == 0 || y == height - 1) rating += 4;
        // lower next-to-edge ratings by 5 points, next-to-corner by 10
        if(x == 1 || x == width - 2) rating -= 5;
        if(y == 1 || y == height - 2) rating -= 5;

        // we cannot rule out a move because of bad location; we must
        // always go somewhere
        if(rating < 1) rating = 1;
    }
    return(rating);
}

function OthelloAI(player) {
    var x, y;
    var best = 0, numbest = 0;
    var rating;
    var pick, count;

    // rank each position on the board by the potential flip count
    CalcFlipCounts();

    // apply AI rating algorithm
    for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
            rating = Rate(x, y, player);

            // store the rating back into the board
            board[x][y].value[player] = rating;

            if(rating == best)
                numbest++;
            else if(rating > best) {
                best = rating;
                numbest = 1;
            }
        }
    }

    while(numbest > 0) {
        // pick a square to put our piece
        pick = Math.floor(Math.random() * numbest);
        count = 0;
        for(y = 0; y < height; y++) {
            for(x = 0; x < width; x++) {
                rating = board[x][y].value[player];
                if(rating == best) {
                    if(count == pick) {
                        FlipPieces(x, y, player);
                        DoneTurn();
                        return;
                    }
                    else count++;
                }
            }
        }
    }

    // if we make it here, then there was nowhere to go
    DoneTurn();
}

function Play() {
    // black always goes first
    if(human != BLACK)
        OthelloAI(BLACK);
    else if(showflips)
        ShowFlipCounts(human);
}

function GameOver() {
    alert("Game Over; White: " + score[WHITE] + ", Black: " + score[BLACK]);
    turn = EMPTY;
}


// THE FOLLOWING INITIALIZATION SHOULD APPEAR IN THE MAIN HTML SOURCE
//
// // define a mouse-over and per-turn handler...
// overhook = 'window.status = "White: " + score[WHITE] + ", Black: " + score[BLACK]';
// turnhook = 'window.defaultStatus = "White: " + score[WHITE] + ", Black: " + score[BLACK]';
//
// // load player piece images
// LoadPieceImage(EMPTY, "images/blank.gif");
// LoadPieceImage(WHITE, "images/white.gif");
// LoadPieceImage(BLACK, "images/black.gif");
// LoadPieceImage(WHITETRANS, "images/white-trans.gif");
// LoadPieceImage(BLACKTRANS, "images/black-trans.gif");
//
// // load number images (must have at least 0-21)
// for(i = 0; i <= 21; i++)
//    LoadPieceImage(NUMBASE + i, "images/trans-" + i + ".gif");
//
// // set defaults
// human = BLACK;
// showcursor = true;
// showflips = false;
// weightsquares = true;
// edgesensitive = true;
//
// // initialize the state of the board
// InitializeBoard("#006600");
//
// // start the game!
// Play();
//