Julia Evans

a tiny whack-a-mole game

Hello! The other day I was learning about vue.js and I thought it was kind of fun so I made this whack-a-mole game (jsfiddle). (if you’re reading this in RSS / email you should maybe click on the post to see the game).

Rules:

  • moles are orange. click them to whack them
  • if you whack all the moles you win

Here, you can play it:

YOU WIN!!!

To make this game work I needed to:

  1. make event handlers that whack the mole when I click on an orange mole
  2. make the game disappear when the player wins
  3. automatically add new moles every 0.5 seconds to be whacked

Usually when I write Javascript I use jQuery and make a lot of callbacks and the code I write is sort of a disaster.

I’m excited about vue.js right now because it feels like an easier way to make tiny interactive javascript programs like this one.

Here is the display logic for this game! It is pretty simple! There is some HTML and it only displays the table if the game is still going (!won()).

The thing I like about this is – I just need to define a data structure for my game state (mole_grid). Each entry in that grid is 1 if there’s a mole there an 0 if there’s no mole. Vue.js automatically takes care of updating the HTML when my game state updates. This is also how React works but vue seems less complicated to me than React and I only want to do simple things anyway.

<div id="app"> <h2 v-if="won()"> YOU WIN!!! </h2> <table v-if="!won()"> <tr v-for="(array, x_coord) in mole_grid"> <td v-for="(value, y_coord) in array"> <div class="circle" v-on:click="squash(x_coord, y_coord)" v-bind:style="{ background: value ? 'orange' : 'black'}"></div> </td> </tr> </table> <!-- and some css to make the circles --> <style type="text/css"> .circle { border-radius: 50%; width: 50px; height: 50px; /* width and height can be anything, as long as they&rsquo;re equal */ }

javascript

Okay, but the app needs, like, callbacks and Javascript and stuff. Here’s all the javascript! It has a squash function and a won function. It feels about as simple as the code for a whack-a-mole game should be which is.. pretty simple.

var app = new Vue({
  el: '#app',
  data: {
    mole_grid: [ // this is the initial grid, with 2 moles on it
                 // all the game state is here basically!
      [0, 1, 0],
      [0, 0, 0],
      [1, 0, 1]
    ],
    has_won: false, // also store if the player won yet
  },
  methods: {
    set_mole: function(x_coord, y_coord, value) {
      this.mole_grid[x_coord][y_coord] = value;
      Vue.set(this.mole_grid, x_coord, this.mole_grid[x_coord]);
    },
    squash: function(x_coord, y_coord) {
      this.set_mole(x_coord, y_coord, 0);
    },
    // check if we won yet
    won: function () {
    	if (this.has_won) {
      	return true
      }
      var sum = 0;
      for (var i in this.mole_grid) {
      	for (var j in this.mole_grid[i]) {
        	sum += parseInt(this.mole_grid[i][j]);
        }
      }
      if (sum == 0) {
      	this.has_won = true;
      }
      return this.has_won;
    }
  }
})

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

// add a new mole to squash every 500ms
setInterval(function() {
console.log(app.won());
  app.set_mole(getRandomInt(0, app.mole_grid.length), getRandomInt(0, app.mole_grid[0].length), 1)
}, 500);

that’s all

I don’t have a lot of opinions about javascript libraries (my local npm installation is definitely broken), but I do like to make tiny interactive webpages on the internet occasionally and this seems like a nice way to do that.