In this post, I will show how to the Yahtzee dice game and keep the game scoring all within the Nextion Logic without the need for an external microprocessor. As we go through the process of creating this game, I will deal with a few techniques that may be useful in your projects.  You can visit Wikipedia to learn more about the Yahtzee dice game.

Materials Used

– Nextion Editor v0.53
– Enhanced Nextion 3.5″ Model NX4832K035_011
– A few graphics, and 1 numbers ZI font 12×24

Step 1

So as this is a dice game, the first thing we will need is 6 dice sides and two hold indicators, and the game board felt.  We will use 1 numbers ZI font 12×24. To help you get started, these can be downloaded in the Yahtzee_resources.zip file.

Load the resource pictures into the Picture Resources Pane in the following Order: the game board YahtzeeA.png as resource 0, then the six dice values pictures d1.png (as 1) d2.png (as 2) d3.png (as 3) d4.png (as 4) d5.png (as 5) d6.png (as 6), and finally the two hold indicators h0.png (as 7) and h1.png (as 8).

Load the 12×24 ZI font as the only font needed for this project.

Step 2

So the next thing we need is a score pad for our Yahtzee game. The score pad traditionally would require many labels. On the upper half: Ones, Twos, Threes, Fours, Fives, Sixes, a Subtotal for the upper half, a Bonus when earned, an total for Upper, and on the lower half: 3 of a Kind, 4 of a Kind, Full House, Small Straight, Large Straight, Yahtzee, and Chance, a Lower Total, a carry over for the Upper Total and lastly the Final Score. Now we could have used 19 Text Components for these labels. You will find it much easier to include the static non-changing items into your page background image, such as the labels, the game board name, an any place holders.

To make the next task of placing our Number components easier, lets load the background image in as our page background by setting the page .sta field to image double click the .pic value and select 0, and OK.

We will need 19 Number components for our dynamic numbers (1 for each of the above labels) and finally 1 for the number of throws remaining. These can not be embedded into the background image. To make it easier for our coding later, the number components should be created with the following order. Ones (n0 id 1), Twos (n1 id 2), Threes (n2 id 3), Fours (n3 id 4), Fives (n4 id 5), Sixes (n5 id 6), Bonus (n6 id 7), 3 of a Kind (n7 id 8), 4 of a Kind (n8 id 9), Full House (n9 id 10), Short Straight (n10 id 11), Large Straight (n11 id 12), Yahtzee (n12 id 13), Chance (n13 id 14), Subtotal (n14 id 15), Upper (n15 id 16), Lower Total (n16 id 17), Upper Total (n17 id 18), Final Score (n18 id 19), and lastly our throws number (n19 id 20).

For all score Number components (n0 to n18), ensure .sta set to crop image, .picc set to 0, .isbr set to false, .w set to 36, .h set to 20, .ycen set to Up, .xcen set to Right, .font set to 0, and .pco set to 65520. The left Upper column of Numbers set .x to 189 the Right Lower Column with Final Score set .x to 424. For n19, ensure .sta set to crop image, .picc set to 0, .isbr set to false, .w set to 12, .h set to 20, .ycen set to Up, .xcen set to Right, .font set to 0, .x to 24, .y to 248 and .pco set to 65520. Here we set the .sta to crop image to allow the board to bleed through. We resize the Number components and set .xcen and .ycen to reduce the amount of time needed to render the font.

Next we will need 5 Picture Components for the top faces of our five dice. Dice 1 (p0 id 21) 2 (p1 id 22) 3 (p2 id 23) 4 (p3 id 24) and 5 (p4 id 25). Preload these with picture resource 1 by double clicking the .pic value select picture 1 and OK. Set the .y value to 252 and place left to right over the appropriate dice spot in the game board background. We will do similar for our 5 hold/no-hold Picture Components that go below the dice. Create Holder 1 (p5 id 26) 2 (p6 id 27) 3 (p7 id 28) 4 (p8 id 29) and 5 (p9 id 30). Preload these 5 with the green no-hold picture resource setting .pic to 7, double clicking the .pic value selecting picture 7 and OK. Then set .y to 301 and place in the hold/no-hold location on the game board below the dice. Note that the Picture component also has a Press and Release event, so we will use these events as a more efficient form of a button.

Next we will need 10 Variables Components for our dice values and hold/no-hold states. Create the 5 dice value Variables 1 (dv1 id 31) 2 (dv2 id 32) 3 (dv3 id 33) 4 (dv4 id 34) 5 (dv5 id 35), and the 5 hold/no-hold state Variables 1 (dh1 id 36) 2 (dh2 id 37) 3 (dh3 id 38) 4 (dh4 id 39) 5 (dh5 id 40).

We will need 5 more Variable components to assist with the game play, we can create these now, they are: Throws Remaining (tr id 41), Plays Remaining (pr id 42), Move Playable (mp id 43), and two general purpose variables (dr id 44) and (nv id 45).

Lastly we will need two Hotspots. Hotspot for the Throw (m0 id 46) with .x 15, .y 281, .w 72 and .h 32 and a final Hotspot as a code holder with .h 20, .w 20 and placed off to the side out of the way. Hotspots make an interesting local code holder that can be accessed by the click instruction.

Throughout this tutorial we will make use the b[.id] Component array to iterate by formula to manipulate our component values. This will save many lines of code.

Step 3

Now that we have all our components placed, time to dig in and do the code.

In the page PreInitialize Event
– set our range for random for dice
– set Throws Remaining to 3 and Plays Remaining to 13
– then set all scorable Number components to green (non-green prevented from play)
– we are now ready to play the game

randset 0,65535
tr.val=3
pr.val=13
for(sys0=1;sys0<=6;sys0++)
{
  b[sys0].pco=2016
}
for(sys0=8;sys0<=14;sys0++)
{
  b[sys0].pco=2016
}

In the Final Score n18 Release Event
- if there are no Plays Remaining then call re-enter page to restart the game.

if(pr.val==0)
{
  page 0
}

In the Throw Hotspot m0 Release Event
- animate the dice rolling 10x, slowing down each round
- then transfer Dice Values and store in variables dv*
- set Move Playable to 1 (can now be played)
- decrease Throws Remaining and update display

if(tr.val>0)
{
  for(sys2=0;sys2<=10;sys2++)
  {
    for(sys1=0;sys1<=4;sys1++)
    {
      if(b[36+sys1].val==0)
      {
        b[21+sys1].pic=rand%6+1
      }
    }
    delay=25*sys2
  }
  for(sys2=0;sys2<=4;sys2++)
  {
    b[31+sys2].val=b[21+sys2].pic
  }
  mp.val=1
  tr.val-=1
  n19.val=tr.val
}

Step 4

In the code holder Hotspot m1 Release Event
- this code is run with every click m1,0 instruction after scoring
- clear Move Playable, reduce Plays Remaining, reset Throws Remaining to 3 and display.
- then clear dice hold variables and reset the dice hold pictures
- after this add up the upper into SubTotal, evaluate if Bonus has been earned
- place the upper totals into Upper and Upper Total
- Tally the lower totals into Lower Total
- if the game is over the tally into the Final Score

mp.val=0
pr.val-=1
tr.val=3
n19.val=tr.val
for(sys0=0;sys0<=4;sys0++)
{
  b[36+sys0].val=0
  b[26+sys0].pic=7
}
sys1=0
sys2=0
for(sys0=1;sys0<=6;sys0++)
{
  sys1=sys1+b[sys0].val
}
n14.val=sys1
if(sys1>=63)
{
  n6.val=35
  sys1+=35
}
n15.val=sys1
n17.val=sys1
for(sys0=8;sys0<=14;sys0++)
{
  sys2=sys2+b[sys0].val
}
n16.val=sys2
if(pr.val==0)
{
  n18.val=n16.val+n17.val
  tr.val=0
  n19.val=tr.val
  n18.pco=2016
}

Step 5

Toggling the Dice Hold/No-Hold in the Dice Release Events

Dice 1: p0 Release Event
- toggles the dice hold variable and sets indicator below die

if(tr.val>0)
{
  if(tr.val<3)
  {
    dh1.val=1-dh1.val
    p5.pic=7+dh1.val
  }
}

Dice 2: p1 Release Event
- toggles the dice hold variable and sets indicator below die

if(tr.val>0)
{
  if(tr.val<3)
  {
    dh2.val=1-dh2.val
    p6.pic=7+dh2.val
  }
}

Dice 3: p2 Release Event
- toggles the dice hold variable and sets indicator below die

if(tr.val>0)
{
  if(tr.val<3)
  {
    dh3.val=1-dh3.val
    p7.pic=7+dh3.val
  }
}

Dice 4: p3 Release Event
- toggles the dice hold variable and sets indicator below die

if(tr.val>0)
{
  if(tr.val<3)
  {
    dh4.val=1-dh4.val
    p8.pic=7+dh4.val
  }
}

Dice 5: p4 Release Event
- toggles the dice hold variable and sets indicator below die

if(tr.val>0)
{
  if(tr.val<3)
  {
    dh5.val=1-dh5.val
    p9.pic=7+dh5.val
  }
}

Step 6

Scoring the Upper Section Dice counts

Ones: n0 Release Event
- when scoring Ones, only dice value of 1 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n0.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==1)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n0.val=sys1
    n0.pco=65520
    click m1,0
  }
}

Twos: n1 Release Event
- when scoring Twos, only dice value of 2 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n1.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==2)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n1.val=sys1
    n1.pco=65520
    click m1,0
  }
}

Threes: n2 Release Event
- when scoring Threes, only dice value of 3 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n2.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==3)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n2.val=sys1
    n2.pco=65520
    click m1,0
  }
}

Fours: n3 Release Event
- when scoring Fours, only dice value of 4 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n3.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==4)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n3.val=sys1
    n3.pco=65520
    click m1,0
  }
}

Fives: n4 Release Event
- when scoring Fives, only dice value of 5 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n4.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==5)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n4.val=sys1
    n4.pco=65520
    click m1,0
  }
}

Sixes: n5 Release Event
- when scoring Sixes, only dice value of 6 count towards the score
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n5.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==6)
      {
        sys1=sys1+b[31+sys0].val
      }
    }
    n5.val=sys1
    n5.pco=65520
    click m1,0
  }
}

Step 7

3-of-a-Kind: n7 Release Event
- In order to score 3-of-a-Kind, 3 dice must be the same
- when the condition is met, we score all dice, set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n7.pco==2016)
  {
    n7.val=0
    dr.val=0
    for(sys0=0;sys0<=2;sys0++)
    {
      sys2=0
      for(sys1=0;sys1<=4;sys1++)
      {
        if(b[31+sys1].val==b[31+sys0].val)
        {
          sys2=sys2+1
        }
      }
      if(sys2>=3)
      {
        dr.val=1
      }
    }
    if(dr.val==1)
    {
      sys2=0
      for(sys0=0;sys0<=4;sys0++)
      {
        sys2=sys2+b[31+sys0].val
      }
      n7.val=sys2
    }
    n7.pco=65520
    click m1,0
  }
}

4-of-a-Kind: n8 Release Event
- In order to score 4-of-a-Kind, 4 dice must be the same
- when the condition is met, we score all dice, set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n8.pco==2016)
  {
    n8.val=0
    dr.val=0
    for(sys0=0;sys0<=1;sys0++)
    {
      sys2=0
      for(sys1=0;sys1<=4;sys1++)
      {
        if(b[31+sys1].val==b[31+sys0].val)
        {
          sys2=sys2+1
        }
      }
      if(sys2>=4)
      {
        dr.val=1
      }
    }
    if(dr.val==1)
    {
      sys2=0
      for(sys0=0;sys0<=4;sys0++)
      {
        sys2=sys2+b[31+sys0].val
      }
      n8.val=sys2
    }
    n8.pco=65520
    click m1,0
  }
}

Step 8

Full House: n9 Release Event
- here we count how many dice have the same value of the first die.
- when the die is not equal to the first die store in nv and set dr to 1
- if dr=1 we have more than 1 value, we then count for the second value
- in this manner we can test for a Full House (3 of 1, 2 of another, or 5 the same)
- when the condition is met, we score 25, set bco to yellow and call m1 Release.

if(mp.val==1)
{
  if(n9.pco==2016)
  {
    n9.val=0
    sys1=0
    sys2=0
    dr.val=0
    for(sys0=0;sys0<=4;sys0++)
    {
      if(b[31+sys0].val==b[31].val)
      {
        sys1=sys1+1
      }else
      {
        nv.val=b[31+sys0].val
        dr.val=1
      }
    }
    if(dr.val==1)
    {
      for(sys0=0;sys0<=4;sys0++)
      {
        if(b[31+sys0].val==nv.val)
        {
          sys2=sys2+1
        }
      }
    }
    if(sys1==5)
    {
      n9.val=25
    }else
    {
      if(sys1==3)
      {
        if(sys2==2)
        {
          n9.val=25
        }
      }
      if(sys1==2)
      {
        if(sys2==3)
        {
          n9.val=25
        }
      }
    }
    n9.pco=65520
    click m1,0
  }
}

Step 9

Short Straight: n10 Release Code
- In order to score a short straight we are looking for a run of 4
- if found our formula of multiplying by 2 will produce
- 60 for 1-2-3-4, 120 for 2-3-4-5, or 240 for 3-4-5-6
- when the condition is met, we score 30, set bco to yellow and call m1 Release

if(mp.val==1)
{
  if(n10.pco==2016)
  {
    n10.val=0
    for(dr.val=0;dr.val<=4;dr.val++)
    {
      sys2=2
      nv.val=0
      for(sys0=1;sys0<=6;sys0++)
      {
        sys2=sys2*2
        for(sys1=0;sys1<=4;sys1++)
        {
          if(b[31+sys1].val==sys0)
          {
            if(dr.val!=sys1)
            {
              nv.val=nv.val+sys2
            }
          }
        }
      }
      if(nv.val==60)
      {
        n10.val=30
      }
      if(nv.val==120)
      {
        n10.val=30
      }
      if(nv.val==240)
      {
        n10.val=30
      }
    }
    n10.pco=65520
    click m1,0
  }
}

Long Straight: n11 Release Code
- In order to score a long straight we are looking for a run of 5
- if found our formula of multiplying by 2 will produce
- 124 for 1-2-3-4-5, or 248 for 2-3-4-5-6
- when the condition is met, we score 40, set bco to yellow and call m1 Release

if(mp.val==1)
{
  if(n11.pco==2016)
  {
    sys2=2
    n11.val=0
    nv.val=0
    for(sys0=1;sys0<=6;sys0++)
    {
      sys2=sys2*2
      for(sys1=0;sys1<=4;sys1++)
      {
        if(b[31+sys1].val==sys0)
        {
          nv.val=nv.val+sys2
        }
      }
    }
    if(nv.val==124)
    {
      n11.val=40
    }
    if(nv.val==248)
    {
      n11.val=40
    }
    n11.pco=65520
    click m1,0
  }
}

Step 10

Yahtzee: n12 Release Code
- In order to score a Yahtzee we are looking for a 5 of a Kind
- when the condition is met, we score 50, set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n12.pco==2016)
  {
    n12.val=0
    if(dv2.val==dv1.val)
    {
      if(dv3.val==dv2.val)
      {
        if(dv4.val==dv3.val)
        {
          if(dv5.val==dv4.val)
          {
            n12.val=50
          }
        }
      }
    }
    n12.pco=65520
    click m1,0
  }
}

Chance: n13 Release Code
- In order to score for Chance, we simply score all dice
- then set bco to yellow, and call m1 Release

if(mp.val==1)
{
  if(n13.pco==2016)
  {
    sys1=0
    for(sys0=0;sys0<=4;sys0++)
    {
      sys1=sys1+b[31+sys0].val
    }
    n13.val=sys1
    n13.pco=65520
    click m1,0
  }
}

Conclusion

Now if we run what we have accomplished, we get a working game of Yahtzee.
I hope this has been a learning experience and Enjoy

Patrick

A special shout out to Steve Lowry for tripping across the b[.id] component array (discovered in Nextion Editor v0.38, introduced in v0.42) and to Gerry Kropf for his short and sweet v=1-v boolean toggle. My tutorial first appeared in the old Nextion forum (in case you recognized it), and has been upgraded to v0.53 capabilities in this post.