Yatzy.javaDenna kod är public domain. Om ni hittar fel eller vill ändra något i koden blir jag jätteglad om ni skickar dessa ändringar till jesper [at] fantasi [punkt] se.
/*
* You may play this game and more on http://www.fantasi.se/
*
* You will also need the following images:
* dot.gif, dice.gif, hold.gif, newgame.gif, roll.gif, hiscore.gif
*
* To get the HiScore list working, you will need the Perl script yatzy.pl
* This script is called as a cgi and must be on a web server supporting
* cgi's. To play the game on a local host, the methods loadHiScore() and
* saveHiScore() need some rewriting to access a local file instead.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.Date;
import java.text.DateFormat;
public class Yatzy extends JApplet implements ActionListener
{
public static final long serialVersionUID = 0;
private CardLayout layout;
private JButton hi2game, addName, game2hi, newGame;
private JLabel points;
private JTextField name;
private JLabel hiName[] = new JLabel[15];
private JLabel score[] = new JLabel[15];
private JLabel date[] = new JLabel[15];
private YatzyDice t[] = new YatzyDice[5];
private Thread tr[] = new Thread[5];
private JLabel txt[] = new JLabel[18];
private JButton but[] = new JButton[15];
private boolean change[] = new boolean[18];
private Font plain = new Font("SansSerif", Font.PLAIN, 12);
private Font bold = new Font("SansSerif", Font.BOLD, 12);
private Container gameContainer;
protected int turns = 0;
protected JButton roll;
public Yatzy()
{
/* Tell the applet to ignore the system event queue to avoid
* error messages in JDK 1.1 and JFC 1.1
*/
getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
}
public void init()
{
gameContainer = getContentPane();
gameContainer.setBackground(Color.white);
/*
* The game view layout
*/
/* We need to catch exceptions thrown by URL creation */
try {
newGame = new JButton(new ImageIcon(new URL(getCodeBase(), "newgame.gif")));
newGame.setBorderPainted(false);
newGame.setMargin(new Insets(0, 0, 0, 0));
newGame.setBackground(Color.white);
newGame.addActionListener(this);
roll = new JButton(new ImageIcon(new URL(getCodeBase(), "roll.gif")));
roll.setBorderPainted(false);
roll.setMargin(new Insets(0, 0, 0, 0));
roll.setBackground(Color.white);
roll.addActionListener(this);
game2hi = new JButton(new ImageIcon(new URL(getCodeBase(), "hiscore.gif")));
game2hi.setBorderPainted(false);
game2hi.setMargin(new Insets(0, 0, 0, 0));
game2hi.setBackground(Color.white);
game2hi.addActionListener(this);
}
catch (IOException e) {
System.out.println("Error while loading graphics! " + e);
}
/* Create five dices and five threads to run them */
for (int i = 0; i < 5; i++) {
t[i] = new YatzyDice(this);
tr[i] = new Thread(t[i]);
}
JPanel scoreBoard = whitePanel();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
scoreBoard.setLayout(gb);
addYatzyLine(scoreBoard, gb, gbc, "Ones", 0);
addYatzyLine(scoreBoard, gb, gbc, "Deuces", 1);
addYatzyLine(scoreBoard, gb, gbc, "Threes", 2);
addYatzyLine(scoreBoard, gb, gbc, "Fours", 3);
addYatzyLine(scoreBoard, gb, gbc, "Fives", 4);
addYatzyLine(scoreBoard, gb, gbc, "Sixes", 5);
addYatzyLine(scoreBoard, gb, gbc, "Sum", 15);
addYatzyLine(scoreBoard, gb, gbc, "Bonus", 16);
addYatzyLine(scoreBoard, gb, gbc, "One Pair", 8);
addYatzyLine(scoreBoard, gb, gbc, "Two Pairs", 9);
addYatzyLine(scoreBoard, gb, gbc, "Three of a kind", 10);
addYatzyLine(scoreBoard, gb, gbc, "Four of a kind", 11);
addYatzyLine(scoreBoard, gb, gbc, "Full house", 12);
addYatzyLine(scoreBoard, gb, gbc, "Small Straight", 13);
addYatzyLine(scoreBoard, gb, gbc, "Large Straight", 14);
addYatzyLine(scoreBoard, gb, gbc, "Chans", 6);
addYatzyLine(scoreBoard, gb, gbc, "Yatzy", 7);
addYatzyLine(scoreBoard, gb, gbc, "Total", 17);
JPanel control = whitePanel();
control.setLayout(new GridLayout(9, 1));
for (int i = 0; i < 5; i++) {
control.add(t[i]);
t[i].setEnabled(false);
}
control.add(whitePanel());
control.add(roll);
control.add(game2hi);
control.add(newGame);
JPanel gameView = whitePanel();
gameView.setLayout(new BorderLayout());
gameView.add("Center",scoreBoard);
gameView.add("East",control);
/*
* The hiscore layout
*/
hi2game = new JButton("Back to the game");
hi2game.addActionListener(this);
JPanel names = whitePanel();
names.setLayout(new GridLayout(18, 1));
names.add(new JLabel("Name:"));
for (int n = 0; n < 15; n++) {
hiName[n] = new JLabel("-");
names.add(hiName[n]);
}
names.add(whitePanel());
names.add(hi2game);
JPanel scores = whitePanel();
scores.setLayout(new GridLayout(18, 1));
scores.add(new JLabel("Score:"));
for (int i = 0; i < 15; i++) {
score[i] = new JLabel("0");
scores.add(score[i]);
}
scores.add(whitePanel());
scores.add(whitePanel());
JPanel dates = whitePanel();
dates.setLayout(new GridLayout(18, 1));
dates.add(new JLabel("Date:"));
for (int i = 0; i < 15; i++) {
date[i] = new JLabel("-");
dates.add(date[i]);
}
dates.add(whitePanel());
dates.add(whitePanel());
JPanel hiscoreView = whitePanel();
hiscoreView.setLayout(new BorderLayout());
hiscoreView.add("West",scores);
hiscoreView.add("Center",names);
hiscoreView.add("East",dates);
/*
* The 'enter name' layout
*/
name = new JTextField(25);
addName = new JButton("Save Hiscore");
addName.addActionListener(this);
points = new JLabel("0", JLabel.CENTER);
JPanel nameView = whitePanel();
nameView.setLayout(new GridLayout(17, 1));
nameView.add(whitePanel());
nameView.add(whitePanel());
nameView.add(whitePanel());
nameView.add(whitePanel());
nameView.add(new JLabel("Congratulations! You've entered the Hall of fame!",
JLabel.CENTER));
nameView.add(whitePanel());
nameView.add(new JLabel("Enter your name:", JLabel.CENTER));
nameView.add(name);
nameView.add(whitePanel());
nameView.add(whitePanel());
nameView.add(new JLabel("Your total score:", JLabel.CENTER));
nameView.add(points);
nameView.add(whitePanel());
nameView.add(addName);
nameView.add(whitePanel());
nameView.add(whitePanel());
nameView.add(whitePanel());
/*
* Put them together in a CardLayout
*/
layout = new CardLayout();
gameContainer.setLayout(layout);
gameContainer.add(gameView, "game");
gameContainer.add(hiscoreView, "hisc");
gameContainer.add(nameView, "name");
}
private JPanel whitePanel()
{
JPanel p = new JPanel();
p.setOpaque(false);
return p;
}
private void addYatzyLine(JPanel p, GridBagLayout gb,
GridBagConstraints gbc, String title, int n)
{
gbc.gridwidth = GridBagConstraints.RELATIVE;
if (n < 15) {
but[n] = new JButton(title);
gb.setConstraints(but[n], gbc);
but[n].setBackground(Color.white);
but[n].setEnabled(false);
but[n].addActionListener(this);
p.add(but[n]);
}
else {
JLabel l = new JLabel(title);
gb.setConstraints(l, gbc);
l.setBackground(Color.white);
p.add(l);
}
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 2.0;
txt[n] = new JLabel("-", JLabel.CENTER);
gb.setConstraints(txt[n], gbc);
txt[n].setBackground(Color.white);
p.add(txt[n]);
change[n] = true;
}
/*
* Handles all the buttons in the game
*/
public void actionPerformed(ActionEvent e)
{
// 'Back to the game' from the HiScore list
if (e.getSource() == hi2game) {
layout.show(gameContainer, "game");
return;
}
// 'Save HiScore' from Hall of fame
if (e.getSource() == addName) {
saveHiScore();
loadHiScore();
layout.show(gameContainer, "hisc");
return;
}
// Roll the dices
if (e.getSource() == roll) {
roll.setEnabled(false);
turns++;
for (int i = 0; i < 5; i++) {
tr[i] = new Thread(t[i]);
tr[i].start();
}
return;
}
// New game
if (e.getSource() == newGame) {
for (int i = 0; i < 5; i++)
if (tr[i].isAlive())
t[i].stop();
diceCleanup();
clearScore();
roll.setEnabled(true);
return;
}
// Show the HiScore
if (e.getSource() == game2hi) {
loadHiScore();
layout.show(gameContainer, "hisc");
return;
}
// Place score during game
for (int i = 0; i < 15; i++) {
if (e.getSource() == but[i])
{
change[i] = false;
txt[i].setFont(plain);
diceCleanup();
for (i = 0; i < 15; i++) {
but[i].setEnabled(false);
if (change[i]) {
txt[i].setText("-");
txt[i].setFont(plain);
}
}
txt[15].setText(getSum());
txt[16].setText(getBon());
txt[17].setText(getTot());
boolean cont = false;
for (int j = 0; j < 15; j++)
cont = cont || change[j];
if (!cont) {
roll.setEnabled(false);
String tot = getTot();
loadHiScore();
if (str2int(tot) > str2int(score[14].getText())) {
points.setText(tot);
layout.show(gameContainer, "name");
}
}
else
roll.setEnabled(true);
return;
}
}
}
/*
* Reset dices
*/
private void diceCleanup()
{
turns = 0;
for (int i = 0; i < 5; i++)
t[i].cleanup();
}
/*
* Calculate and place current result. This is the heart of the
* game. Here the dices values are turned into scores. It might
* look a bit confusing but it's acually quite fast...
*/
protected void checkScore()
{
/* Both arrays below are indexed with the value of a dice (1 - 6)
* of course arrays are indexed from zero, which means that we use
* value - 1 as index.
*/
int re[] = new int[6];
boolean ex[] = new boolean[6];
int n;
/* Init each variable to -1 to mark that we have not found any
* pair etc yet
*/
int pair1 = -1, pair2 = -1, thok = -1, fook = -1, fiok = -1;
boolean bigstr = false, smallstr = false;
/* First, step through the five dices and count how many of
* each value there are.
*/
for (int i = 0; i < 5; i++)
re[t[i].getValue() - 1]++;
/* For each value, set the existance flag if the value was
* represented on any dice.
*/
for (int i = 0; i < 6; i++) {
if (re[i] > 0)
ex[i] = true;
else
ex[i] = false;
}
/* Step through values, start from the highest. If we find
* more than four of any value, stop immediately.
*/
for (n = 5; (n > -1) && (re[n] < 4); n--) {
if (re[n] > 2)
thok = n; /* Found three of a kind */
if (re[n] > 1) {
/* We found a pair. If this is the first pair set
* pair1 to this value otherwise set pair 2.
*/
if (pair1 == -1)
pair1 = n;
else
pair2 = n;
}
}
/* If n reached -1 in the previous for loop, we did not find
* the same value on more than at most three dices. Otherwise,
* set the four of a kind and perhaps even the five of a kind
* variable to what value the dices had.
*/
if (n != -1) {
pair1 = n; thok = n; fook = n;
if (re[n] == 5)
fiok = n;
}
/* So n did reach -1.. Then we might have a straight,
* check the corresponding flags.
*/
else if (ex[0] && ex[1] && ex[2] && ex[3] && ex[4])
smallstr = true;
else if (ex[1] && ex[2] && ex[3] && ex[4] && ex[5])
bigstr = true;
/* Display score in the first six fields */
for (int i = 0; i < 6; i++)
if (change[i]) {
but[i].setEnabled(true);
txt[i].setText(re[i] * (i + 1) + "");
txt[i].setFont(bold);
}
/* Set zeros in the rest */
for (int i = 6; i < 15; i++)
if (change[i]) {
but[i].setEnabled(true);
txt[i].setText("0");
txt[i].setFont(bold);
}
if (pair1 != -1) {
/* We found a pair! */
if (change[8])
txt[8].setText((Math.max(pair1,pair2) + 1) * 2 + "");
if (pair2 != -1) {
/* We found another pair! */
if (change[9])
txt[9].setText(pair1 * 2 + pair2 * 2 + 4 + "");
if (thok != -1) {
/* We have three of a kind, that means we also
* have a full house!
*/
if (change[10])
txt[10].setText(thok * 3 + 3 + "");
if ((thok == pair1) && change[12])
txt[12].setText(thok * 3 + pair2 * 2 + 5 + "");
else if (change[12])
txt[12].setText(thok * 3 + pair1 * 2 + 5 + "");
}
}
else if (thok != -1) {
/* We did not have two pairs, but we might still have
* three, four and five of a kind.
*/
if (change[10])
txt[10].setText(thok * 3 + 3 + "");
if (fook != -1) {
if (change[11])
txt[11].setText(fook * 4 + 4 + "");
if ((fiok != -1) && change[7])
txt[7].setText("50");
}
}
}
/* No pair? Then we might have a straight. */
else if (smallstr && change[13])
txt[13].setText("15");
else if (bigstr && change[14])
txt[14].setText("20");
/* Set the sum field */
if (change[6])
txt[6].setText(t[0].getValue() + t[1].getValue() +
t[2].getValue() +
t[3].getValue() + t[4].getValue() + "");
}
/*
* Clear the scoreboard before a new game
*/
private void clearScore()
{
for (int i = 0; i < 15; i++)
but[i].setEnabled(false);
for (int i = 0; i < 18; i++) {
change[i] = true;
txt[i].setText("-");
txt[i].setFont(plain);
}
}
/*
* Converts string numbers to ints and '-' to zero
*/
private int str2int(String str)
{
if (str != "-")
return Integer.parseInt(str);
else
return 0;
}
/*
* Calculates the upper sum
*/
private String getSum()
{
int sum = 0;
for (int i = 0; i < 6; i++)
sum = sum + str2int(txt[i].getText());
return sum + "";
}
/*
* Check for bonus
*/
private String getBon()
{
if (str2int(txt[15].getText()) >= 63)
return "50";
else
return "0";
}
/*
* Calculate the total score
*/
private String getTot()
{
int tot = 0;
for (int i = 6; i < 17; i++)
tot = tot + str2int(txt[i].getText());
return tot + "";
}
/*
* Read the HiScore from a file
*/
private void loadHiScore()
{
try {
URL url = new URL(this.getCodeBase(), "Yatzy.hi");
BufferedReader indata =
new BufferedReader(new InputStreamReader(url.openStream()));
for (int i = 0; i < 15; i++) {
hiName[i].setText(indata.readLine());
score[i].setText(indata.readLine());
date[i].setText(indata.readLine());
}
indata.close();
}
catch (IOException e) {
for (int i = 0; i < 15; i++) {
hiName[i].setText("Yatzy");
score[i].setText("0");
date[i].setText("someday");
}
}
}
/*
* Send score to the HiScore CGI.
* The Perl CGI is also available from http://www.fantasi.se/jesper
*/
private void saveHiScore()
{
try {
Date d = new Date();
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
URL url = new URL("http://url.to.server/yatzy.pl?" +
"name=" + name.getText() + "&score=" + getTot() +
"&date=" + df.format(d));
BufferedReader indata =
new BufferedReader(new InputStreamReader(url.openStream()));
String tmp = indata.readLine();
System.out.println(tmp);
}
catch (RuntimeException e) {
System.err.println(e.getMessage());
return;
}
catch (MalformedURLException e) {
System.err.println(e.getMessage());
return;
}
catch (IOException e) {
System.err.println(e.getMessage());
return;
}
}
}
/*
* A threaded dice
*/
class YatzyDice extends JPanel implements Runnable
{
public static final long serialVersionUID = 0;
private int value;
private boolean lock;
private boolean stopped;
private Yatzy theGame;
// Should be ImageIcon...
private Image imgDice, imgDot, imgHold;
YatzyDice( Yatzy pan )
{
theGame = pan;
value = -1;
lock = false;
imgDice = theGame.getImage(theGame.getCodeBase(), "dice.gif");
imgDot = theGame.getImage(theGame.getCodeBase(), "dot.gif");
imgHold = theGame.getImage(theGame.getCodeBase(), "hold.gif");
setBackground(Color.white);
addMouseListener(new DiceMouseListener());
}
/*
* Make the dice look all new and shiny
*/
public void cleanup()
{
setEnabled(true);
lock = false;
value = -1;
repaint();
}
/*
* Let the dice roll for a while before giving final result
*/
public void roll()
{
for(int i = 0; i < 20; i++) {
if (stopped)
return;
if (!lock) {
value = (int)(Math.random() * 6) + 1;
repaint();
}
try {
Thread.sleep(70);
}
catch (InterruptedException e) {
System.err.println(e.getMessage());
}
}
if (theGame.turns >= 3) {
lock = true;
repaint();
}
else
theGame.roll.setEnabled(true);
}
/*
* Do you feel lucky?
*/
public void run()
{
stopped = false;
setEnabled(false);
roll();
if (!stopped) {
theGame.checkScore();
if (theGame.turns < 3)
setEnabled(true);
}
}
/*
* Some small get and set methods...
*/
public void stop() { stopped = true; }
public int getValue() { return value; }
public boolean isLocked() { return lock; }
/*
* Listen for those tiny squeek noises only a mouse can make
*/
class DiceMouseListener extends MouseAdapter
{
public void mousePressed( MouseEvent e )
{
if (lock && (theGame.turns < 3))
lock = false;
else if (!lock && (value != -1))
lock = true;
repaint();
}
}
/*
* A not entirely stupid way of drawing a dice accually
*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (lock)
g.drawImage(imgHold, 52, 18, this);
else {
g.setColor(Color.white);
g.fillRect(52, 18, 30, 14);
}
g.drawImage(imgDice, 0, 0, this);
if (value != -1) {
if ((value % 2) == 1)
g.drawImage(imgDot, 21, 21, this);
if (value >= 2) {
g.drawImage(imgDot, 31, 11, this);
g.drawImage(imgDot, 11, 31, this);
if (value >= 4) {
g.drawImage(imgDot, 11, 11, this);
g.drawImage(imgDot, 31, 31, this);
if (value == 6) {
g.drawImage(imgDot, 11, 21, this);
g.drawImage(imgDot, 31, 21, this);
}
}
}
}
}
}
|