Tuesday, 13 May 2025

Web Tutorial: Paper Rock Scissors Game (Part 2/2)

The game is started via the start() method. So make sure that clicking the Start button runs this.
<button id="btnStart" class="topBtn" onclick="paprocksc.start()">Start</button>


In the start() method, we set the range and auto properties depending on the values of the ddlRange drop-down list and the cbAuto checkbox.
start: function()
{
  var ddlRange = document.getElementById("ddlRange");
  this.range = ddlRange.value;

  var cbAuto = document.getElementById("cbAuto");
  this.auto = cbAuto.checked;

},


Then we hide btnStart by adding the hidden CSS class to it, and show btnStop by removing the hidden CSS class.
start: function()
{
  var ddlRange = document.getElementById("ddlRange");
  this.range = ddlRange.value;

  var cbAuto = document.getElementById("cbAuto");
  this.auto = cbAuto.checked;

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn hidden";
  btnStop.className = "topBtn";

},


And set the active property to true.
start: function()
{
  var ddlRange = document.getElementById("ddlRange");
  this.range = ddlRange.value;

  var cbAuto = document.getElementById("cbAuto");
  this.auto = cbAuto.checked;

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn hidden";
  btnStop.className = "topBtn";
  this.active = true;
},


We then have an If block to handle the scenario of auto being true. For now, we will leave that alone, If auto is not true, however, we run showOptions().
start: function()
{
  var ddlRange = document.getElementById("ddlRange");
  this.range = ddlRange.value;

  var cbAuto = document.getElementById("cbAuto");
  this.auto = cbAuto.checked;

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn hidden";
  btnStop.className = "topBtn";
  this.active = true;

  if (this.auto)
  {

  }
  else
  {
    this.showOptions();
  }

},


Now let's do stop(). This is run every time the Stop button is clicked, and also when the values in ddlRange are changed, and cbAuto is clicked.
<h1>Paper, Rock, Scissors</h1>
<select id="ddlRange" onchange="paprocksc.stop()">
  <option value="3">Classic</option>
  <option value="5">Extended</option>
</select>
<input type="checkbox" id="cbAuto" onclick="paprocksc.stop()">Auto

<button id="btnStart" class="topBtn" onclick="paprocksc.start()">Start</button>
<button id="btnStop" class="topBtn hidden" onclick="paprocksc.stop()">Stop</button>

<div class="gameContainer">


In here, we set range to 0 and run showOptions(). This effectively hides all the symbol buttons.
stop: function()
{
  this.range = 0;
  this.showOptions();

},


After that, we hide the Stop button and display the Start button.
stop: function()
{
  this.range = 0;
  this.showOptions();

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn";
  btnStop.className = "topBtn hidden";

},


Then we change both user and computer symbols to show a question mark, by running showSymbol() twice, passing in an empty string for the second argument for both calls. We then set score to have all zeroes in the array, and run showScore() to show the zeroes.
stop: function()
{
  this.range = 0;
  this.showOptions();

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn";
  btnStop.className = "topBtn hidden";

  this.showSymbol(0, "");
  this.showSymbol(1, "");

  this.score = [0, 0];
  this.showScore();

},


And if timer is not null, we run clearInterval() on it.
stop: function()
{
  this.range = 0;
  this.showOptions();

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn";
  btnStop.className = "topBtn hidden";

  this.showSymbol(0, "");
  this.showSymbol(1, "");

  this.score = [0, 0];
  this.showScore();

  if (this.timer !== null) clearInterval(this.timer);
},


Now let's try this. Click the start button. Do the three buttons appear? Does the Start button disappear, only to be replaced by the Stop button?


Now select "Extended" in the drop-down list. Does the Stop button disappear, only to be replaced by the Start button? If you click Start, do all 5 buttons appear?


Now that we have a scenario where the symbol buttons appear, let's handle them being clicked.
<div class="dashboard">
  <button class="symbolBtn hidden" onclick="paprocksc.chooseSymbol('paper')"><img src="symbol_paper.jpg" width="80" /></button>
  <button class="symbolBtn hidden" onclick="paprocksc.chooseSymbol('rock')"><img src="symbol_rock.jpg" width="80" /></button>
  <button class="symbolBtn hidden" onclick="paprocksc.chooseSymbol('scissors')"><img src="symbol_scissors.jpg" width="80" /></button>
  <button class="symbolBtn hidden" onclick="paprocksc.chooseSymbol('spock')"><img src="symbol_spock.jpg" width="80" /></button>
  <button class="symbolBtn hidden" onclick="paprocksc.chooseSymbol('lizard')"><img src="symbol_lizard.jpg" width="80" /></button>
</div>


And we'll work on the chooseSymbol() method. It has a parameter, symbol. This is a string such as "rock, "paper", etc. The first thing we should do is check if active is false, and exit early if so. This means that when active is false, clicking on the buttons accomplishes nothing.
chooseSymbol: function(symbol)
{
  if (!this.active) return;
},  


There will be a scenario where symbol is an empty string. For now, create an If block for it, and cater to the Else condition. If symbol has a value, set the first element of the round array to that value. Then recursively call chooseSymbol(), this time with an empty string.
chooseSymbol: function(symbol)
{
  if (!this.active) return;

  if (symbol === "")
  {

  }
  else
  {
    this.round[0] = symbol;  

    this.chooseSymbol("");              
  }

},  


Thus, if chooseSymbol() is called with an empty string, we declare ptr and assign a random number to it, between 0 and range, excluding range. And then use it to point to an element in symbols, and assign that value to the second element in the round array. In effect, the computer makes a random choice! Use the return statement at this point, because then we're done for that scenario.
chooseSymbol: function(symbol)
{
  if (!this.active) return;

  if (symbol === "")
  {
    var ptr = Math.floor(Math.random() * this.range);
    this.round[1] = this.symbols[ptr].name;
    return;

  }
  else
  {
    this.round[0] = symbol;
    
    this.chooseSymbol("");              
  }
},  


Then we run the showSymbol() method twice, once for the user and once for the computer. And after that, we run whowins().
chooseSymbol: function(symbol)
{
  if (!this.active) return;

  if (symbol === "")
  {
    var ptr = Math.floor(Math.random() * this.range);
    this.round[1] = this.symbols[ptr].name;
    return;
  }
  else
  {
    this.round[0] = symbol;
    
    this.chooseSymbol("");              
  }

  this.showSymbol(0, this.round[0]);
  this.showSymbol(1, this.round[1]);
  this.whowins();

},  


We begin whowins() by setting the active property to false, to ensure that the symbol buttons can't be clicked during this time.
whowins: function()
{
  this.active = false;
},


Then we declare winner0 and winner1, both Booleans. winner1 is defined by passing the first and second elements of the round array into the xbeatsy() method. Thus winner0 is true if the user beats the computer, and false if not. The reverse is true for winner1. Note that the values are still false if it's a draw.
whowins: function()
{
  this.active = false;

  var winner0 = this.xbeatsy(this.round[0], this.round[1]);
  var winner1 = this.xbeatsy(this.round[1], this.round[0]);

},


We next have an If-else block. The first condition checks for a draw - meaning winner0 and winner1 are both false. In the Else block, we then have cases for if user beats computer or computer beats user.
whowins: function()
{
  this.active = false;

  var winner0 = this.xbeatsy(this.round[0], this.round[1]);
  var winner1 = this.xbeatsy(this.round[1], this.round[0]);

  if (!winner0 && !winner1)
  {

  }
  else
  {
    if (winner0)
    {

    }

    if (winner1)
    {

    }
  }

},


If it's a draw, we run showColor() twice, ensuring that both user and computer's circles have a grey outline.
whowins: function()
{
  this.active = false;

  var winner0 = this.xbeatsy(this.round[0], this.round[1]);
  var winner1 = this.xbeatsy(this.round[1], this.round[0]);

  if (!winner0 && !winner1)
  {
    this.showColor(0, "draw");
    this.showColor(1, "draw");

  }
  else
  {
    if (winner0)
    {

    }

    if (winner1)
    {

    }
  }
},


In the case of there being a winner, we display the correct colors too. And update the score array accordingly. At the end of it, because the score array was updated, we also run showScore().
whowins: function()
{
  this.active = false;

  var winner0 = this.xbeatsy(this.round[0], this.round[1]);
  var winner1 = this.xbeatsy(this.round[1], this.round[0]);

  if (!winner0 && !winner1)
  {
    this.showColor(0, "draw");
    this.showColor(1, "draw");
  }
  else
  {
    if (winner0)
    {
      this.score[0] ++;
      this.showColor(0, "win");
      this.showColor(1, "loss");

    }

    if (winner1)
    {
      this.score[1] ++;
      this.showColor(0, "loss");
      this.showColor(1, "win");

    }

    this.showScore();
  }
},


After that, we use the setTimeout() function, resetting the circle outlines to white and the symbols to question marks, and active to true, after 1 second.
whowins: function()
{
  this.active = false;

  var winner0 = this.xbeatsy(this.round[0], this.round[1]);
  var winner1 = this.xbeatsy(this.round[1], this.round[0]);

  if (!winner0 && !winner1)
  {
    this.showColor(0, "draw");
    this.showColor(1, "draw");
  }
  else
  {
    if (winner0)
    {
      this.score[0] ++;
      this.showColor(0, "win");
      this.showColor(1, "loss");
    }

    if (winner1)
    {
      this.score[1] ++;
      this.showColor(0, "loss");
      this.showColor(1, "win");
    }

    this.showScore();
  }

  setTimeout
  (
    ()=>
    {
      this.showSymbol(0, "");
      this.showSymbol(1, "");
      this.showColor(0, "end");
      this.showColor(1, "end");
      this.active = true;
    },
    1000
  );

},


Time to test this!

Click on Start. Select Scissors. The computer will randomly select its own symbol. In this case, it also selects Scissors, and it's a draw. See the grey outline?


Now select Rock. As you can see, the computer selects Paper and it's a loss. One point to computer.


Now select Paper. As you can see, the computer selects Rock and it's a win. One point to user.


Try selected Extended Mode. You'll see that the game stops immediately. And then select Lizard. Computer also selects Lizard, and it's a draw.


Now select Spock. Computer selects Paper. It's a loss! One point to Computer.


Auto Mode

We're going to write the code for Auto Mode now! This will be fun.

Remember in the start() method we checked if auto was true? Well, if so, we use setInterval() to run chooseSymbol() with "auto" passed in as an argument, every 1.5 seconds. To ensure that this can be disabled later with clearInterval(), we set this to the timer property.
start: function()
{
  var ddlRange = document.getElementById("ddlRange");
  this.range = ddlRange.value;

  var cbAuto = document.getElementById("cbAuto");
  this.auto = cbAuto.checked;

  var btnStart = document.getElementById("btnStart");
  var btnStop = document.getElementById("btnStop");

  btnStart.className = "topBtn hidden";
  btnStop.className = "topBtn";
  this.active = true;

  if (this.auto)
  {
    this.timer = setInterval
    (
      () =>
      {
        this.chooseSymbol("auto");
      },
      1500
    );

  }
  else
  {
    this.showOptions();
  }
},


In chooseSymbol(), we take that part where the first element of the round array is set to symbol, and encase it in the Else portion of an If-else block. The If block checks if symbol is "auto".
chooseSymbol: function(symbol)
{
  if (!this.active) return;

  if (symbol === "")
  {
    var ptr = Math.floor(Math.random() * this.range);
    this.round[1] = this.symbols[ptr].name;
    return;
  }
  else
  {
    if (symbol === "auto")
    {

    }
    else
    {

      this.round[0] = symbol;
    }
    
    this.chooseSymbol("");              
  }

  this.showSymbol(0, this.round[0]);
  this.showSymbol(1, this.round[1]);
  this.whowins();
},  


If it is, we write the code to randomly select a symbol for the user.
chooseSymbol: function(symbol)
{
  if (!this.active) return;

  if (symbol === "")
  {
    var ptr = Math.floor(Math.random() * this.range);
    this.round[1] = this.symbols[ptr].name;
    return;
  }
  else
  {
    if (symbol === "auto")
    {
      var ptr = Math.floor(Math.random() * this.range);
      this.round[0] = this.symbols[ptr].name;

    }
    else
    {
      this.round[0] = symbol;
    }
    
    this.chooseSymbol("");              
  }

  this.showSymbol(0, this.round[0]);
  this.showSymbol(1, this.round[1]);
  this.whowins();
},  


Now try checking Auto Mode and then clicking Start. You should see the game play by itself! The buttons aren't shown because you don't need them in Auto Mode.

That's about what I wrote for the coding test back then. Hopefully I've improved since!


Rock on!
T___T

No comments:

Post a Comment