// for stats var gamesPlayed = 0; var totalMoves = 0; // run this when the button is clicked $('#run').click(function(){ var options = { // see if the option to run until everyone wins is checked doRunUntilEveryoneWins: $('#all-win').is(':checked') }; // configure two players var players = [ // ladies first { name: 'Thing 1', isLosingATurn: false, position: -1, isWinner: false, moves: 0 }, { name: 'Michael', isLosingATurn: false, position: -1, isWinner: false, moves: 0 } ]; // call "DoGame" to play an entire game, passing // in the players array DoGame(options, players); // update stats gamesPlayed++; totalMoves += players[0].moves + players[1].moves; $('#average').text(Math.ceil(totalMoves/gamesPlayed)); // append another row to the table $('#results').show() .find('table').append( $('<tr/>').append( $('<td/>').text(players[0].moves) ) .append( $('<td/>').text(players[1].moves) ) .append( $('<td/>').text(players[0].moves + players[1].moves) ) ); }); function DoGame(options, players){ // initialize the board var board = MakeBoard(); // initialize the deck var cards = MakeDeck(); // call "DoGameLoop" (pass in the board and deck) // until it returns false, which indicates the game is over while(DoGameLoop(options, players, board, cards)); } // return false when the game is over function DoGameLoop(options, players, board, cards){ // we will set this to true if someone is playing... var IsSomeoneStillPlaying = false; // for each player: DoPlayerLoop for(var i = 0; i < players.length; ++i){ var player = players[i]; // skip this player if they've won already // or made 10000 moves (that would be too many) if(!player.isWinner && player.moves < 10000){ // do the actual move DoPlayerLoop(options, player, board, cards); // keep track if this player has won IsSomeoneStillPlaying |= !player.isWinner; // see if we should stop when just one player wins (configurable) if(!options.doRunUntilEveryoneWins && player.isWinner){ return false; } } } // things went as planned, return true if some players are still playing return IsSomeoneStillPlaying; } function DoPlayerLoop(options, player, board, cards){ // if we are losing a turn, turn off the "isLosingATurn" // property and we're done (exit now) if(player.isLosingATurn){ player.isLosingATurn = false; return true; } // draw a card and increment the "moves" counter var drawnCard = DrawACard(cards); player.moves++; // we'll can play either 1 or 2 moves because we have doubles var currentSpace = DoMove(options, player, board, drawnCard); // if the player drew a double card, they move again if(drawnCard.isDouble && !player.isWinner){ DoMove(options, player, board, drawnCard ); // do it again! } if(player.isWinner){ // woohoo return true; } // if the space we landed on is a bridge, follow the bridge if(currentSpace.bridgeTo){ player.position = currentSpace.bridgeTo; currentSpace = board[player.position]; } // if we are now on a lose-a-turn space, turn on the // "isLosingATurn" property so we know // to skip our turn the next time around if(currentSpace.loseTurn){ player.isLosingATurn = true; } } function DoMove(options, player, board, card){ // we'll cycle through the board. // if we have a regular color card (or double), we'll go // until we hit the color, OR reach the end of the board var currentSpace; var iterations = 0; do{ // advance one space player.position++; // if we hit the end of the board // we start over if we have a character card // or we win if we have a regular color card if(player.position == board.length){ if(card.isCharacter){ // if we have a character card and we've reached the // end of the board, wrap around player.position = 0; } else{ // if your move takes you to the last square or beyond, you win // set the "isWinner" property to true and exit player.isWinner = true; } } currentSpace = board[player.position]; // loop until we find the space we're looking for // or we win // or we iterate 10000 times (because something must be broken) }while(currentSpace && currentSpace.color != card.color && !player.isWinner && ++iterations < 10000); return currentSpace; } function DrawACard(cards){ // if there are no cards left in the deck they must have all been played so // reshuffle them! Boom, now there are cards in the deck if(cards.length == 0){ // note: we can't just overwrite cards as we did up above like this: // cards = MakeDeck() // because javascript doesn't support pass-by-reference. That means that // when this function returns, cards still points to the same memory location, // not the new location that MakeDeck points to. And so we need to merge the two arrays // (even though one of them is empty), preserving the original memory address // This is smelly and worthy of future attention var newDeck = MakeDeck(); for(var i = 0; i< newDeck.length; ++i){ cards.push(newDeck[i]); } } // remove a card and return it return cards.pop(); } function MakeDeck(){ // return a new, shuffled deck ! var unshuffled = [ { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Red' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Purple' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Yellow' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Blue' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Orange' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Green' }, { color: 'Red', isDouble: true }, { color: 'Blue', isDouble: true }, { color: 'Purple', isDouble: true }, { color: 'Orange', isDouble: true }, { color: 'Yellow', isDouble: true }, { color: 'Green', isDouble: true }, { color: 'Red', isDouble: true }, { color: 'Blue', isDouble: true }, { color: 'Purple', isDouble: true }, { color: 'Orange', isDouble: true }, { color: 'Yellow', isDouble: true }, { color: 'Green', isDouble: true }, { color: 'Gingerbread Man', isCharacter: true }, { color: 'Candy Cane', isCharacter: true }, { color: 'Gum Drop', isCharacter: true }, { color: 'Peanut', isCharacter: true }, { color: 'Lolly Pop', isCharacter: true }, { color: 'Ice Cream Cone', isCharacter: true } ]; return shuffle(unshuffled); } function MakeBoard(){ // return a new board return [ { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange', bridgeTo: 59 },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Gingerbread Man' }, { color: 'Yellow' },{ color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' },{ color: 'Blue' }, { color: 'Orange' },{ color: 'Green' },{ color: 'Candy Cane' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow', bridgeTo: 45 }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' },{ color: 'Gum Drop' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red', loseTurn: true },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Peanut' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue', loseTurn: true },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' },{ color: 'Lolly Pop' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' },{ color: 'Ice Cream Cone' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow', loseTurn: true }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' },{ color: 'Purple' },{ color: 'Yellow' }, { color: 'Blue' },{ color: 'Orange' },{ color: 'Green' }, { color: 'Red' } ]; } //spiffy Fisher–Yates shuffle http://stackoverflow.com/q/962802/29 // O(n) woo hoo! function shuffle(array) { var tmp, current, top = array.length; if(top) while(--top) { current = Math.floor(Math.random() * (top + 1)); tmp = array[current]; array[current] = array[top]; array[top] = tmp; } return array; }
<button id='run'>Run a game</button> <label><input type='checkbox' id='all-win'/>Play out until everyone "wins"</label> <div id='results'> <hr/> <h2>Results:</h2> <p>Moves per game (average: <span id='average'>0</span>)</p> <table> <tr><th>Daddy</th><th>Thing 1</th><th>Total</th></tr> </table> </div>
#results { display:none; }