// JavaScript - Mastermind
// 2005 (c) Gregor Rayman (rayman@grayman.de)
// Released under GPL Version 2 from June 1991 (http://www.gnu.org/licenses/gpl.html)
// $Id: mastermind.js 11 2005-02-12 01:05:47Z gra $

var images = new Array();
images[1] = new Image();
images[1].src = "ball-red.gif";
images[2] = new Image();
images[2].src = "ball-blue.gif";
images[3] = new Image();
images[3].src = "ball-green.gif";
images[4] = new Image();
images[4].src = "ball-magenta.gif";
images[5] = new Image();
images[5].src = "ball-yellow.gif";
images[6] = new Image();
images[6].src = "ball-white.gif";

whitePin = new Image(); whitePin.src = "pin-white.gif";
blackPin = new Image(); blackPin.src = "pin-black.gif";


var dragIndex = null;
var oldTarget = null;
var playRow = 1;

var playGround = new Array();
var scoreFields = new Array();
var hiddenRow = new Array();
var numCol = new Array();

var combinations;

var waiting = false;

var solution = new Array();

var tip = new Array(0, 0, 0, 0);

var inGame = true;

var VERY_EASY = 0;
var EASY = 1;
var NORMAL = 2;
var DIFFICULT = 3;

var difficulty = NORMAL;

var textWin = "Glckwunsch! ;-)";
var textLost = "Nochmal spielen?";

function initCombinations() {
  var i = 0;
  combinations = new Array();
  for (var k1 = 1; k1 <= 6; k1++) {
    for (var k2 = 1; k2 <= 6; k2++) {
      for (var k3 = 1; k3 <= 6; k3++) {
        for (var k4 = 1; k4 <= 6; k4++) {
          var c = new Array(k1, k2, k3, k4);
          combinations[i++] = c;
        }
      }
    }
  }
  for (var i = 0; i < 4; ++i) {
    solution[i] = Math.floor(Math.random()*6) + 1;
  }
  inGame = true;
}

function getScore(c1, c2) {
  // same color, same position
  var score = 0;
  var b1 = new Array(true, true, true, true);
  var b2 = new Array(true, true, true, true);
  for (var i = 0; i < 4; ++i) {
    if (c1[i] == c2[i]) {
      score += 10;
      b1[i] = b2[i] = false;
    }
  }
  
  // same color, different position
  for (var i = 0; i < 4; ++i) {
    for (var j = 0; b1[i] && j < 4; ++j) {
      if (b2[j] && c1[i] == c2[j]) {
        score++;
        b1[i] = b2[j] = false;
      }
    }
  }
  return score;
}

function sortBuckets() {
  waiting = true;
  var buckets = new Array();
  var bi = new Array();
  for (var i = 0; i < combinations.length; ++i) {
    var score = getScore(combinations[i], tip);
    if (!buckets[score]) {
      bi[bi.length] = score;
      buckets[score] = new Array();
    }
    buckets[score][buckets[score].length] = combinations[i];
  }
  var top = 0;
  var bottom = 10000;
  var worst = 40;
  var best = 0;
  var score = getScore(solution, tip);
  var bestBuckets;
  var bestCombinations;
  var worstCombinations;
  var worstBuckets;
  
  for (var i = 0; i < bi.length; ++i) {
    if (buckets[bi[i]].length > top) {
      bestBuckets = new Array();
    } 
    if (buckets[bi[i]].length >= top && bi[i] != 40) {
      bestBuckets[bestBuckets.length] = bi[i];
      top = buckets[bi[i]].length;
    }
    if (buckets[bi[i]].length < bottom) {
      worstBuckets = new Array();
    }
    if (buckets[bi[i]].length <= bottom && bi[i] != 40) {
      worstBuckets[worstBuckets.length] = bi[i];
      bottom = buckets[bi[i]].length;
    }
  }
  
  if (bestBuckets.length == 0) bestBuckets[0] = 40;
  if (worstBuckets.length == 0) worstBuckets[0] = 40;
  if (difficulty == VERY_EASY && buckets[40]) worstBuckets[0] = 40;
  
  best = bestBuckets[Math.floor(Math.random() * bestBuckets.length)];
  bestCombinations = buckets[best];  

  worst = worstBuckets[Math.floor(Math.random() * worstBuckets.length)];
  worstCombinations = buckets[worst];  

  
  var result = score;
  if (difficulty == DIFFICULT) {
    result = best;
    combinations = bestCombinations;
    solution = combinations[Math.floor(Math.random()*combinations.length)];
  } else if (difficulty <= EASY) {
    result = worst;
    combinations = worstCombinations;
    solution = combinations[Math.floor(Math.random()*combinations.length)];
  } else {
    result = score;
    combinations = buckets[score];
  }
  
  var r = result;
  var j = 0;
  while (r >= 10) {
    scoreFields[playRow][j].style.backgroundImage = 'url(' + blackPin.src +')';
    r -= 10;
    ++j;
  }
  while (r >= 1) {
    scoreFields[playRow][j].style.backgroundImage = 'url(' + whitePin.src +')';
    r -= 1;
    ++j;
  }
 
  waiting = false;
  return result;
}

function createPlayground() {
  document.writeln('<table width="180" style="padding: 0ex; border: solid 4px #aaaaaa; background-color: #cccccc" id="playground" border="0" cellpadding="0" cellspacing="0" >');
  document.writeln('<tr><td></td>');
  for (var j = 0; j < 4; ++j) {
      var name = 'h_' + j;
      document.write('<td class="hidden" id="' + name + '">&nbsp;</td>');
      hiddenRow[j] = document.getElementById(name);      
  }
  document.writeln('<tr><td colspan="7" id="notice" align="center">&nbsp;</td></tr>');
  for (var i = 10; 0 < i; --i) {
    name = "rn_" + i;
    document.writeln('<tr><td rowspan="2" align="center" style="background-color: #808080; color: #ffffff" id="'+name+'">' + i + '</td>');
    numCol[i] = document.getElementById(name);
    var playRow = new Array();
    playGround[i] = playRow;
    for (var j = 0; j < 4; ++j) {
      var name = 'pg_' + i + '_' + j;
      document.write('<td class="field" rowspan="2" id="' + name + '">&nbsp;</td>');
      playRow[j] = document.getElementById(name);      
    }
    var scoreRow = new Array();
    scoreFields[i] = scoreRow;
    for (var j = 0; j < 2; ++j) {
      var name = 'sf_' + i + '_' + j;
      document.writeln('<td class="score" id="' + name + '"></td>');
      scoreRow[j] = document.getElementById(name);      
    }
    document.writeln('</tr><tr>');
    for (var j = 2; j < 4; ++j) {
      var name = 'sf_' + i + '_' + j;
      document.writeln('<td class="score" id="' + name + '"></td>');
      scoreRow[j] = document.getElementById(name);      
    }
    document.writeln('</tr>');
  }
  document.writeln('<tr><td colspan="7">&nbsp;</td></tr>');
  document.writeln('<tr>');
  for (var i = 1; i <= 5; ++i) {
    document.write('<td class="hidden" onmousedown="dragStart(' + i + ', event)" align="center" valign="middle">');
    document.write('<img src="' + images[i].src + '" alt="(' + i + ')">');
    document.write('</td>');
  }
  document.write('<td colspan="2" class="hidden" onmousedown="dragStart(6, event)" align="center" valign="middle">');
  document.write('<img src="' + images[6].src + '" alt="(6)">');
  document.write('</td>');
  document.writeln('</tr>');
  document.writeln('</table>');
}

function dragStart(index, event) {
  if (waiting || !inGame) return;
  dragIndex = index;
  var img = document.images["ball"];
  img.src = images[index].src;
  img.style.display = "inline";
  var posx = document.all ? window.event.offsetX + getLeft(window.event.srcElement) : event.pageX;
  var posy = document.all ? window.event.offsetY + getTop(window.event.srcElement): event.pageY;
  img.style.left = (posx - 12) + "px";
  img.style.top = (posy - 12) + "px";
  document.onmousemove = drag;
}

function drag(event) {
  var img = document.images["ball"];
  var posx = document.all ? window.event.offsetX + getLeft(window.event.srcElement) : event.pageX;
  var posy = document.all ? window.event.offsetY + getTop(window.event.srcElement): event.pageY;
  img.style.left = (posx - 12) + "px";
  img.style.top = (posy - 12) + "px";
  findTarget(posx, posy);
  if (oldTarget != targetObject.node) {
    if (oldTarget != null) {
      oldTarget.style.backgroundColor = "#eeeeff";
    }
    if (targetObject.node != null) {
      targetObject.node.style.backgroundColor = "#ffffff";
    }
    oldTarget = targetObject.node;
  }
}

function dragStop(event) {
  if (waiting) return;
  var img = document.images["ball"];
  img.style.display = "none";
  var posx = document.all ? window.event.offsetX + getLeft(window.event.srcElement) : event.pageX;
  var posy = document.all ? window.event.offsetY + getTop(window.event.srcElement): event.pageY;
  findTarget(posx, posy);
  if (targetObject.node != null) {
    targetObject.node.style.backgroundImage = "url(" + img.src + ")";
  }
  if (oldTarget != null) {
    oldTarget.style.backgroundColor = "#eeeeff";
    oldTarget = null;
  }
  document.onmousemove = null;
 
  if (targetObject.node == null) return;
  tip[targetObject.col] = dragIndex;
  for (var i = 0; i < 4; ++i) {
    if (tip[i] == 0) return;
  }
  
  var score = sortBuckets();
  tip = new Array(0, 0, 0, 0);
  numCol[playRow].style.color = '#ffff00';
  ++playRow;
  if (playRow > 10 || score == 40) {
    inGame = false;
    if (score == 40) {
      document.getElementById("notice").innerHTML = textWin;
    } else {
      document.getElementById("notice").innerHTML = textLost; 
    }
    s = getSolution();
    for (var i = 0; i < 4; ++i) {
      hiddenRow[i].style.backgroundImage = 'url(' + images[s[i]].src + ')';
    } 
  }
}

function getSolution() {
  if (difficulty == DIFFICULT) {
    var i = Math.floor(Math.random() * combinations.length);
    return combinations[i];
  } 
  return solution;
}

function getLeft(e) {
  if (e.offsetParent) return e.offsetLeft + getLeft(e.offsetParent);
  return e.offsetLeft;
}

function getTop(e) {
  if (e.offsetParent) return e.offsetTop + getTop(e.offsetParent);
  return e.offsetTop;
}

var targetObject = new Object();

function findTarget(x, y) {
  var pg =  document.getElementById('playground');
  for (var j = 0; j < 4; ++j) {
    var e = playGround[playRow][j];
    if (x > getLeft(e) && y > getTop(e) && getLeft(e) + e.offsetWidth > x && getTop(e) + e.offsetHeight > y) {
      targetObject.node = e;
      targetObject.col = j;
      return;
    }
  }
  targetObject.node = null;
}

function resetGame() {
  waiting = true;
  initCombinations();
  document.getElementById("notice").innerHTML = "&nbsp;";
  for (var i = 1; i <= 10; ++i) {
    numCol[i].style.color = '#ffffff';
    for (var j = 0; j < 4; ++j ) {
      playGround[i][j].style.backgroundImage = "none";
      scoreFields[i][j].style.backgroundImage = "none";
    }
  }
  for (var j = 0; j < 4; ++j ) {
    hiddenRow[j].style.backgroundImage = "none";
  }
  playRow = 1;
  waiting = false;
}

function setDifficulty(d) {
  difficulty = d;
  for (var i = 0; i <= 3; ++i) {
    document.images["d_" + i].src = (i==d) ? "checked.gif" : "unchecked.gif";
  }
}

