* add rps teams project

* renamed project page

* fixed summary
This commit is contained in:
Peli de Halleux 2017-06-26 11:24:11 -07:00 committed by GitHub
parent 94753dfc4e
commit 39edf10ada
4 changed files with 229 additions and 2 deletions

View File

@ -23,9 +23,10 @@
* [Reaction Time](/projects/reaction-time)
* [States of Matter](/projects/states-of-matter)
* [Hot Or Cold](/projects/hot-or-cold)
* [Voting Machine](/projects/voting-machine)
* [Voting Machine](/projects/voting-machine)
* [Infection](/projects/infection)
* [Fireflies](/projects/fireflies)
* [Rock Paper Scissors Teams](/projects/rps-teams)
* [Inchworm](/projects/inchworm)
* [Milk Carton Robot](/projects/milk-carton-robot)
* [Milk monster](/projects/milky-monster)

View File

@ -52,6 +52,10 @@ Fun games to build with your @boardname@.
"name": "Voting Machine",
"url": "/projects/voting-machine",
"imageUrl": "/static/mb/projects/voting-machine.png"
}, {
"name": "Rock Paper Scissors Teams",
"url": "/projects/rps-teams",
"imageUrl": "/static/mb/projects/rpsteams.png"
}]
```
@ -158,4 +162,5 @@ Fun games to build with your @boardname@.
[Flashing Heart](/projects/flashing-heart), [Smiley Buttons](/projects/smiley-buttons), [Love Meter](/projects/love-meter), [Rock Paper Scissors](/projects/rock-paper-scissors), [Compass](/projects/compass), [Hack your headphones](/projects/hack-your-headphones), [Banana keyboard](/projects/banana-keyboard), [Telegraph](/projects/telegraph), [Guitar](/projects/guitar), [Wallet](/projects/wallet), [Watch](/projects/watch),
[Milk Monster](/projects/milky-monster), [Karel the LED](/projects/karel), [Infection](/projects/infection), [Voting Machine](/projects/voting-machine)
[Fireflies](/projects/fireflies), [Soil Moisture](/projects/soil-moisture),
[States Of Matter](/projects/states-of-matter), [Reaction Time](/projects/reaction-time)
[States Of Matter](/projects/states-of-matter), [Reaction Time](/projects/reaction-time),
[Rock Paper Scissors Teams](/projects/rps-teams)

221
docs/projects/rps-teams.md Normal file
View File

@ -0,0 +1,221 @@
# Rock Paper Scissors Teams
### ~avatar avatar
Massively multi-player rock paper scissors!
### ~
Playing rock paper scissors is usually a two player game... but it works with much more players too!
When playing with more than two players, it becomes a team game: all players shake at the same time,
then the number of **rock**, **paper**, **scissors** is tallied between all the players.
The team with the most players wins the game.
Starting from the [basic version of the RPS game](/projects/rock-paper-scissors), we are going
to change the code so that the @boardname@ counts and displays the number of players in the same team.
Using the **radio** communication, the @boardname@ will send its status and receive the status of other boards.
Let's get started!
## Starting blocks
Let's start form a . The basic version picks the weapon in a ``|on shake|``
event and display an icon accordingly. Take a peek at the code below to refresh your memory on that game.
```blocks
let weapon = 0
input.onGesture(Gesture.Shake, () => {
weapon = Math.random(3)
if (weapon == 0) {
basic.showIcon(IconNames.SmallSquare)
} else if (weapon == 1) {
basic.showIcon(IconNames.Square)
} else {
basic.showIcon(IconNames.Scissors)
}
});
```
## Step 1: Refactoring the rendering
**Refactoring** is a funny word used in coding which pretty much means ``reorganizing``. In this case,
we are going to move the code that displays the rock/paper/scissor icon into its own ``|forever|`` loop.
```blocks
let weapon = 0
input.onGesture(Gesture.Shake, () => {
weapon = Math.random(3)
})
basic.forever(() => {
if (weapon == 0) {
basic.showIcon(IconNames.SmallSquare)
} else if (weapon == 1) {
basic.showIcon(IconNames.Square)
} else {
basic.showIcon(IconNames.Scissors)
}
});
```
## Step 2: send status via radio
We send the value of ``weapon`` via radio to other @boardname@ in the ``|forever|``.
Since radio packet may or may not arrive, it's a good idea to keep sending them.
We also set the radio group and send the device serial number (a number that uniquely identifies a @boardname@) as we will need that later.
```blocks
let weapon = 0
input.onGesture(Gesture.Shake, () => {
weapon = Math.random(3)
})
basic.forever(() => {
radio.sendNumber(weapon)
if (weapon == 0) {
basic.showIcon(IconNames.SmallSquare)
} else if (weapon == 1) {
basic.showIcon(IconNames.Square)
} else {
basic.showIcon(IconNames.Scissors)
}
});
radio.setGroup(10)
radio.setTransmitSerialNumber(true)
```
## Step 3: the team roster
So all players are constantly broadcasting which face they picked to other players.
Let's add the code that receives those status and counts them.
We are going to add an **Array** variable that contains all the players in the same team as the current player.
That array, named ``players``, is like your team roster: it contains the list of @boardname@ serial numbers
that have the same weapon as you.
```block
let players: number[] = [0]
```
## Step 4: Receiving a message (part 1)
In an the ``|on radio received|`` event, we receive the status from another @boardname@. Click on the **gearwheel*
to add the ``serial`` parameter as we will need it to identify who sent that packet.
We compute three values from the data received:
* ``match``, a boolean value indicating whether the weapon of the other @boardname@ matches our current weapon
* ``player_index``, the position in the array of the other board's serial number. It will be -1 if it is not in the array
* ``found``, a boolean value indicating whether the @boardname@ serial number is part of the ``players`` array
```blocks
let match = false
let player_index = 0
let players: number[] = [0]
let weapon = 0
let found = false
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
match = weapon == receivedNumber
player_index = players.indexOf(serial)
found = player_index >= 0
})
```
## Step 5: Receiving a message (part 2)
There are two cases that we need to handle when looking at ``match`` and ``found``:
* **if** we have a ``match`` **and** the player is ``not found`` in the list, **then** we **add** it to ``players``
* **if** we don't have a ``match`` **and** the player is ``found`` in the list, **then** we **remove** it from ``players``
We turn the two rules above into two ``if`` statement where the serial number is added or removed.
```blocks
let match = false
let player_index = 0
let players: number[] = [0]
let weapon = 0
let found = false
let temp = 0
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
match = weapon == receivedNumber
player_index = players.indexOf(serial)
found = player_index >= 0
if (match && !(found)) {
players.push(serial)
}
if (!(match) && found) {
temp = players.removeAt(player_index)
}
})
```
## Step 6: reseting the team
What if another player would leave the game? He would stop broadcasting its status and it would stay in our
list of players. To avoid this problem, we reset the ``players`` array each time we shake:
```block
input.onGesture(Gesture.Shake, () => {
let players: number[] = [0]
let weapon = Math.random(3)
})
```
## Step 7: showing team score
The team score is the number of players in that team... which boils down to the ``length`` of the ``players``
array. We add a ``|show number|`` block in the ``|forever|`` loop to display it.
```block
let players: number[] = [0]
let weapon = 0
basic.forever(() => {
basic.showNumber(players.length)
})
```
## The final code
Now it's time to glue all together the pieces of our program.
Go carefully through all the steps and assemble the various features. Eventually, it should look
like the following program. Download it and plays with your friend**ssss**!
```blocks
let temp = 0
let found = false
let player_index = 0
let weapon = 0
let match = false
let players: number[] = []
input.onGesture(Gesture.Shake, () => {
players = [0]
weapon = Math.random(3)
})
radio.onDataPacketReceived( ({ receivedNumber, serial }) => {
match = weapon == receivedNumber
player_index = players.indexOf(serial)
found = player_index >= 0
if (match && !(found)) {
players.push(serial)
}
if (!(match) && found) {
temp = players.removeAt(player_index)
}
})
basic.forever(() => {
radio.sendNumber(weapon)
if (weapon == 0) {
basic.showIcon(IconNames.SmallSquare)
} else if (weapon == 1) {
basic.showIcon(IconNames.Square)
} else {
basic.showIcon(IconNames.Scissors)
}
basic.showNumber(players.length)
})
players = [0]
radio.setGroup(10)
radio.setTransmitSerialNumber(true)
```

BIN
docs/static/mb/projects/rpsteams.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB