n+m frog puzzle

In this example below you will see how to do a n+m frog puzzle with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by kriswik, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright kriswik ©
  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>n+m frog puzzle</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <div id="uxNMPuzzleApp">
  <div id="uxAbout"> 
   <h1 id="uxTitle">6 Frog Puzzle</h1>
   <p id="uxInstructions">
    The goal of this puzzle is for the green and blue "frogs" to change sides. Blue frogs can only move left, and green frogs can only move right.
    There are two legal moves. (1) A frog can slide into an ajacent free slot. (2) A frog can jump over another frog into a free slot.
   </p>
  </div>
  
  <form id="uxPuzzleSettingsForm">
        <label for="uxPuzzleSymmetric">Symmetric</label>
        <input id="uxPuzzleSymmetric" type="checkbox" checked onclick="puzzleSymmetric()" />
        
        <label for="uxPuzzleSizeLeft" id="uxPuzzleSizeLeftLabel">Frogs on left</label>
        <input id="uxPuzzleSizeLeft" max="7" min="1" value="3" type="range" width="100" oninput="puzzleSizeChanged()" onchange="puzzleSizeChanged()" />

        <label for="uxPuzzleSizeRight" id="uxPuzzleSizeRightLabel">Frogs on right</label>
        <input id="uxPuzzleSizeRight" max="7" min="1" value="3" type="range" width="100" oninput="puzzleSizeChanged()" onchange="puzzleSizeChanged()" />

        <input id="uxPuzzleRestart" type="button" value="Restart" onclick="newGame()" />
  </form>

  <canvas height="140" id="uxCanvas" width="420" onclick="canvasClick"></canvas>
  
  <p id="uxAuthor">by Kristian Wik [Kristian.Wik@rogfk.no] 2014</p>  
</div><!-- end uxNMPuzzleApp -->
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/kriswik/nm-frog-puzzle-wGPezy */
        
         body {
        margin: 0px;
    }

#uxNMPuzzleApp {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

  #uxAbout {
    order: 1;
    flex: 1;
  }

  #uxPuzzleSettingsForm {
    flex-basis: 120px;
    order: 2;
    
    width: 120px;
    padding: 10px;
    background-color: #eeeeee;
    margin: 5px;
    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 10px;

  }

    label {  
      display: block;
      font-family: Arial, Helvetica, sans-serif;
      font-size: 10px;
      margin: 0;
    }

    input {
      display: block;
    }

    input[type='range'] {
      width: 100px;
    }

    #uxPuzzleRestart {
        background: #E48F8F;
        border: none;
        padding: 5px 5px 5px 5px;
        color: #FFF;
        margin: 5px;
    }

    #uxPuzzleRestart:hover {
      background: #f59f9f;
    }  
  

  #uxCanvas {
    order: 3;
    margin: 5px;  
  }

  #uxAuthor {
    order: 4;
    font-family: sans-serif;
    font-size: 10px;
  }


/*Downloaded from https://www.codeseek.co/kriswik/nm-frog-puzzle-wGPezy */
      // Global variables
            var puzzleSizeLeft = 3;
            var puzzleSizeRight = 3;
            var puzzle = [];
            var moves = 0;
            
            // Setup
            var c = document.getElementById("uxCanvas");
            c.addEventListener("click", canvasClick);
            document.getElementById("uxPuzzleSizeLeft").value = puzzleSizeLeft;
            document.getElementById("uxPuzzleSizeRight").value = puzzleSizeRight;
            requestAnimationFrame(animationTimer);
            puzzleSymmetric();
            newGame();

            function animationTimer()
            {
                drawPond();
                requestAnimationFrame(animationTimer);
            }

            function newGame()
            {
                moves = 0;
                puzzle = [];

                for (var i = 0; i < puzzleSizeLeft; i++)    // Left
                {
                    puzzle[i] = 1;
                }
                puzzle[puzzleSizeLeft] = 0;                 // Middle
                for (var i = 0; i < puzzleSizeRight; i++)    // Right
                {
                    puzzle[puzzleSizeLeft + puzzleSizeRight - i] = 2;
                }

                drawPond();
            }

            function puzzleSymmetric()
            {
                if (document.getElementById("uxPuzzleSymmetric").checked === true)
                {
                    document.getElementById("uxPuzzleSizeLeftLabel").innerHTML= "Frogs on either side";
                    document.getElementById("uxPuzzleSizeRightLabel").style.opacity = 0.4;
                    document.getElementById("uxPuzzleSizeRight").style.opacity = 0.4;
                    document.getElementById("uxPuzzleSizeRight").disabled = true;
                }
                else
                {
                    document.getElementById("uxPuzzleSizeLeftLabel").innerHTML = "Frogs on left";
                    document.getElementById("uxPuzzleSizeRightLabel").style.opacity = 1;
                    document.getElementById("uxPuzzleSizeRight").style.opacity = 1;
                    document.getElementById("uxPuzzleSizeRight").disabled = false;

                }
                document.getElementById("uxPuzzleSizeRight").value = document.getElementById("uxPuzzleSizeLeft").value;
                newGame();
            }

            function tryMove( frog )
            {
                if (puzzle[frog] != 0) // there is a frog there
                {
                    if (puzzle[frog] == 1) // moving right
                    {
                        if (frog + 1 < puzzle.length && puzzle[frog + 1] == 0) {
                            puzzle[frog + 1] = 1;
                            puzzle[frog] = 0;
                            moves++;
                        }
                        else if (frog + 2 < puzzle.length && puzzle[frog + 2] == 0) {
                            puzzle[frog + 2] = 1;
                            puzzle[frog] = 0;
                            moves++;
                        }
                    }
                    else if (puzzle[frog] == 2) // moving left
                    {
                        if (frog - 1 >= 0 && puzzle[frog - 1] == 0) {
                            puzzle[frog - 1] = 2;
                            puzzle[frog] = 0;
                            moves++;
                        }
                        else if (frog - 2 >= 0 && puzzle[frog - 2] == 0) {
                            puzzle[frog - 2] = 2;
                            puzzle[frog] = 0;
                            moves++;
                        }
                    }
                }
            }

            function checkForWin()
            {
                var won = true;     // assume victory

                for (var i = 0; i < puzzleSizeRight; i++)    // Left
                {
                    if (puzzle[i] != 2)
                        won = false;
                }
                if (puzzle[puzzleSizeRight] != 0)
                    won = false;                        // Middle
                for (var i = 0; i < puzzleSizeLeft; i++)    // Right
                {
                    if ( puzzle[puzzleSizeLeft + puzzleSizeRight - i] != 1)
                        won = false;
                }

                if (won)
                {
                    alert("Puzzle solved in " + moves + " moves :)");
                    newGame();
                }
            }

            function canvasClick(event)
            {
                var rect = c.getBoundingClientRect();
                var clickX = event.pageX - rect.left

                var stone = Math.floor( clickX / (c.width / (puzzleSizeLeft + puzzleSizeRight + 1)) );

                tryMove(stone);
                drawPond();
                checkForWin();
            }

            function puzzleSizeChanged()
            {
                if (document.getElementById("uxPuzzleSymmetric").checked === true)
                    document.getElementById("uxPuzzleSizeRight").value = document.getElementById("uxPuzzleSizeLeft").value;

                puzzleSizeLeft  = parseInt(document.getElementById("uxPuzzleSizeLeft").value);
                puzzleSizeRight = parseInt(document.getElementById("uxPuzzleSizeRight").value);

                if ( puzzleSizeLeft === puzzleSizeRight)
                    document.getElementById("uxTitle").innerHTML = (puzzleSizeLeft * 2) + " Frog Puzzle";
                else
                    document.getElementById("uxTitle").innerHTML = puzzleSizeLeft + "+" + puzzleSizeRight + " Frog Puzzle";

                newGame();
            }

            function drawPond()
            {
                var appContainer = document.getElementById("uxNMPuzzleApp");
                var appWidth = appContainer.offsetWidth; // Other property?
                
                var stoneWidth = ((appWidth - 10) / ((puzzleSizeLeft + puzzleSizeRight) + 1));
                c.width = appWidth - 10;
                c.height = stoneWidth;

                // Pulsating circle animation
                var time = (new Date()).getTime();
                var radiusScale = Math.sin(time / 200) * 0.1 + 0.9;



                var ctx = c.getContext("2d");
                ctx.clearRect(0, 0, c.width, c.height);

                for (var i = 0; i < (puzzleSizeLeft + puzzleSizeRight) + 1; i++)
                {
                    // Draw checkered pattern
                    if (i % 2 === 0)
                        ctx.fillStyle = '#999999';
                    else
                        ctx.fillStyle = '#CCCCCC';
                    ctx.fillRect(i * stoneWidth, 0, stoneWidth, stoneWidth);

                    // Draw "frogs"
                    if (puzzle[i] != 0) {
                        if (puzzle[i] === 1)
                            ctx.fillStyle = '#008000';
                        else
                            ctx.fillStyle = '#000080';
                        ctx.beginPath();
                        ctx.arc(
                            i * stoneWidth + (stoneWidth / 2),
                            (stoneWidth / 2),
                            (stoneWidth / 2) * 0.85 * radiusScale,
                            0, 2 * Math.PI
                            );
                        ctx.lineWidth = 2;
                        ctx.stroke();
                        ctx.fill();                    
                    }
                }
            }

Comments