Rock Paper Scissors Lizard Spock

Simple, class-based implementation of the classic Rock Paper Scissors Lizard Spock. Demonstrates JavaScript class inheritance. Has grammatically-correct outcome text. Shows win percentage. May add smarter AI in the future.

by Taylor Lopez

HTML

<div class="game">
  <span style="font-size: 20px; font-weight: bold;">Pick Your Weapon</span>
  <br />
  <div class="weapons">
    <div class="weapon Rock" title="Rock"></div>
    <div class="weapon Paper" title="Paper"></div>
    <div class="weapon Scissors" title="Scissors"></div>
    <div class="weapon Lizard" title="Lizard"></div>
    <div class="weapon Spock" title="Spock"></div>
  </div>
  <br />
  <br />
  <div class="player">
    <p class="player_name">Player</p>
    <div class="weap_output p1 Lizard"></div>
    <p class="p1_score score"></p>
  </div>
  <span class="vs">&nbsp;VS.</span>
  <div class="player">
    <p class="player_name">Computer</p>
    <div class="weap_output p2 Spock"></div>
    <p class="comp_score score"></p>
  </div>
  <br />
  <span class="percentage"></span>
  <br />
  <p class="outcome">Welcome to Rock, Paper, Scissors, Lizard, Spock<br/>&nbsp;</p>
  <div class="reset">Reset Scores</div>
</div>

CSS

body {
  margin-top: 50px;
  margin-bottom: 50px;
  font-family: Arial, sans;
  color: white;
  background-color: #222;
  opacity: 1;
}

body:after {
  display: none;
  /* Preload the images to avoid flicker on hover */
  content: url('http://picoplex.net/games/rpslp/rock.png') url('http://picoplex.net/games/rpslp/rock2.png') url('http://picoplex.net/games/rpslp/paper.png') url('http://picoplex.net/games/rpslp/paper2.png') url('http://picoplex.net/games/rpslp/scissors.png') url('http://picoplex.net/games/rpslp/scissors2.png') url('http://picoplex.net/games/rpslp/lizard.png') url('http://picoplex.net/games/rpslp/lizard2.png') url('http://picoplex.net/games/rpslp/spock.png') url('http://picoplex.net/games/rpslp/spock2.png');
}

.game {
  text-align: center;
}

.weapons {
  margin-top: 10px;
  display: inline-block;
  position: relative;
  height: 224.66px;
}

.weapon {
  position: absolute;
  width: 100px;
  height: 100px;
  margin-left: -50px;
  background-size: cover;
  border: none;
  cursor: pointer;
  display: inline-block;
  border-radius: 50%;
  border: solid 3px rgba(0, 0, 0, 0);
  transform: translate(-3px, -3px);
  background-repeat: no-repeat;
}

.weapon:hover {
  border-color: rgb(20, 153, 224);
}
.worse {
  border-color: rgb(227, 85, 17) !important;
}
.better {
  border-color: rgb(100, 200, 0) !important;
}

/* I did the maths. Yay trig. */
.weapon.Lizard { left: -60px; top: 0 }
.weapon.Spock { left: 60px; top: 0 }
.weapon.Rock { left: -97.1px; top: 114.12px }
.weapon.Paper { left: 97.1px; top: 114.12px }
.weapon.Scissors { left: 0px; top: 184.66px }

.weap_output {
  margin: 5px;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background-size: cover;
  border: solid 6px rgba(0, 0, 0, 0);
  background-repeat: no-repeat;
}

.Rock { background-image: url('http://picoplex.net/games/rpslp/rock.png') }
.weapon.Rock:hover { background-image: url('http://picoplex.net/games/rpslp/rock2.png') }
.Paper { background-image:...

JavaScript

// Rock Paper Scissors Lizard Spock
// images from http://picoplex.net/

var weapons = {};
var p1Wins = 0;
var compWins = 0;
var numRounds = 0;
  
function main() {
  weapons = { "Rock": new Rock(),
              "Paper": new Paper(),
              "Scissors": new Scissors(),
              "Lizard": new Lizard(),
              "Spock": new Spock() };
  resetScores();
  
  $(".weapon").click(function(){
    // get the selected weapon object and pass it to the main game function as the player's input
    var weapstr = $(this).attr("class").split(/\s+/)[1];
    var p1Weapon = weapons[weapstr];
    rpsls(p1Weapon);
  }).on("mouseover", function(){
    // Get the hovered weapon name
    var thisWeaponName = $(this).attr("class").split(/\s+/)[1];
    
    // Get all the weapon dom elements and begin removing classes that aren't "winners" against the hovered weapon.
    var $winners = $(".weapon").not("."+thisWeaponName);
    
    // The names of the weapons that lose to the hovered weapon
    var worse = Object.keys(weapons[thisWeaponName]._losers);
    for (var i = 0; i < worse.length; i++) {
    
      // Adds the green circle around items the hovered will beat
      $(".weapon." + worse[i]).addClass("better");
      
      // excludes this weapon from the "winners" against the hovered weapon
      $winners = $winners.not("."+worse[i]);
    }
    
    // Add a red circle around weapons that aren't the hovered weapon or in the selected weapon's "losers" list
    $winners.addClass("worse");
  }).on("mouseout", function(){
    // Clear 'em all out
    $(".weapon").removeClass("better worse");
  });
  
  $(".reset").click(function(){ resetScores(); });
  
  // Two computers play 10,000 times.
  // for (var i = 0; i < 10000; i++) rpsls(weapons[Object.keys(weapons)[Math.floor(Math.random()*5)]]);
}

function rpsls(p1Weapon) {
  // Get the computer's "chosen weapon"
  var compWeapIdx = Math.floor(Math.random()*5);
  var compWeapon =...