| Weitere Artikel aus dem Elo-Magazin |
Ping-Pong Wettbewerb
Aus Ping Pong wird King Kong: Kniffel-König
Das Würfelspiel Kniffel wird fast jedem bekannt sein. Dieses Spiel wurde hier elektronisch zur Verwendung auf der Ping-Pong-Platine umgesetzt. Wie kommt es zum Namen King Kong? Ganz einfach: auf der Platine des Ping Pong, abgekürzt PP, kann der Kniffel-König, abgekürzt KK, ausgespielt werden, somit wird das Ping Pong umfunktioniert zu King Kong.
von Michael Gaus
Das Würfelspiel Kniffel wird fast jedem bekannt sein.
Dieses Spiel wurde hier elektronisch zur Verwendung auf der Ping-Pong-Platine umgesetzt.
Wie kommt es zum Namen King Kong? Ganz einfach: auf der Platine des Ping Pong, abgekürzt PP, kann der Kniffel-König, abgekürzt KK, ausgespielt werden, somit wird das Ping Pong umfunktioniert zu King Kong.
Auszug aus Wikipedia: Kniffel ist ein Würfelspiel, das mit fünf Würfeln gespielt wird. In jedem Durchgang darf man bis zu drei mal hintereinander würfeln. Dabei darf man "passende" Würfel zur Seite legen und mit den verbleibenden weiter würfeln. Spätestens nach dem dritten Wurf muss man sich für ein freies Feld auf dem Spielzettel entscheiden, welches nun mit dem Ergebnis dieses Wurfes bewertet wird.
Ziel ist es, eine möglichst hohe Gesamtpunktzahl zu erzielen. Es gibt insgesamt 13 Felder, die es auszufüllen gilt:

a) Einser: alle Einser werden addiert
b) Zweier: alle Zweier werden addiert
d) Dreier: alle Dreier werden addiert
c) Vierer: alle Vierer werden addiert
e) Fünfer: alle Fünfer werden addiert
f) Sechser: alle Sechser werden addiert
g) Full House: drei gleiche und zwei gleiche Würfel, wird mit 25 Punkten bewertet
h) Große Straße: 1-2-3-4-5 oder 2-3-4-5-6, wird mit 40 Punkten bewertet
i) Kleine Straße: 1-2-3-4 oder 2-3-4-5 oder 3-4-5-6, wird mit 30 Punkten bewertet
j) Chance: alle Würfelaugen werden addiert
k) Dreierpasch: drei gleiche Würfel, alle Würfelaugen werden addiert
l) Viererpasch: vier gleiche Würfel, alle Würfelaugen werden addiert
m) Fünferpasch bzw. Kniffel: fünf gleiche Würfel, wird mit 50 Punkten bewertet
Wenn man beim Sammeln der ersten 6 Kategorien (Einser bis Sechser) in der Summe mindestens 63 Punkte bekommen hat, also beispielsweise für jedes Feld drei passende Würfel, gibt es einen Bonus von 35 Punkten.
Zusätzlich benötigte Hardware: Ein zusätzlicher Taster (1-poliger Schließer), der zwischen PortD.3 (also Lötpad D3) und GND angeschlossen wird. Der benötigte Pullup-Widerstand wird im Controller intern hinzugeschaltet.
Anzeige und Bedienung
Durch Einwurf einer Münze wird King Kong gestartet. Im Display erscheint kurz ein Startbildschirm. Anschließend wird bereits der erste Würfelvorgang mit allen 5 Würfeln gestartet, was auch im Display angezeigt wird. Durch einen Tastendruck wird das Würfeln gestoppt und es wird das Würfelergebnis angezeigt. Zusätzlich zu den 5 Würfeln werden im unteren Displaybereich zwei Symbole angezeigt: links ein Tildesymbol (~), um einen erneuten Würfelvorgang zu starten, rechts ein Pfeil, um in die Anzeige der auszufüllenden Spielfelder zu gelangen.

Mit dem rechten Poti kann nun ein Würfel oder eines der 2 Symbole angewählt werden, hierzu ist der Einstellbereich des Potis in 7 Bereiche unterteilt. Der momentan angewählte Würfel bzw. das angewählte Symbol blinkt.
Man kann nun festlegen, welche Würfel stehen bleiben sollen und welche erneut gewürfelt werden sollen, falls gewünscht. Dazu wählt man einen Würfel an und bestätigt mit einem Tastendruck. Der Würfel blinkt dann als ausgefülltes Quadrat und symbolisiert damit, dass er zwar gelöscht wurde, aber momentan per Poti angewählt ist. Dreht man das Poti weiter, dann wird das Quadrat gelöscht.
Durch einen erneuten Tastendruck kann ein abgewählter Würfel auch jederzeit wieder angewählt werden, es wird dann wieder der entsprechende Würfelwert angezeigt. Nachdem man für alle 5 Würfel die Auswahl durchgeführt hat, wählt man das Symbol für "neu würfeln" an, sodass es blinkt und bestätigt dies mit einem Tastendruck. Die abgewählten Würfel werden dann neu gewürfelt, die angewählten bleiben erhalten. Falls kein Würfel abgewählt wurde, wird auch nicht neu gewürfelt, es erfolgt dann keine Reaktion auf den Tastendruck.
Das Würfeln wird wieder durch einen Tastendruck gestoppt. Nun können wieder mit dem rechten Poti die Würfel an- und abgewählt werden und auf Wunsch wieder neu gewürfelt werden. Es sind maximal 3 Würfelvorgänge möglich, danach ist das Abwählen sowie das neu Würfeln solange blockiert, bis ein Spielfeld ausgewählt wurde. Es kann jedoch auch bereits nach dem ersten Wurf das Würfelergebnis in ein Spielfeld eingetragen werden, wenn z.B. schon ein geeignetes nicht mehr zu optimierendes Würfelmuster vorliegt.
Um das Würfelergebnis in ein Spielfeld einzutragen, wird mit dem rechten Poti das Pfeil-Symbol unten rechts angewählt, sodass es blinkt. Durch einen Tastendruck wird die Auswahl bestätigt. Nun werden die noch zu vergebenden Spielfelder (max. 13) angezeigt. Bereits ausgefüllte Spielfelder werden nicht mehr angezeigt.
Im oberen Displaybereich werden die Spielfelder a-g und im unteren Bereich die Spielfelder h-m angezeigt (Aufteilung siehe bei Spielregeln). Die Symbole für die einzelnen Spielfelder sind auch in der Grafik spielfeld.jpg zu sehen.
Mit dem rechten Poti, das nun in 13 Einstellbereiche unterteilt ist, kann das gewünschte Feld angewählt werden, sodass es blinkt und mit einem kurzen Tastendruck wird die Auswahl bestätigt. Bei der Auswahl eines Felds werden die freien Felder automatisch übersprungen.
Nach dem kurzen Tastendruck wird die Punkteanzahl, die das gewählte Feld in Verbindung mit dem Würfelergebnis ergibt, auf dem Display angezeigt, z.B. 25 bei Full House. Durch einen kurzen Tastendruck wird der nächste Würfelvorgang gestartet und es wird weiter verfahren wie oben beschrieben. Dies wiederholt sich solange, bis alle 13 Spielfelder ausgefüllt wurden.
In der Spielfeldauswahl kann statt eines kurzen Tastendrucks auch ein langer Tastendruck erfolgen. Dies bewirkt, dass das Würfelergebnis nicht in das gewählte Spielfeld eingetragen wird, sondern stattdessen zurück zur Anzeige des Würfelergebnisses gewechselt wird.
Hierzu muss die Taste solange gedrückt werden, bis wieder die Anzeige mit dem Würfelergebnis erscheint.
Dadurch ist es möglich, jederzeit das Spielfeld einzublenden und ohne Auswahl wieder zu verlassen, um nachschauen zu können, welche Felder denn noch frei sind und dementsprechend die Würfelan- und abwahl vorzunehmen.
Nachdem alle 13 Spielfelder ausgefüllt wurden, wird die erzielte Gesamtpunktezahl blinkend im Display dargestellt.
Falls in den Spielfeldern a-f (Einser bis Sechser) mehr als 63 Punkte erzielt wurden, wird der Bonus von 35 Punkten automatisch hinzuaddiert.
Durch einen weiteren Tastendruck geht King Kong in den stromsparenden Standbymodus.
Durch einen erneuten Münzeinwurf kann das Spiel neu gestartet werden.
Quellcode
Der Code für den ATmega8 auf der Ping Pong Platine wurde mit dem C-Compiler CodeVision AVR (Version 2.04.6 Evaluation) erstellt. Diese Evaluation-Version kann für den privaten nicht-kommerziellen Gebrauch kostenlos verwendet werden und ist auf eine Codegröße von 3 kB beschränkt, was für diese Anwendung gerade noch ausreicht. Das komplette Projekt ist in der ZIP-Datei enthalten (Projektdatei für CodeVison AVR ist kingkong.prj).
Download: Quelltext und Hexdatei
/*****************************************************
Compiler : CodeVisionAVR 2.04.6 Evaluation
Chip type : ATmega8
Clock frequency : 8 MHz (int. RC-OSC)
*****************************************************/
//***************************************************
// King Kong - Kniffel-König
// auf Basis des Franzis-Pingpong
// http://www.elo-web.de/ping-pong-start
//***************************************************
#include <mega8.h>
#include <stdio.h>
#include <delay.h>
#include <sleep.h>
#include <stdlib.h>
#define P_CLK PORTB.3
#define P_DATA PORTB.4
#define P_STROBE PORTB.2
#define PIN_COIN PIND.2
#define PULLUP_COIN PORTD.2
#define DIR_COIN DDRD.2
#define COIN_INSERTED (PIN_COIN == 0)
#define PIN_KEY PIND.3
#define PULLUP_KEY PORTD.3
#define KEY_PRESSED (PIN_KEY == 0)
#define WIDTH 12 // number of fields in horizontal direction
#define HEIGHT 10 // number of fields in vertical direction
unsigned int leds[WIDTH]; // current state of each LED (organized in columns)
unsigned int ledsBlink[WIDTH]; // current blink state of each LED (organized in columns)
typedef struct // patterns for dices
{
unsigned char available; // 1=pattern still available
unsigned char blink; // 1=pattern blinking on display
} S_PATTERN;
S_PATTERN pattern[13]; // 13 patterns are used => defined in enumeration below
enum { P_1, P_2, P_3, P_4, P_5, P_6, P_FULL_HOUSE, P_LARGESTREET, P_SMALLSTREET, P_CHANCE, P_3_OF_A_KIND, P_4_OF_A_KIND, P_5_OF_A_KIND };
typedef struct // dices
{
unsigned char value; // value of dice (1..6)
unsigned char keep; // 1=keep dice, do not roll again
unsigned char blink; // 1=dice blinking on display
} S_DICE;
S_DICE dice[5]; // 5 dices are used
unsigned int iScore; // total score
unsigned char upperSum; // sum of patterns P_1...P_6
bit bRollDevices; // 1=roll the devices is active
flash unsigned char dicefont[6*3] =
{ // font for dices
0x00, 0x02, 0x00, // 1
0x01, 0x00, 0x04, // 2
0x01, 0x02, 0x04, // 3
0x05, 0x00, 0x05, // 4
0x05, 0x02, 0x05, // 5
0x07, 0x00, 0x07 // 6
};
flash unsigned char decimals[] =
{ // Font for decimal values
0x1F, 0x11, 0x1F, // 0
0x00, 0x00, 0x1F, // 1
0x1D, 0x15, 0x17, // 2
0x15, 0x15, 0x1F, // 3
0x07, 0x04, 0x1F, // 4
0x17, 0x15, 0x1D, // 5
0x1F, 0x15, 0x1D, // 6
0x01, 0x01, 0x1F, // 7
0x1F, 0x15, 0x1F, // 8
0x17, 0x15, 0x1F // 9
};
// clear the whole screen, all LEDs off
void clearScreen(void)
{
unsigned char i;
for(i = 0; i < (WIDTH); i++)
{
leds[i] = 0;
}
}
// wait until key is pressed
void waitUntilKeypressed(void)
{
while(!KEY_PRESSED);
delay_ms(20);
}
// wait until key is released
void waitUntilKeyreleased(void)
{
while(KEY_PRESSED);
delay_ms(20);
}
// check if key is pressed
// return: 0=key not pressed, 1=key pressed
unsigned char keyPressed(void)
{
unsigned char result = 0;
if(KEY_PRESSED)
result = 1;
delay_ms(20);
return result;
}
// Timer 2 overflow interrupt service routine
// multiplexing of LEDs
// approx. every 1ms
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
static unsigned char count = 0;
unsigned char cValue, cValue2;
static unsigned char cBlink = 0x00;
static unsigned char cBlinkcnt = 0;
cBlinkcnt++;
if(cBlinkcnt >= 250)
{
cBlinkcnt = 0;
cBlink = ~cBlink;
}
count++;
if(count >= 12)
{
count = 0;
P_DATA = 0;
}
else
{
P_DATA = 1;
}
P_CLK = 1;
P_CLK = 0;
PORTC &= (~0x0F);
PORTD &= (~0xF0);
PORTB &= (~0x03);
P_STROBE = 1;
P_STROBE = 0;
cValue = (unsigned char)leds[count] & 0x0F;
cValue2 = (unsigned char)ledsBlink[count] & cBlink;
cValue &= (~cValue2);
PORTC |= cValue;
cValue = (unsigned char)leds[count] & 0xF0;
cValue &= (~cValue2);
PORTD |= cValue;
cValue = (unsigned char)(leds[count]>>8) & 0x03;
cValue2 = (unsigned char)(ledsBlink[count]>>8) & cBlink;
cValue &= (~cValue2);
PORTB |= cValue;
}
// initialization of Timer0 and Timer2
void initTimers(void)
{
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 250,000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
//ASSR=0x00;
TCCR2=0x03;
//TCNT2=0x00;
//OCR2=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
TCCR0=0x01;
//TCNT0=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
}
// set controller in Powerdown mode
void setStandbyMode(void)
{
TCCR2 &= 0xF8; //stop Timer2
PORTC = 0;
PORTD = 0;
PORTB = 0;
ADCSRA &= 0x7F; // stopADC
DDRD.2 = 0;
PORTD.2 = 1;
GICR |= 0x40; //enable INT0
sleep_enable();
powerdown();
GICR &= (~0x40); //disable INT0
PULLUP_KEY = 1;
DDRD.2 = 1;
PORTD.2 = 0;
ADCSRA |= 0x80; //startADC
TCCR2 |= 0x03; //start Timer2
}
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
}
// initialization of INT0
void initInt0(void)
{
// External Interrupt(s) initialization
// INT0: disabled
// INT0 Mode: Low level
GICR &= (~0x40); //disable INT0
MCUCR &= 0xFC;
GIFR=0x40;
}
// initialization of ports
void init(void)
{
//PORTB = 0;
DDRB = 0x1F;
//PORTC = 0;
DDRC = 0x0F;
//PORTD = 0;
DDRD = 0xF4;
PULLUP_KEY = 1;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
//SFIOR=0x00;
}
#define ADC_VREF_TYPE 0x00
// initialization of ADC
void initADC(void)
{
// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AREF pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;
}
// Read the AD conversion result
// adc_input: ADC channel (0..7)
// return: ADC value (0..1023)
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
// select dices
// return: selected dice (0...4) or "roll the dices" (5) or "select pattern" (6)
unsigned char selectDices(void)
{
unsigned char x;
x = 6 - (read_adc(7) / (1023/7 + 1));
return(x);
}
// select patterns for dices
// return: selected pattern (0...12)
unsigned char selectPatterns(void)
{
unsigned char x;
x = 12 - (read_adc(7) / (1023/13 + 1));
return(x);
}
// set blinking status for upper 8 LED rows
// blink: 0=blinking off, 0xFF=blinking on
void blinkScreen(unsigned char blink)
{
unsigned char i;
for(i = 0; i < 12; i++)
ledsBlink[i] = blink;
}
// show available patterns for dices
void showPatterns(void)
{
unsigned char i;
unsigned int localLeds[12];
unsigned int localLedsBlink[12];
for(i = 0; i < 12; i++)
localLeds[i] = 0;
if(pattern[P_1].available)
localLeds[1] |= 0x001;
if(pattern[P_2].available)
localLeds[2] |= 0x003;
if(pattern[P_3].available)
localLeds[3] |= 0x007;
if(pattern[P_4].available)
localLeds[4] |= 0x00F;
if(pattern[P_5].available)
localLeds[5] |= 0x01F;
if(pattern[P_6].available)
localLeds[6] |= 0x03F;
if(pattern[P_FULL_HOUSE].available)
{
localLeds[8] |= 0x00E;
localLeds[9] |= 0x00F;
localLeds[10] |= 0x00E;
}
if(pattern[P_LARGESTREET].available)
{
localLeds[0] |= 0x3E0;
localLeds[1] |= 0x3E0;
}
if(pattern[P_SMALLSTREET].available)
{
localLeds[3] |= 0x3C0;
localLeds[4] |= 0x3C0;
}
if(pattern[P_CHANCE].available)
{
localLeds[6] |= 0x380;
localLeds[7] |= 0x300;
}
if(pattern[P_3_OF_A_KIND].available)
{
localLeds[9] |= 0x380;
}
if(pattern[P_4_OF_A_KIND].available)
{
localLeds[10] |= 0x3C0;
}
if(pattern[P_5_OF_A_KIND].available)
{
localLeds[11] |= 0x3E0;
}
for(i = 0; i < 12; i++)
localLedsBlink[i] = ledsBlink[i];
if(pattern[P_1].blink)
localLedsBlink[1] |= 0x001;
else
localLedsBlink[1] &= (~0x001);
if(pattern[P_2].blink)
localLedsBlink[2] |= 0x003;
else
localLedsBlink[2] &= (~0x003);
if(pattern[P_3].blink)
localLedsBlink[3] |= 0x007;
else
localLedsBlink[3] &= (~0x007);
if(pattern[P_4].blink)
localLedsBlink[4] |= 0x00F;
else
localLedsBlink[4] &= (~0x00F);
if(pattern[P_5].blink)
localLedsBlink[5] |= 0x01F;
else
localLedsBlink[5] &= (~0x01F);
if(pattern[P_6].blink)
localLedsBlink[6] |= 0x03F;
else
localLedsBlink[6] &= (~0x03F);
if(pattern[P_FULL_HOUSE].blink)
{
localLedsBlink[8] |= 0x00E;
localLedsBlink[9] |= 0x00F;
localLedsBlink[10] |= 0x00E;
}
else
{
localLedsBlink[8] &= (~0x00E);
localLedsBlink[9] &= (~0x00F);
localLedsBlink[10] &= (~0x00E);
}
if(pattern[P_LARGESTREET].blink)
{
localLedsBlink[0] |= 0x3E0;
localLedsBlink[1] |= 0x3E0;
}
else
{
localLedsBlink[0] &= (~0x3E0);
localLedsBlink[1] &= (~0x3E0);
}
if(pattern[P_SMALLSTREET].blink)
{
localLedsBlink[3] |= 0x3C0;
localLedsBlink[4] |= 0x3C0;
}
else
{
localLedsBlink[3] &= (~0x3C0);
localLedsBlink[4] &= (~0x3C0);
}
if(pattern[P_CHANCE].blink)
{
localLedsBlink[6] |= 0x380;
localLedsBlink[7] |= 0x300;
}
else
{
localLedsBlink[6] &= (~0x380);
localLedsBlink[7] &= (~0x300);
}
if(pattern[P_3_OF_A_KIND].blink)
{
localLedsBlink[9] |= 0x380;
}
else
{
localLedsBlink[9] &= (~0x380);
}
if(pattern[P_4_OF_A_KIND].blink)
{
localLedsBlink[10] |= 0x3C0;
}
else
{
localLedsBlink[10] &= (~0x3C0);
}
if(pattern[P_5_OF_A_KIND].blink)
{
localLedsBlink[11] |= 0x3E0;
}
else
{
localLedsBlink[11] &= (~0x3E0);
}
for(i = 0; i < 12; i++)
leds[i] = localLeds[i];
for(i = 0; i < 12; i++)
ledsBlink[i] = localLedsBlink[i];
}
// show the symbol for rolling the dices
// blink: 1=symbol is blinking
void showSymbolRollDices(unsigned char blink)
{
unsigned char i;
leds[0] |= 0x0100;
leds[1] |= 0x0200;
leds[2] |= 0x0100;
leds[3] |= 0x0200;
for(i = 0; i <= 3; i++)
{
if(blink)
{
ledsBlink[i] |= 0x0300;
}
else
{
ledsBlink[i] &= (~0x0300);
}
}
}
// show the symbol for select pattern
// blink: 1=symbol is blinking
void showSymbolSelectPattern(unsigned char blink)
{
unsigned char i;
leds[8] |= 0x0100;
leds[9] |= 0x0100;
leds[10] |= 0x0380;
leds[11] |= 0x0100;
for(i = 8; i <= 11; i++)
{
if(blink)
{
ledsBlink[i] |= 0x0380;
}
else
{
ledsBlink[i] &= (~0x0380);
}
}
}
// show a dice on display
// number: number of dice (0...5)
// row: row for start on display
// col: column for start on display
void showDice(unsigned char number, unsigned char row, unsigned char col)
{
unsigned char i;
unsigned int localLeds[12];
for(i = 0; i < 12; i++)
{
localLeds[i] = leds[i];
}
for(i = 0; i < 3; i++)
{
localLeds[col] &= (~((unsigned int)0x7 << row));
if(dice[number].keep || bRollDevices)
{ // show dice because it should be keeped or rolling the dices is active
localLeds[col] |= (unsigned int)dicefont[(dice[number].value - 1)*3 + i] << row;
}
else
{ // do not show dice because it should be rolled again
if(dice[number].blink) // but if it is selected, show all LEDs of this dice blinking
localLeds[col] |= ((unsigned int)0x7 << row);
}
if(dice[number].blink)
{
ledsBlink[col] |= ((unsigned int)0x7 << row);
}
else
{
ledsBlink[col] &= ~((unsigned int)0x7 << row);
}
col++;
}
for(i = 0; i < 12; i++)
leds[i] = localLeds[i];
}
// show the values of all 5 dices
void showDices(void)
{
showDice(0, 0, 0);
showDice(1, 0, 4);
showDice(2, 0, 8);
showDice(3, 4, 0);
showDice(4, 4, 4);
}
// roll the dices
void rollDices(void)
{
unsigned char i;
bRollDevices = 1;
do
{
for(i = 0; i < 5; i++)
{
if(dice[i].keep == 0)
{
dice[i].value = (rand() % 6) + 1;
srand(TCNT0); //initialize random generator
}
}
showDices();
}
while(!keyPressed());
bRollDevices = 0;
waitUntilKeyreleased();
}
// show startlogo logo on LED display
void showStartLogo(void)
{
unsigned char i;
for(i = 0; i < 5; i++)
{
dice[i].value = i+2;
dice[i].keep = 1;
}
showDices();
showSymbolRollDices(0);
showSymbolSelectPattern(0);
}
// calculate the score depending on the selected pattern
// pattern: selected pattern for dices
unsigned char score(unsigned char pattern)
{
unsigned char value, i, j, k, cEqual;
bit bNoPoints = 0;
bit bFound;
value = 0;
if(pattern <= 5)
{
for(i = 0; i < 5; i++)
{
if(dice[i].value == (pattern+1))
value += (pattern+1);
}
upperSum += value;
}
else
{
switch(pattern)
{
case P_FULL_HOUSE: // 25 points
cEqual = 1;
for(i = 1; i < 5; i++)
{
if(dice[0].value == dice[i].value)
cEqual++;
}
if(cEqual == 2)
{
for(i = 1; i < 5; i++)
{
if(dice[0].value != dice[i].value)
break;
}
cEqual = 0;
for(j = i; j < 5; j++)
{
if(dice[i].value == dice[j].value)
cEqual++;
}
if(cEqual == 3)
value = 25;
}
else if(cEqual == 3)
{
for(i = 1; i < 5; i++)
{
if(dice[0].value != dice[i].value)
break;
}
cEqual = 0;
for(j = i; j < 5; j++)
{
if(dice[i].value == dice[j].value)
cEqual++;
}
if(cEqual == 2)
value = 25;
}
break;
case P_LARGESTREET: // 40 points
bFound = 0;
for(k = 1; k <= 2; k++)
{
if(!bFound)
{
for(i = k; i <= (k+4); i++)
{
bFound = 0;
for(j = 0; j < 5; j++)
{
if(dice[j].value == i)
bFound = 1;
}
if(!bFound)
break;
}
}
}
if(bFound)
value = 40;
break;
case P_SMALLSTREET: // 30 points
bFound = 0;
for(k = 1; k <= 3; k++)
{
if(!bFound)
{
for(i = k; i <= (k+3); i++)
{
bFound = 0;
for(j = 0; j < 5; j++)
{
if(dice[j].value == i)
bFound = 1;
}
if(!bFound)
break;
}
}
}
if(bFound)
value = 30;
break;
case P_CHANCE: // all dices count
for(i = 0; i < 5; i++)
value += dice[i].value;
break;
case P_3_OF_A_KIND: // all dices count
cEqual = 1;
for(i = 1; i < 5; i++)
{
if(dice[0].value == dice[i].value)
cEqual++;
}
if(cEqual < 3)
{
cEqual = 1;
for(i = 2; i < 5; i++)
{
if(dice[1].value == dice[i].value)
cEqual++;
}
}
if(cEqual < 3)
{
cEqual = 1;
for(i = 3; i < 5; i++)
{
if(dice[2].value == dice[i].value)
cEqual++;
}
}
if(cEqual >= 3)
{
for(i = 0; i < 5; i++)
value += dice[i].value;
}
break;
case P_4_OF_A_KIND: // all dices count
cEqual = 1;
for(i = 1; i < 5; i++)
{
if(dice[0].value == dice[i].value)
cEqual++;
}
if(cEqual < 4)
{
cEqual = 1;
for(i = 2; i < 5; i++)
{
if(dice[1].value == dice[i].value)
cEqual++;
}
}
if(cEqual >= 4)
{
for(i = 0; i < 5; i++)
value += dice[i].value;
}
break;
case P_5_OF_A_KIND: // 50 points
for(i = 1; i < 5; i++)
{
if(dice[0].value != dice[i].value)
bNoPoints = 1;
}
if(!bNoPoints)
value = 50;
break;
}
}
return(value);
}
// show score on display
// score: value to be displayed (0...999)
void showScore(unsigned int score)
{
unsigned char j, k, value, col;
col = 0;
for(k = 2; k != 0xFF; k--)
{
value = score % 10;
col = (k) * 4;
for(j = 0; j < 3; j++)
{ // show decimal using stored font
leds[col++] = ((unsigned int)decimals[value*3 + j] << 2);
}
score = score / 10;
}
}
// main routine
void main(void)
{
unsigned char i, j, roll;
unsigned char x, lastX, blink1, blink2;
unsigned int patternScore;
bit bNoRoll;
init();
initTimers();
initADC();
initInt0();
#asm("sei") // Global enable interrupts
while(1)
{
clearScreen();
showStartLogo();
delay_ms(2000);
clearScreen();
srand(TCNT0); //initialize random generator
iScore = 0;
upperSum = 0;
for(i = 0; i < 13; i++)
{
pattern[i].available = 1;
pattern[i].blink = 0;
}
for(j = 0; j < 13; j++) // 13 patterns to fill
{
for(i = 0; i < 5; i++)
{
dice[i].keep = 0;
dice[i].blink = 0;
}
for(roll = 0; roll < 3; roll++) // up to 3x roll the dices
{
clearScreen();
rollDices();
bNoRoll = 0;
do
{
for(i = 0; i < 5; i++)
{
dice[i].keep = 1;
}
do
{
lastX = 0xFF;
do
{
x = selectDices();
if(x != lastX)
{
if(lastX < 5)
dice[lastX].blink = 0;
}
lastX = x;
blink1 = 0;
blink2 = 0;
if(x < 5)
{
dice[x].blink = 1;
}
else if(x == 5)
{
blink1 = 1;
}
else
{
blink2 = 1;
}
showDices();
showSymbolRollDices(blink1);
showSymbolSelectPattern(blink2);
if(bNoRoll)
{
waitUntilKeyreleased();
bNoRoll = 0;
}
}
while(!keyPressed());
waitUntilKeyreleased();
bNoRoll = 0;
if(x < 5)
{ // dice selected => toggle keep state
if(roll != 2)
{ // only allowed after the first 2 rolls of the dices
if(dice[x].keep)
dice[x].keep = 0;
else
dice[x].keep = 1;
}
}
else if(x == 5)
{ // roll the dices selected
for(i = 0; i < 5; i++)
{
if(dice[i].keep == 0)
break;
}
if( (i == 5) || (roll == 2) )
{ // all dices should be keeped => do not start roll the dices
bNoRoll = 1;
}
}
}
while( (x < 5) || bNoRoll );
showSymbolRollDices(0);
showSymbolSelectPattern(0);
bNoRoll = 0;
if( x == 6 )
{ // show patterns selected
lastX = 0xFF;
do
{
x = selectPatterns();
while( (x != 0xFF) && (pattern[x].available == 0) )
{
x--;
}
while( pattern[x].available == 0 )
{
x++;
}
if(x != lastX)
{
pattern[lastX].blink = 0;
}
lastX = x;
pattern[x].blink = 1;
showPatterns();
}
while(!keyPressed());
pattern[x].blink = 0;
showPatterns();
i = 100;
while(keyPressed() && (i != 0))
{
i--;
}
if(i == 0)
{
bNoRoll = 1;
clearScreen();
}
else
{
patternScore = score(x);
iScore += patternScore;
pattern[x].available = 0;
clearScreen();
showScore(patternScore);
waitUntilKeypressed();
waitUntilKeyreleased();
roll = 3; // leave for-loop for rolling dices
}
}
}
while(bNoRoll);
}
}
clearScreen();
blinkScreen(0xFF);
if(upperSum >= 63)
{
iScore += 35; // add Bonus
}
showScore(iScore);
waitUntilKeypressed();
waitUntilKeyreleased();
blinkScreen(0);
setStandbyMode();
}
}
![]() | Franzis Ping-Pong Produktart: Softwarebox 29,95 € |












