void star games

* play * code * learn *


Flash Tutorials

puce Flash Yahtzee Game Tutorial 4 Back Start Over

Core Game Functionality. We have created all the classes involved in the game, we have set up the stage, and placed all the objects on it. We can now start to work towards the game functionality.

The first part we can focus on is the functionality of the rolls. For every combination, the dice are first rolled, then the player selects some of them, and then they are rolled again. This will have to be implemented in the class Game. Add two class attributes to this class called rollNr and scored. Initialize them both to 0 in the constructor.

Modify the function roll the following way: after the loop, increment the value of the variable rollNr. Then place the function call to the function roll for each die inside a conditional, where you test if the roll number is less than 2, and if it is, perform the call as it is, otherwise call the function roll with a parameter of value true. Place the whole function inside a conditional testing if the rollNr is less than 3.

Test this new functionality.

Next, we can organize the rolls and re-rolls at the level of the class game. In the function roll in this class, which is the one called by clicking the Roll button, we should allow the dice to be rolled only when the current number of rolls doesn't exceed 2. The scoring function will reset the number of rolls to 0. We'll assume that the first roll happen automatically, and then the player will be able to do it manually twice. At each roll, we'll increase the value of the variable rollNr. All we have to do is to place the entire code of the function roll inside the following conditional and add a statement incrementing this variable:

if (rollNr < 3) {
   rollNr++;

Once this is working, add an instruction to the function newGame where you reset this variable to 0.

Next, we can focus on the scoring functionality. The scoring itself can be implemented in the class ScoreCell, since that is where the mouse event will be directed, but it will need to retrieve the values of all the dice for this purpose. Thus we need a function in the class Game that can deliver these values. Since the dice can form any given combination regardless of the order in which they are, it would make sense for this function to sort these values in ascending order before communicating them back. This way, the scoring function can assume these values to be in oder.

In the class Game, add the following function.

public function retrieveDice() {
   var dice = new Array(5);
   for (var i=0; i<diceNr; i++) {
      dice[i] = diceArray[i].number;
   }
   dice.sort();
   return dice;
}

In the same class, we'll need a function that can be called once the score is computed to update the interface elements and re-roll the dice. Here is this function:

public function recordScore(scoreVal) {
   scored++;
   scoreArray[combNr-1].score += scoreVal;
   scoreArray[combNr-1].setScore(scoreArray[combNr-1].score);
   rollNr = 0;
   for (var i=0; i<diceNr; i++) {
      diceArray[i].setSprite(0);
  }
}

Going now to the class ScoreCell, since the previous function needs to access the score attribute, turn this into a public one. Then let's add a function that will be called on a mouse click event:

public function scoreMe(event:MouseEvent) {
   if (!used) {
      used = true;
      var dice = gameRef.retrieveDice();
      score = computeScore(dice);
      setScore(score);
      gameRef.recordScore(score);
   }
}

To test this function, add a function called computeScore taking one parameter and returning a constant. Then go back to the class constructor and add this line at the end to make the name box react to the mouse click, then add a similar one for the second box and for each of the text fields.

boxName.addEventListener(MouseEvent.CLICK, scoreMe);

At this point you should be able to test the functionality of the app.

There is one more step to do before we can start implementing the scoring: we don't want the Total box, the Upper Bonus box, and the Yahtzee Bonus box to react to mouse click, since these are not set by scoring a combination. Thus, place the four statements setting the mouse events in a conditional testing that the attribute combination does not have the values 7, 15, and 16.

The last thing to do is to go ahead and actually implement the scoring function. To organize this process, we start with a driver function that will select the type of evaluation to be done based on the combination number. Then this function will call one of a set of functions doing the actual computations. Test each of the scoring functions as soon as you can.

To get started, let's write a function that computes the score for the first six number combinations. To make this function more easily reusable, let's have the number passed in as a parameter. All we have to do here is go through the array of dice numbers and add the ones equal to the target number. This is an adaptation of a simple function "find" or "locate" that is present in many textbooks.

public function addTarget(dice, target) {
   var i, sum = 0;
   for (i=0; i<5; i++) {
      if (dice[i] == target) {
         sum += target;
      }
   }
   return sum;
}

Replace the statement returning a constant in the function computeScore in the class with the following code. This will be our driver function.

if (combination <= 6) {
   return addTarget(dice, combination);
}

The next one to implement would be the Three of a kind, but the same function can also be used for the four of a kind. Considering that the dice are ordered, we need to check for the longest contiguous sequence of equal dice. We will need two loops for this: one with a variable j marking the beginning of the sequence, and a second one with a variable i, counting the dice equal to the first one in the sequence. Then if the length f the sequence, given by the difference between i and j, is at least equal to the required length, we can return the sum of the dice equal to each other. Otherwise if we don't find such a sequence, we return 0.

public function countfAKind(dice, count) {
   var i, j=0, sum;
   while (j<5) {
      sum = 0;
      for (i=j; i<5 && dice[i]==dice[j]; i++) {
         sum += dice[j];
      }
      if (i-j >= count) {
         return sum;
      }
      j = i;
   }
   return 0;
}

Going back to the function computeScore, add the following else to the conditional. This contains a switch statement that will allow us to add more cases later.

else {
   switch (combination) {
      case 8:
      case 9: return countfAKind(dice, combination - 5);
   } }

We will not detail all of the scoring functions here, but will briefly discuss them. For the full house, a positive score can be returned either if the first 3 dice are equal to each other and the last two are equal to each other, or the other way around (first two, last 3). The small straight and large straight can be implemented under a single function that looks for contiguous sequences of a given length such that each dice in the sequence is one higher than the previous one. This function can be very similar to the function countOfAKind above, but special treatment must be made of the duplicate numbers, since they will break the contiguous sequence. A yahtzee combination can be tested with a function call to countOfAKind with the second parameter having the value 5, except that the return value should be 50 in all the cases and not the value returned by the function countOfAKind. The chance combination is a simple sum of all the dice numbers.

On your own:

Here is an example of the resulting program including these last suggestions.

Back Start Over