Start Here: Zero to JavaScript — Rolling Dices, built-in Math functions, and Class

Jack Yeh
TeamZeroLabs
Published in
7 min readNov 20, 2020

Bite size Javascript Lesson you can finish in 3–5 minutes!
Missed the previous lesson on Data Types? Go here.

Photo by Robert Coelho on Unsplash

Context: You need to learn JavaScript in Less than 3 Weeks for a job interview

We have all been there. I did Python and Java in college, and during the second job interview of my life, my then-boss asked me:

Can you do any frontend programming? Do you know any Javascript?

I answered honestly that I don’t know any JavaScript.

Ok, read this book and come learn on the job

Before I know it, I have been doing JavaScript for 12 years!
In today’s lesson, I will teach you about Rolling Dices/Built-in Math Functions/Class.

Before Jumping In

Every example in this article can be run inside Chrome’s console, which you can access by:

  • Open a new Blank Tab
  • Right click and select Inspect
  • Select the Console Tab, see a little blue > arrow
  • Let’s cook.

Build-Your-Own In Browser Casino

Here is a challenge for you from yesterday’s lesson:

Write a function that rolls 3 dices, and print the result to the console. If user gets all 1s or all 6s, print “All the Dots”.

It should look like the following when typed into Chrome:

function rollDices() { ... }> rollDices()
< "1, 4, 5"
> rollDices()
< "2, 1, 3"
> rollDices()
< "All the Dots"
> rollDices()
< "3, 3, 3"

Before we can roll three dices, we first need to figure out how to roll one dice.

We know how to write functions with Calculator operators like +, — , * , /

How do we get a random number to return though?

Introducing Math.random()

> Math.random()
< 0.958177795523361
> Math.random()
< 0.6310123393722489
> Math.random()
< 0.25878621218521314
> Math.random()
< 0.21485672365359743

Here we are using a function called random(), which comes from the Math object. If you type in Math by itself, you will see the following goodies:

Loads of functions, at our disposal!

We are interested in writing a function that returns a random number from this sequence [1, 2, 3, 4, 5, 6], given that Math.random() returns a number between 0 and 1 (it can generate 0, but will always be less than 1).

We can try to multiply Math.random() with 6, which should return a number between 0 to 5.9

This is not a whole number (also known as integers), how do we remove the decimal portion?

This is where the second built-in function can be used: Math.floor()

Math.floor() takes a number and remove the decimal portion. Try these examples in the console to see its effects:

> Math.floor(0.5)
< 0
> Math.floor(1.9999999)
< 1
> Math.floor(3.0000000001)
< 3

So we write the following:

> function rollDice() {
return Math.floor(Math.random() * 6);
}

undefined
> rollDice()
< 1
> rollDice()
< 5
> rollDice()
< 0
> rollDice()
< 2
> rollDice()
< 0
> rollDice()
< 3
> rollDice()

Hmm, not quite. It’s returning from 0 to 5, not 1 to 6.

Ok, just add one before returning it!

> function rollDice() {
return Math.floor(Math.random() * 6) + 1;
}

undefined
> rollDice()
< 2
> rollDice()
< 2
> rollDice()
< 4
> rollDice()
< 6
> rollDice()
< 1
> rollDice()
< 1

Easy.

Roll it Three Times

> function rollDices() {
return rollDice() + ", " + rollDice() + ", " + rollDice();
}

undefined
> rollDices()
< "2, 2, 1"
> rollDices()
< "4, 2, 3"
> rollDices()
< "5, 6, 5"
> rollDices()
< "2, 1, 4"
> rollDices()
< "5, 3, 5"

Not bad.

But, it does not return the string “All the Dots” when we roll all 1s or 6s. We will only get a B on this quiz.

If you are trying to fix it quickly, you could do this solution:

> function rollDices() {
var result = rollDice() + ", " + rollDice() + ", " + rollDice();
if (result === "1, 1, 1") {
return "All the Dots";
} else if (result === "6, 6, 6") {
return "All the Dots";
} else {
return result;
}
}
< undefined
> for (var i = 0; i < 20; ++i) { console.log(rollDices()); }
5, 3, 1
< VM1953:1 2, 6, 1
< VM1953:1 2, 1, 3
< VM1953:1 1, 1, 5
< VM1953:1 6, 1, 1
< VM1953:1 6, 3, 3
< VM1953:1 6, 4, 5
< VM1953:1 1, 2, 5
< VM1953:1 All the Dots
< VM1953:1 6, 6, 5
< VM1953:1 2, 3, 6
< VM1953:1 3, 1, 5
< VM1953:1 3, 2, 6
< VM1953:1 5, 6, 2
< VM1953:1 4, 2, 3
< VM1953:1 1, 5, 6
< VM1953:1 1, 5, 4
< VM1953:1 3, 4, 2
< VM1953:1 4, 4, 2

We fixed it! And we have proof as well. We loop 20 times and keep rolling them dices.

If this is a homework assignment or a test, you might move on to the next challenge already. However, in real life you will be asked follow-up questions by different people:

  • Customer: I want to roll 5 dices at the same time.
  • Boss: Can you support 20 sided dice?
  • Product manager: Can it say Royal Flush when you roll three consecutive numbers?
  • Big Data Coworker: Can we save rolling result to a database?

Implementing all of these requirements will make the code way more complicated. You gotta figure out when is the proper time to close the book on a codebase. Or else, you will be stuck maintaining the same code for a long time!

To make some of these change requests simple, next we will cover the usage of classes.

What are Classes?

A Class is a blueprint used to create more copies of itself. This sounds abstract, so let’s look at a couple of examples:

> class Dice {
constructor(sides){
this.sides = sides;
}
}

< undefined
> var myDice = new Dice(6);
< undefined
> console.log("My dice has " + myDice.sides + " sides!")
< VM2319:1 My dice has 6 sides!
< undefined

Class syntax looks like this:

class Name {
constructor(0 - N parameters){
initialization step1;
initialization step2;
initialization step3;
...
initialization stepN;
}
memberFunction(0 - N parameters) {
function step1;
...
function stepN;
}
// As many member function as you like.
}

To make a copy of the class, we type var myDice = new Dice(6); , and at this point we have a copy with sides = 6 stored inside.

You can see that it is basically an object:

> myDice
< Dice {sides: 6}

So we can store multiple fields inside a copy, what’s the big deal?

The big deal is that we can attach functions to a Class, and every copy can use these functions:

> class Dice {
constructor(sides){
this.sides = sides;
}
roll() {
return Math.floor(Math.random() * this.sides) + 1;
}
}

< undefined
> myDice = new Dice(6);
< Dice {sides: 6}
> myDice.roll();
< 6
> myDice.roll();
< 2
> myDice.roll();
< 6
> myDice.roll();
< 4
> myDice.roll();
< 5

This seems like a longer way to write functions compare to before. Wait… you can pass any number of sides into the instance!

> var myBossDice = new Dice(20)
< undefined
> myBossDice.roll()
< 8
> myBossDice.roll()
< 3
> myBossDice.roll()
< 15
> myBossDice.roll()
< 2
> myBossDice.roll()
< 1

Not too shabby. What about the customer’s request to play with 5 dices at the same time?

We could modify the original code to rollDice() 5 times and check for “1, 1, 1, 1, 1” and “6, 6, 6, 6, 6”, but it’s not that clean.

Maybe we can write another class to represent a bunch of Dices

> class Hand {
constructor(dices) {
this.dices = dices;
}
roll() {
var result = []
for (var i = 0; i < this.dices.length; ++i) {
result.push(this.dices[i].roll());
}
if (result.every((num) => num === 1)) {
return "All the Dots";
} else if (result.every((num) => num === 6)) {
return "All the Dots";
} else {
return result.join(", ");
}
}
}

< undefined
> var customerHand = new Hand([new Dice(6), new Dice(6), new Dice(6), new Dice(6), new Dice(6)]);
< undefined
> customerHand.roll();
< "5, 3, 1, 4, 2"

The Hand class takes in a list of Dices to start.

When we call the roll() method, it will loop over each dice, roll it, and collect the result into our Array.

Did you notice that we are calling several methods on the Array?

  • push() — Adds a data to the end of the list
  • every() — Runs an inline function and return true, if that function returns true for each item in the list.
  • join() — Convert all items to String and put the input strings between each gap.

An Array is a copy of a Class as well! That is how it is able to carry additional member functions.

The Big Idea Behind these concepts

So, what’s the big deal?

JavaScript enjoys reminding us that built-in functions and Classes are everywhere. If we make a habit of using them, we stand to save a lot of time rather than writing them ourselves.

You won’t get very far if you do not stand on the shoulder of giants.

By combining functions/loops/if-else, we can make functions do anything we want, but it can become complicated quickly as new feature requests come in.

You will find that some of these requests are about changing values that were constants in our original functions: This is a good time to package them together into classes.

Simple Rule of Thumb: If we wish to change our function behaviors, you can often satisfy their request by converting it into a class and receive the changes through input parameters.

Lastly, rather than writing one giant function/class that does everything, our code is more readable if we split them into smaller pieces (rollDice() + rollDices(), or class Dice{} + class Hand).

You will often find that these smaller functions and classes can still stand on their own. They are similar to smaller components at the hardware store, ready to be assemble into bigger pieces of functionalities.

We are just a couple of lessons away from interacting with the entire internet and acing that interview

In the next article: we will cover callback/fetching data/working with JSON!
Thanks for reading.

--

--

Jack Yeh
TeamZeroLabs

I monitor your full stack deployment in production, so you can sleep at night. Docker | Kubernetes | AWS | Prometheus | Grafana