Over a million developers have joined DZone.
Platinum Partner

Create a Yahtzee Dice Roller and Scorer in Compiled JavaFX Script

· Java Zone

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

I'm still at The Server Side Java Symposium in Las Vegas, and I think that walking by all these slot machines has inspired this blog post. Today's example builds on the program in the Roll the Dice post in order to create a Yahtzee dice roller and scorer. Each time you click the Roll button, the five dice assume random values, and the combination of values is scored according to the possible categories in the bottom portion of a Yahtzee scoring sheet. Here's a screenshot:

Yahtzee_2

In addition to the Dice.fx and PipPlacement.fx files from the Roll the Dice post, this program consists of the following source code files.

YahtzeeMain.fx

 

/*
* YahtzeeMain.fx -
* A compiled JavaFX program that demonstrates creating custom
* components with CompositeNode and evaluates Yahtzee dice rolls.
*
*
* Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
* to serve as a JavaFX Script example.
*/

import javafx.ui.*;
import javafx.ui.canvas.*;
import java.lang.System;

Frame {
var model = YahtzeeModel {}
width: 510
height: 400
title: "Roll Dice and Evaluate Yahtzee Combinations"
background: Color.WHITE
content:
BorderPanel {
center:
Box {
var evalFont =
Font {
size: 20
}
orientation: Orientation.VERTICAL
content: [
Canvas {
content:
for (diceNum in [0 .. model.numDice - 1]) {
model.newDice =
Dice {
x: diceNum * 100 + 10
y: 10
width: 80
height: 80
faceColor: Color.RED
pipColor: Color.WHITE
}
}
},
GroupPanel {
var fiveOfKindRow = Row { alignment: Alignment.BASELINE }
var largeStraightRow = Row { alignment: Alignment.BASELINE }
var smallStraightRow = Row { alignment: Alignment.BASELINE }
var fullHouseRow = Row { alignment: Alignment.BASELINE }
var fourOfKindRow = Row { alignment: Alignment.BASELINE }
var threeOfKindRow = Row { alignment: Alignment.BASELINE }
var chanceRow = Row { alignment: Alignment.BASELINE }

var labelsColumn = Column {
alignment: Alignment.TRAILING
}
var fieldsColumn = Column {
alignment: Alignment.LEADING
}
rows: [
fiveOfKindRow,
largeStraightRow,
smallStraightRow,
fullHouseRow,
fourOfKindRow,
threeOfKindRow,
chanceRow
]
columns: [
labelsColumn,
fieldsColumn
]
content: [
SimpleLabel {
font: evalFont
row: fiveOfKindRow
column: labelsColumn
text: "Five of a Kind (Yahtzee):"
},
SimpleLabel {
font: evalFont
row: fiveOfKindRow
column: fieldsColumn
text: bind
if (model.fiveOfKind)
"{model.fiveOfKindScore}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: largeStraightRow
column: labelsColumn
text: "Large Straight:"
},
SimpleLabel {
font: evalFont
row: largeStraightRow
column: fieldsColumn
text: bind
if (model.largeStraight)
"{model.largeStraightScore}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: smallStraightRow
column: labelsColumn
text: "Small Straight:"
},
SimpleLabel {
font: evalFont
row: smallStraightRow
column: fieldsColumn
text: bind
if (model.smallStraight)
"{model.smallStraightScore}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: fullHouseRow
column: labelsColumn
text: "Full House:"
},
SimpleLabel {
font: evalFont
row: fullHouseRow
column: fieldsColumn
text: bind
if (model.fullHouse)
"{model.fullHouseScore}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: fourOfKindRow
column: labelsColumn
text: "Four of a Kind:"
},
SimpleLabel {
font: evalFont
row: fourOfKindRow
column: fieldsColumn
text: bind
if (model.fourOfKind)
"{model.sumOfDiceValues}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: threeOfKindRow
column: labelsColumn
text: "Three of a Kind:"
},
SimpleLabel {
font: evalFont
row: threeOfKindRow
column: fieldsColumn
text: bind
if (model.threeOfKind)
"{model.sumOfDiceValues}"
else "N/A"
},

SimpleLabel {
font: evalFont
row: chanceRow
column: labelsColumn
text: "Chance:"
},
SimpleLabel {
font: evalFont
row: chanceRow
column: fieldsColumn
text: bind "{model.sumOfDiceValues}"
},
]
},
]
}
bottom:
FlowPanel {
content:
Button {
text: "Roll"
defaultButton: true
action:
function():Void {
model.roll();
}
}
}
}
visible: true
onClose:
function():Void {
System.exit(0);
}
}


YahtzeeModel.fx

/*
* YahtzeeModel.fx -
* The model behind the Yahtzee dice roll and combination evaluation
*
* Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
* to serve as a JavaFX Script example.
*/
import javafx.lang.Sequences;
import java.lang.System;

class YahtzeeModel {
attribute numDice:Integer = 5;
attribute diceDistribution:Integer[];
attribute newDice:Dice on replace {
insert newDice into dice;
}
attribute dice:Dice[];

attribute fiveOfKind:Boolean;
attribute largeStraight:Boolean;
attribute smallStraight:Boolean;
attribute fullHouse:Boolean;
attribute fourOfKind:Boolean;
attribute threeOfKind:Boolean;

attribute fiveOfKindScore:Integer = 50;
attribute largeStraightScore:Integer = 40;
attribute smallStraightScore:Integer = 30;
attribute fullHouseScore:Integer = 25;

attribute sumOfDiceValues:Integer = 0;

function roll():Void {
for (die in dice) {
die.roll();
}
evalYahtzeeCombos();
}

function evalYahtzeeCombos() {
var values =
for (val in dice) {
val.value;
}

var maxVal:Integer = Sequences.max(values, null) as Integer;
var minVal:Integer = Sequences.min(values, null) as Integer;

// Create a sequence that contains the distribution of values
// and Calclulate the sum of the dice values
diceDistribution =
for (i in [1 .. 6]) 0;

sumOfDiceValues = 0;

for (val in values) {
diceDistribution[val - 1]++;
sumOfDiceValues += val;
}

// Determine if five-of-a-kind
fiveOfKind =
((for (occurance in diceDistribution
where occurance >= 5) occurance) <> []);

// Determine if four-of-a-kind
fourOfKind =
((for (occurance in diceDistribution
where occurance >= 4) occurance) <> []);

// Determine if three-of-a-kind
threeOfKind =
sizeof (for (occurance in diceDistribution
where occurance >= 3) occurance) > 0;

// Determine if full house
fullHouse =
sizeof (for (occurance in diceDistribution
where occurance == 3) occurance) > 0 and
sizeof (for (occurance in diceDistribution
where occurance == 2) occurance) > 0;

// Determine if large straight
largeStraight =
sizeof (for (occurance in diceDistribution
where occurance > 1) occurance) == 0 and
(maxVal - minVal == 4);

// Determine if small straight
smallStraight =
sizeof (for (occurance in diceDistribution
where occurance == 2) occurance) == 1 and
(maxVal - minVal == 3);
}
}

 



A JavaFX Script concept that we haven't covered yet is the set of static functions available in the new javafx.lang.Sequences class. These functions enable you to perform operations (such as sorting) on a sequence. In this program I'm using the max and min functions of that class to find the largest and smallest value in a dice roll.

Regards,
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

Immediate eBook (PDF) download available at the book's Apress site

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}