4
\$\begingroup\$

It's a standalone HTML file on GitHub

I included the CSS and JavaScript with the HTML so it would be easier to e-mail the game.

I'm most interested in comments about the solution-checking functions. This is the main function:

var evaluateSolution = function () {
//"In play" is the default state for the game.
var state = stateGame;

//Look for exact matches. 
checkColorPositionMatches();

//If every peg matches exactly, the game was won
if (colorPositionMatches == codeLength) {
    state = stateWin;

} else {
    //Look for color matches among the unmatched pegs.
    checkColorMatches();
    state = stateLose;
}

//Reset the match state of each codePeg
unmatchCodePegs();

return state;
}

This one checks for exact matches.

var checkColorPositionMatches = function() {
colorPositionMatches = 0;

codePegLoop:
for (var codePegIdx=0;codePegIdx<codePegs.length;codePegIdx++) {
    var codePeg = codePegs[codePegIdx];

    //evaluate each gamePeg, stopping if we hit an exact match.
    gamePegLoop:
    for (var gamePegIdx=0;gamePegIdx<gamePegs.length;gamePegIdx++) {
        var gamePeg = gamePegs[gamePegIdx];

        if ((gamePeg.color == codePeg.color) &&
            (gamePeg.position == codePeg.position)) {

                gamePeg.colorPositionMatched = true;
                codePeg.colorPositionMatched = true;

                colorPositionMatches++;

                break gamePegLoop;
        }
    }
}
}

This one checks for color-only matches.

var checkColorMatches = function() {
colorMatches = 0;

codePegLoop:
for (var codePegIdx=0;codePegIdx<codePegs.length;codePegIdx++) {
    var codePeg = codePegs[codePegIdx];

    //evaluate each unmatched game peg, recording matches as they occur
    gamePegLoop:
    for (var gamePegIdx=0;gamePegIdx<gamePegs.length;gamePegIdx++) {
        var gamePeg = gamePegs[gamePegIdx];

        if (gamePeg.color == codePeg.color && 
           (gamePeg.colorMatched == false) &&
           (codePeg.colorMatched == false) &&
           (gamePeg.colorPositionMatched == false) &&
           (codePeg.colorPositionMatched == false)) {

            gamePeg.colorMatched=true;
            codePeg.colorMatched=true;

            colorMatches++;

            break gamePegLoop;
        }
    }
}
}
\$\endgroup\$
2
\$\begingroup\$

The first thing I notice is that you're "manually" handling both color and position. This isn't actually necessary if you set everything up using simple arrays.

An array is, by definition, an indexed list of values. So if you use a simple array for your code and the pegs, then positions are the array's indices and colors are its values. This simplifies things considerably.

For instance, to find exact (color and position) matches, you only need to check if code[i] === pegs[i]. And to check if a peg matches anywhere in the code, you only need to check code.indexOf(peg[i]) !== -1. So if you can get something like this:

var code = ["white","black","red","blue","green"];  // the code
var pegs = ["white","black","blue","red","orange"]; // the player's selections

it'll make the checking a lot easier.

Now, along the way you'll need to do some extra work to keep track of the number of matches, and make sure you're not double-matching stuff. I.e. you need to pare down your arrays as you go, so they only contain the remaining unmatched values.

Here's an example:

function evaluateSolution(code, pegs) {
  var i, l,
      foundIndex,
      exactMatches = 0,
      valueMatches = 0;

  // copy the arrays, so we don't ruin the orignals
  code = code.slice(0);
  pegs = pegs.slice(0);

  // First pass: Look for value & position matches
  // We're looping "backwards", so we can safely remove items
  // "behind us"
  for( i = pegs.length - 1 ; i >= 0 ; i-- ) {
    // If there's a match, remove the matched index from both
    // the code and the pegs so it isn't matched again later.
    if(pegs[i] === code[i]) {
      exactMatches++;
      pegs.splice(i, 1);
      code.splice(i, 1);
    }
  }

  // Now, pegs and code only contain unmatched values

  // Second pass: Look for value matches anywhere in the code
  for( i = 0 , l = pegs.length ; i < l ; i++ ) {
    // attempt to find the peg in the remaining code
    foundIndex = code.indexOf(pegs[i]);
    if( foundIndex !== -1 ) {
      valueMatches++;
      // remove the matched code peg, since it's been matched
      code.splice(foundIndex, 1);
    }
  }

  // Now, return the number of exact and inexact matches
  // as an object, so it's easy to use
  return {
    exactMatches: exactMatches,
    valueMatches: valueMatches,
    totalMatches: exactMatches + valueMatches
  };
}

If you feed the arrays above to evaluateSolution() you'll get this back:

{
  exactMatches: 2,
  valueMatches: 2,
  totalMatches: 4
}

If exactMatches === code.length, then congrats, you've won! Otherwise, use the numbers to render the hint.


Other observations:

  • You leave a lot of blank lines in your code, but the non-blank lines are pretty crammed (e.g. your whitespace-less for-loop declarations). Give you code (and the reader) some space to breathe.
  • I looked briefly at the code on GitHub, and there's a lot going on. Too much really. But here's a hint: You can build most of HTML using JavaScript. Copy/pasting the HTML for each "turn" and giving it a new ID is a nightmare to deal with. Just loop and create elements in code.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.