// Four Wins - 3D
// $Id:$
// Copyright (c) 2000-2003 - Gregor Rayman - Internet Technology DE GmbH
// Copyrighted is the implementation of the game "Four Wins 3D". It can be
// distributed only as part of this HTML-Page. Every other usage
// requires written permission from me (Gregor Rayman)
//
// I do not claim copyright for the game "Four Wins 3D" itself. I did not
// invent it. We used to play it at school years ago...

var RadioOffImg = new Image(); RadioOffImg.src = 'img/games/radioE.gif';
var RadioOnImg = new Image(); RadioOnImg.src = 'img/games/radioF.gif';

var TileXWImage = new Image(); TileXWImage.src = 'img/games/tileXW.gif';
var TileOWImage = new Image(); TileOWImage.src = 'img/games/tileOW.gif';
var TileXBImage = new Image(); TileXBImage.src = 'img/games/tileXR.gif';
var TileOBImage = new Image(); TileOBImage.src = 'img/games/tileOR.gif';
var TileEWImage = new Image(); TileEWImage.src = 'img/games/tileEW.gif';
var TileHintImage = new Image(); TileHintImage.src = "img/games/tileHR.gif";

var WinLength = 4;

var Directions = new Array();

Directions[Directions.length] = new Array( 0,  0,  1);
Directions[Directions.length] = new Array( 0,  1,  0);
Directions[Directions.length] = new Array( 1,  0,  0);
Directions[Directions.length] = new Array( 0,  1,  1);
Directions[Directions.length] = new Array( 0,  1, -1)
Directions[Directions.length] = new Array( 1,  0,  1);
Directions[Directions.length] = new Array( 1,  0, -1);
Directions[Directions.length] = new Array( 1,  1,  0);
Directions[Directions.length] = new Array( 1, -1,  0);
Directions[Directions.length] = new Array( 1,  1, -1);
Directions[Directions.length] = new Array( 1, -1,  1);
Directions[Directions.length] = new Array(-1,  1,  1);
Directions[Directions.length] = new Array( 1,  1,  1);

var eX = 1;
var eO = -1;

var AutoPlaying = false;
var PlayGround;
var Lines;
var TilesPlayed = 0;
var MaxDepth = 10;

var PendingTimeout = 0;

var PlayAllowed = true;
var LastPlayed = new Array(-1, -1, -1);
var HintShown = new Array(-1, -1, -1);

function ResetGame() {
    window.clearTimeout(PendingTimeout);
    TilesPlayed = 0;
    LastPlayed[0] = -1;
    LastPlayed[1] = -1;
    LastPlayed[2] = -1;
    HintShown[0] = -1;
    HintShown[1] = -1;
    HintShown[2] = -1;

    PlayGround = new Array();

    for (var x = 0; x < WinLength; ++x) {
        PlayGround[x] = new Array();
        for (var y = 0; y < WinLength; ++y) {
            PlayGround[x][y] = new Array();
            for (var z = 0; z < WinLength; ++z) {
                PlayGround[x][y][z] = 0;
                ShowTile(x, y, z);
            }
        }
    }
    InitLines();
    AllowPlay();
}

function InitLines() {
    Lines = new Array();
    for (var x = 0; x < WinLength; ++x) {
        Lines[x] = new Array();
        for (var y = 0; y < WinLength; ++y) {
            Lines[x][y] = new Array();
            for (var z = 0; z < WinLength; ++z) {
                Lines[x][y][z] = new Array();
                for (var d = 0; d < Directions.length; ++d) {                    
                    Lines[x][y][z][d] = GetLineValue(x, y, z, d);
                }
            }
        }
    }                                                                    
}

function GetLineValue(x, y, z, d) {
    var Tile = 0;
    var TileCount = 0;
    var TotalCount = 0;
    var xx = x;
    var yy = y;
    var zz = z;
    for (var m = 0; 
        (m < WinLength) && 
        (xx >= 0) && (xx < WinLength) &&
        (yy >= 0) && (yy < WinLength) &&
        (zz >= 0) && (zz < WinLength);
        ++m, xx += Directions[d][0], yy += Directions[d][1], zz += Directions[d][2]) 
    {
        if (PlayGround[xx][yy][zz] == 0)
            ++TotalCount
        else if ((Tile == 0) || (Tile == PlayGround[xx][yy][zz])) {
            ++TotalCount;
            ++TileCount;
            Tile = PlayGround[xx][yy][zz];
        } 
        else break;        
    }            
    if (TotalCount < WinLength) return 10000
    else if (Tile == 0) return TotalCount
    else return (TotalCount - TileCount) * Tile;
}    

function UpdateLines(x, y, z) {
    var Result = false;
    for (var d = 0; d < Directions.length; ++d) {
        var xx = x; 
        var yy = y;
        var zz = z;
        for (var m = 0;     
            (m < WinLength) && 
            (xx >= 0) && (xx < WinLength) &&
            (yy >= 0) && (yy < WinLength) &&
            (zz >= 0) && (zz < WinLength);
            ++m, xx -= Directions[d][0], yy -= Directions[d][1], zz -= Directions[d][2]) 
        {
            var Value = GetLineValue(xx, yy, zz, d);
            Lines[xx][yy][zz][d] = Value;   
            if (0 == Value) {
                Result = true;
                HighlightLine(xx, yy, zz, d);
            }
        }
    }
    return Result;
}
   
function HighlightLine(x, y, z, d) {
    var ImgSrc = TileOBImage.src;
    var OWins = true;
    if (PlayGround[x][y][z] == eX) {
        ImgSrc = TileXBImage.src;
        OWins = false;
    }
    
    for (m = 0; m < WinLength; ++m) {
        ShowTileHi(x, y, z);
        x += Directions[d][0];
        y += Directions[d][1];
        z += Directions[d][2];
    }
    
    if (!AutoPlaying) {
        window.alert( OWins ? "Congratulations! You are the best! :-)": "Nice try, but this time I've had better luck :-)");
    }
}

function GetPointScoreVector(x, y, z, Player) {
    var Result = new Array();
    for (var i = 0; i <= WinLength * 2 - 2; ++i)
        Result[i] = 0;
    for (var d = 0; d < Directions.length; ++d) {
        var xx = x;
        var yy = y;
        var zz = z;
        for (var m = 0;     
            (m < WinLength) && 
            (xx >= 0) && (xx < WinLength) &&
            (yy >= 0) && (yy < WinLength) &&
            (zz >= 0) && (zz < WinLength);
            ++m, xx -= Directions[d][0], yy -= Directions[d][1], zz -= Directions[d][2]) 
        {
            var LineValue = Lines[xx][yy][zz][d];
            if ((Math.abs(LineValue) < WinLength) && (Math.abs(LineValue) > 0)) {
                ++Result[ (Math.abs(LineValue)-1) * 2 + 1];
                if (Player * LineValue > 0)
                    ++Result[ (Math.abs(LineValue)-1) * 2];
            } else if (Math.abs(LineValue) == WinLength) {
                ++Result[WinLength * 2 - 2];
            }
        }
    }
    return Result;
}

function CompareScores(ScoreA, ScoreB, Depth) {
    if (typeof(ScoreB) == "undefined")
        return 1;
    for (var i = 0; (i < Depth) && (i < ScoreA.length); ++i) {
        if (ScoreA[i] < ScoreB[i]) return -1
        else if (ScoreA[i] > ScoreB[i]) return 1;
    }
    return 0;
}

function ChoseMove(Depth, Player) {
    var BestScore;
    var Chosen;
    for (var x = 0; x < WinLength; ++x) {
        for (var y = 0; y < WinLength; ++y) {
            for (var z = 0; z < WinLength; ++z) {
                if (PlayGround[x][y][z] == 0) {
                    var Score = GetPointScoreVector(x, y, z, Player);
                    var Comp = CompareScores(Score, BestScore, Depth);
                    if ((Comp > 0) || typeof Chosen == "undefined") {
                        Chosen = new Array();
                        Chosen[0] = new Array(x, y, z);
                        BestScore = Score;
                    } else if (Comp === 0) {
                        Chosen[Chosen.length] = new Array(x, y, z);
                    }   
                }
            }
        }
    }                                     
    if (typeof Chosen == "undefined") {
        return new Array(-1, -1, -1);
    } else return Chosen[ Math.floor(Math.random() * Chosen.length) ];    
}

function DisallowPlay() {
    PlayAllowed = false;
}

function AllowPlay() {
    PlayAllowed = true;
}

function ShowTile(x, y, z) {
    var TileImage;
    var Player = PlayGround[x][y][z];
    if (Player == eX) TileImage = TileXWImage
    else if (Player == eO) TileImage = TileOWImage
    else TileImage = TileEWImage;
    
    window.document.images['D_'+x.toString()+'_'+y.toString()+'_'+z.toString()].src = TileImage.src;
}

function ShowTileHi(x, y, z) {
    var TileImage;
    var Player = PlayGround[x][y][z];
    if (Player == eX) TileImage = TileXBImage
    else if (Player == eO) TileImage = TileOBImage
    else TileImage = TileEWImage;
    
    window.document.images['D_'+x.toString()+'_'+y.toString()+'_'+z.toString()].src = TileImage.src;
}

function ShowHint() {
    if (PlayAllowed) {
        if (HintShown[0] >= 0) {
            ShowTile(HintShown[0], HintShown[1], HintShown[2]);
        }
        HintShown = ChoseMove(MaxDepth, eO);
        if (HintShown[0] >= 0) {
            x = HintShown[0];
            y = HintShown[1];
            z = HintShown[2];
            window.document.images['D_'+x.toString()+'_'+y.toString()+'_'+z.toString()].src = TileHintImage.src;
        } 
    }
}

function PutTile(x, y, z, Player) {
    PlayGround[x][y][z] = Player;
    if (LastPlayed[0] >= 0) {
        ShowTile(LastPlayed[0], LastPlayed[1], LastPlayed[2]);
    }
    ShowTileHi(x, y, z, Player);
    LastPlayed[0] = x;
    LastPlayed[1] = y;
    LastPlayed[2] = z;
    ++TilesPlayed;
    var Result = UpdateLines(x, y, z);
    if ((!Result) && (TilesPlayed >= WinLength * WinLength * WinLength)) {
        if (!AutoPlaying)
            window.alert('Draw. You play pretty good!');
        Result = true;
    }
    return Result;
}

function Play(x, y, z) {
    if (PlayAllowed && (PlayGround[x][y][z] == 0)) {
        DisallowPlay();
        if (HintShown[0] >= 0) {
            ShowTile(HintShown[0], HintShown[1], HintShown[2]);
            HintShown[0] = -1;
            HintShown[1] = -1;
            HintShown[2] = -1;
        }
        if (!PutTile(x, y, z, eO)) {
            PendingTimeout = window.setTimeout("ComputerPlay()", 400);
        }
    }
}

function ComputerPlay() {
    var Chosen = ChoseMove(MaxDepth, eX);
    if (Chosen[0] >= 0) {
        var x = Chosen[0];
        var y = Chosen[1];
        var z = Chosen[2];
        if (!PutTile(x, y, z, eX)) {
            AllowPlay();
        }
    }
}

function AutoPlayX() {
    var Chosen = ChoseMove(MaxDepth, eX);
    if (Chosen[0] >= 0) {
        var x = Chosen[0];
        var y = Chosen[1];
        var z = Chosen[2];
        if (!PutTile(x, y, z, eX)) {
            PendingTimeout = window.setTimeout("AutoPlayO()", 400);
        }
    }
}

function AutoPlayO() {
    var Chosen = ChoseMove(MaxDepth, eO);
    if (Chosen[0] >= 0) {
        var x = Chosen[0];
        var y = Chosen[1];
        var z = Chosen[2];
        if (!PutTile(x, y, z, eO)) {
            PendingTimeout = window.setTimeout("AutoPlayX()", 400);
        }
    }
}

function DemoGame() {
    ResetGame();
    DisallowPlay();
    AutoPlaying = true;
    AutoPlayO();
}

function StartX() {
    ResetGame();
    ComputerPlay();
}

function CreateDeskTable() {
    document.writeln('<table border=0 cellpadding=0 cellspacing=0>');
    for (var x = 0; x < WinLength; ++x) {
        document.writeln('<tr>');
        for (var y = 0; y < WinLength; ++y) {
            for (var z = 0; z < WinLength; ++z) {
                document.writeln(
                    '<td><a href="javascript:Play(' + x.toString() + ',' + y.toString() + ',' + z.toString() + ')">' +
                    '<img alt="" border="0" height="20" ' +
                    'id="D_'+x.toString()+'_'+y.toString()+'_'+z.toString()+'" ' +
                    'src="img/games/tileEW.gif"' +
                    'width="20"></a></td>');
            }
            document.writeln('<td><img alt="" border="0" height="20" src="img/games/dot.gif" width="1"></td>');
            document.writeln('<td><img alt="" border="0" height="20" src="img/emptydot.gif" width="40"></td>');
        }            
        document.writeln('</tr>');
    }
    document.writeln('<tr>');
    for (var y = 0; y < WinLength; ++y) {
        for (var z = 0; z < WinLength; ++z) {
            document.writeln(
                '<td><img alt="" border="0" height="1" src="img/games/dot.gif" width="20"></td>');
        }
        document.writeln('<td><img alt="" border="0" height="1" src="img/games/dot.gif" width="1"></td>');
        document.writeln('<td><img alt="" border="0" height="1" src="img/emptydot.gif" width="40"></td>');
    }            
    document.writeln('</tr>');
    document.writeln('</table>');
}
CreateDeskTable();
ResetGame();
