/*****************************************************************************************************************************************
*                                                                                                                                                                                                                                                                                *
* Mastermind-Code-Generator version 0.99 / 21/Feb/2010                                                                                                                                                                              *
* Mastermind-Code-Generator version 1.0 / 30/Nov/2011                                                                                                                                                                                *
* changelog:                                                                                                                                                                                                                                                              *
* code length greater than 9 got no correct patterns,  because of wrong string length comparison                                                                                                                *
* turned the program into a class                                                                                                                                                                                                                            *
* (c) 2010 Jürgen Müller-Lütken; kontakt@p-six.de                                                                                                                                                                                             *
* free to use and to modify with kind permission if you leave this note inside. I would be very happy about a mail                                                                                     *
*                                                                                                                                                                                                                                                                                  *
* Example of using:                                                                                                                                                                                                                                                   *
* var options = { codeLength : 4, elementsForCoding : ["rot", "orange", "gelb", "blau", "braun", "gruen"], singles : false, randomCode : false, random : false };               *
* var coder = new SecretCodeGenerator(options);                                                                                                                                                                                                *                                                                               
* SecretCode = coder.create();                                                                                                                                                                                                                                *
* options:                                                                                                                                                                                                                                                                    *
* codeLength = length of the secret code, that you want to generate                                                                                                                                                                   *
* elementsForCoding = array of elements, the code will be generated of; the secret code is an array chosen out of these elements                                                           *
* singles = set it to true and you get back a secret code without any doubles                                                                                                                                                     *
* randomCode = set it to true and you get a secret code where every element will only be chosen by random selection                                                                                *
* random = if its true, the generator will randomly build the secret code by pattern or just by random selection                                                                                           *
*                                                                                                                                                                                                                                                                                   *
*******************************************************************************************************************************************/

// some helper functions
Array.prototype.Shuffle = function()
{
  var tmp, rand;
  for(var i =0; i < this.length; i++)
  {
    rand = Math.floor(Math.random() * this.length);
    tmp = this[i];
    this[i] = this[rand];
    this[rand] = tmp;
  }
}

Array.prototype.Copy = function()
{
  var copiedArray = new Array();
  for(var i =0; i < this.length; i++)
  {
    copiedArray[i] = this[i];
  }
  return copiedArray;
}

Array.prototype.isInArray = function(val)
{
	for(var i=0; i<this.length; i++)
	{
		if(this[i] == val)
		{
			return true;
		}
	}
	return false;
}

var SecretCodeGenerator = function(options)
{
	this.codeLength = options.codeLength;
	this.elementsForCoding = options.elementsForCoding;
	this.randomCode = options.randomCode;
	this.singles = options.singles;
	this.random = options.random;
	
	var _patterns = [];
	
	// function creating all possible patterns (for a code of four colors it will create an array with these patterns: 1234, 1123, 1122, 1112, 1111)
	var _createPatterns = function(codeLength)
	{
	  var blockLength = 0;
	  var patternLength = 0;

	  while(blockLength < codeLength)
	  {
	    var pattern = '';
	    var goAhead = false;
	    var blocks = 1;
	    var possibilities = true;
	    var numberOfBlocks = 0;
	    var innerBlockLength = 2;
		
	    blockLength++;

	    while(possibilities == true)
	    {
	      pattern = '';
		  
	      if(blockLength > 1)
	      {
	        numberOfBlocks = Math.floor((codeLength-blockLength)/innerBlockLength);
	        if((codeLength-blockLength) >= 2 && numberOfBlocks == 0)
	          break;
	      }
	      for(var i=1; i<=codeLength; i++)
	      {
	        if(i == 1)
	        {
	          for(var j=0; j<blockLength; j++)
	          {
	            pattern += String(i) + "|";
				patternLength++;
	          }
	          goAhead = true;
	        }
	        else if(numberOfBlocks && blocks > 1 && i <= blocks)
	        {
	          for(var x=0; x<innerBlockLength; x++)
	          {

				if(patternLength < codeLength)
				{
	              pattern +=  (i + '|');
				  patternLength++;
				}
	            else
	              break;
	          }
	        }
	        else
	        {
			  if(patternLength < codeLength)
	           {
	              pattern +=  (i + '|');
				  patternLength++;
				}
	          else
	            break;
	        }
	        if(!goAhead)
	          break;
	      }
	      if(blockLength > 1 && blocks > numberOfBlocks)
	      {
	        blocks = 1;
	        innerBlockLength++;
	      }

	      if(innerBlockLength > blockLength || numberOfBlocks == 0)
	        possibilities = false;
	      blocks++;
	      _patterns.push(pattern.substring(0, pattern.length-1));
		  patternLength = 0;
	    }
	  }
	  _patterns.Shuffle();
	}
	
	_createPatterns(options.codeLength);

	// choose a random pattern from the shuffled array of all patterns
	var _getRandomPattern = function()
	{
	  var rnd = Math.floor(Math.random()*(_patterns.length));
	  var pattern = _patterns[rnd].split('|');
	  pattern.Shuffle();
	  return pattern;
	}

	// change the pattern into the code (of colors, digits, symbols etc.) and return it
	this.create = function()
	{
		var pattern = _getRandomPattern();
		var copiedElements = this.elementsForCoding.Copy();
		var secretCode = new Array(this.codeLength);
		var fullCode = false;
		var count = 0;
		if(this.random && Math.random() > 0.5)
		{
			this.randomCode =  true;
		}
		
		for(var k=0; k<secretCode.length; k++)
		{
			secretCode[k] = 'x';
		}
		if(this.singles)
		{
			while(count < this.codeLength)
			{
				var rnd = Math.floor(Math.random()*copiedElements.length);
				if(!secretCode.isInArray(rnd))
				{
					secretCode[count] = rnd;
					count++;
				}
			}
			for(k=0; k<secretCode.length; k++)
			{
				secretCode[k] = copiedElements[secretCode[k]];
			}
		}
		else
		{
			for(k=0; k<this.codeLength; k++)
			{
				var rnd = Math.floor(Math.random()*copiedElements.length);

				if(!this.randomCode)
				{
					var elem = copiedElements[rnd];
					var deleted = false;
					var sC = pattern[k];
					for(var q=0; q<pattern.length; q++)
					{
						if(secretCode[q] == 'x' && pattern[q] == sC)
						{
							secretCode[q] = elem;
							count++;
							if(count == this.codeLength)
							{
								fullCode = true;
								break;
							}
							if(!deleted)
							{
								copiedElements.splice(rnd, 1);
								deleted = true;
							}
						}
					}
					if(fullCode)
					{
						break;
					}
				}
				else
				{
					secretCode[k] = copiedElements[rnd];
				}
			}
		}
		return secretCode;
	}
}

// configure the length of the code and the kind of code (colors, digits etc.) or the kind of code generating you like (see usage explanation above)
var options = { codeLength : 4, elementsForCoding : ["rot", "orange", "gelb", "blau", "braun", "gruen"], singles : false, randomCode : false, random : false };
var coder = new SecretCodeGenerator(options);
