Dienstag, 8. Oktober 2013

Hammurabi - die "Vollversion" der Spiellogik mit Ereignissen

Wer sich dafür interessieren sollte:
Hier ist die vollständige Version des Quellcodes zu finden, die hinter der App "Hammurabi" steht. Zumindest der aktuellen Version, denn demnächst wird es eine überarbeitete Version geben.
Es handelt sich dabei um die Klasse, die die Spiellogik und alle Berichte bereitstellt. Im Gegensatz zur einfacheren Version, die in der Artikelreihe "Die 5-Minuten-App" Verwendung fand, hat diese vor allem unterschiedliche Ereignisse, die im Verlauf des Spiels auftreten können.

Wer sich also dafür interessiert findet hier den Quellcode. Wer fragen Fragen oder Anregungen hat: Ich freue mich über eine Nachricht, meine eMail-Adresse ist ja bekannt und auf diesen Seiten zu finden.


/* 
 * Hamurabi
 *
 * Frei nach der urspruenglichen BASIC-Version von David H. Ahl, 
 * dem alleine jegliche Ehre und Dank gebuehren.
 * Veroeffentlicht in den 70er Jahren seinem Buch BASIC Computer Games. 
 *
 * Mein Dank geht an Werner Diwischek und ganz besonders an 
 * Tim Riemer fuer die ausfuehrlichen Kommentare.
 * 
 * Weitere Informationen finden Sie unter www.punktuelles-im-web.net. 
 * Ich freue mich ueber Kommentare, Kritik und weitere Versionen von Hammurabi.
 */

package de.punktuellesimweb.hammurabi;

import java.util.Random;
//TODO: Version noch mehrsprachig machen.
//import android.content.Context;

/**
 * Die Klasse Hammurabi.
 * 
 * Nach dem Aufruf des Konstruktors befindet sich das Spiel im Jahr 1 der
 * hoffentlich glorreichen Herrschaft des Spielers. Mit der Methode getBericht()
 * kann der aktuelle Status des eigenen Reiches jederzeit als ein String
 * abgefragt werden. Eine neue Runde, bzw. neues Jahr startet die Methode
 * zug(int Landkauf, int Landverkauf, int Nahrung, int Saat). Wird das Spielende
 * erreicht, ist kein weiterer Zug moeglich. Das Ende kann mit getEnde()
 * abgefragt werden. Mit getKorn() und getLand() koennen die aktuellen Werte
 * fuer Korn und Land abgefragt werden. Jeder Buerger benoetigt 20 Scheffel
 * Korn. Auf jedem Stueck Land koennen 2 Scheffel Korn ausgesaet werden. Jeder
 * Buerger kann sagenhafte 10 Acker Land bewirtschaften.
 * 
 * @version 2.0 August 2013
 * @author Stephan Elter
 */
public class Hammurabi {

private int verteileKorn = 2000;
private int saeheKorn = 400;
private int kaufeLand = 0;
private int verkaufeLand = 0;
private int ernteProAcker;
private int verstorbeneBuergerGesamt = 0;
private Random random = new Random();

private int jahr = 1;
private int buerger = 100;
private int getKorn = 6000;
private int land = 400;
private int neueBuerger = 0;
private int verstorbeneBuerger = 0;
private int geerntetesKorn = 0;
private int landPreis;
private int plage = 0;
private String abbruchGrund = "";
private String alteEreignisse = "";
private boolean ende = false;

public Hammurabi() {

/*
* erstmalig den Landpreis und Rate fuer Ernte festlegen
*/

bestimmeLandPreis();
bestimmeWetter();

}

private void bestimmeLandPreis() {
/*
* Ganz banal wird der Preis fuer einen Acker Land berechnet. Hier ganz
* ohne goettliche Hilfe, also ohne den Wert noch irgendwie zu
* beeinflussen.
*/
landPreis = random.nextInt(7) + 1;
}

private void bestimmeWetter() {
/*
* Wie wird das Wetter und wie faellt damit die Ernte aus? Auf jeden
* Fall helfen wir der Gluecksfee zugunsten der Spieler ein klein wenig
* auf die Spruenge. Wer dem Spieler etwas mehr helfen moechte, kann
* hier natuerlich noch weiter "unterstuetzend" eingreifen.
*/
ernteProAcker = random.nextInt(5) + random.nextInt(5) + 1;
if (ernteProAcker < 2) {
ernteProAcker = 2;
}
}

public void zug(int verkauf, int ankauf, int nahrung, int saat) {

/*
* Die ganz normale Paranoia, sind die gegebenen Befehle und Werte
* sinnvoll?
*/
if (verkauf < 0) {
verkauf = 0;
}
if (ankauf < 0) {
ankauf = 0;
}
if (nahrung < 1) {
nahrung = 1;
}

if (saat < 0) {
saat = 1;
}
verkaufeLand = verkauf;
kaufeLand = ankauf;
verteileKorn = nahrung;
saeheKorn = saat;

/*
* Vollstaendigen Zug (erst) nach einer Pruefung durchfuehren. Sollte
* das Ende aktuell oder schon frueher erreicht sein, ist kein Zug mehr
* moeglich.
*/

if (!ende) {
if (!pruefeEnde()) {
berechneZug();
}
}

}

private void berechneZug() {

/*
* Hurra! Ein neues Jahr bricht an
*/

jahr = jahr + 1;

/*
* Neues Wetter, neues Glueck? Wie wird die Ernte in diesem Jahr?
*/

bestimmeWetter();

/*
* HANDEL

* Es kann nur verkauft werden wenn genug Land im Besitz ist, und das
* Korn fuer die Order ausreicht. Gleichzeitiger Kauf und Verkauf sind
* moeglich, auch wenn das nicht sinnvoll ist. Es muss immer 1 Acker
* Land im Besitz bleiben und Korn wird zur Sicherheit nie null.
*/
if (verkaufeLand < land) {
if ((getKorn + (verkaufeLand - kaufeLand) * landPreis) > 0) {
land = land + kaufeLand - verkaufeLand;
getKorn = getKorn + (verkaufeLand - kaufeLand) * landPreis;
if (getKorn < 1) {
getKorn = 1;
}
}
}

/*
* NAHRUNG

* Nahrung verteilen. Es kann natuerlich nur verteilt werden was da ist.
* Korn wird zur Sicherheit nie null.
*/
if (verteileKorn > getKorn) {
verteileKorn = getKorn;
}
getKorn = getKorn - verteileKorn;
if (getKorn < 1) {
getKorn = 1;
}

/*
* Auswirkungen der Nahrungsverteilung auf die Bevoelkerung. Reicht das
* Korn fuer alle? 20 Korn pro Buerger? Na dann Prost! Sterben Buerger
* wegen Mangel oder kommen neue Buerger ins Land aufgrund des
* Ueberflusses? Auch hier greifen wir ein um eine moegliche
* Bevoelkerungsexplosion in den Griff zu bekommen.
*/
neueBuerger = 0;
verstorbeneBuerger = 0;
int ausreichendNahrung;
ausreichendNahrung = verteileKorn / 20 - buerger;

if (ausreichendNahrung > 0) {
neueBuerger = ausreichendNahrung / 2;
} else {
verstorbeneBuerger = -ausreichendNahrung;
}

if (neueBuerger > 50) {
neueBuerger = 35 + random.nextInt(20) + 1;
}
verstorbeneBuergerGesamt += verstorbeneBuerger;
buerger = buerger + neueBuerger - verstorbeneBuerger;

/*
* AUSSAAT

* Es kann (ueberraschenderweise) nur das ausgesaeht werden was auch da
* ist, auch zu viel bereitgestelltes Korn verfaellt. Pro Acker werden 2
* Scheffel Korn benoetigt. Sind genug Buerger als Arbeiter zum
* Aussaehen da? Wie viel Land, bzw. Acker stehen zur Aussaat denn noch
* zur Verfuegung?
*/
if (getKorn < saeheKorn) {
saeheKorn = getKorn;
}
getKorn = getKorn - saeheKorn;
if (getKorn < 1) {
getKorn = 1;
}

saeheKorn = saeheKorn / 2;

if (buerger * 10 <= saeheKorn) {
saeheKorn = buerger * 10;
}
if (land < saeheKorn) {
saeheKorn = land;
}

/*
* ERNTE

* Endlich Zeit fuer einen Korn! Verdient haben wir es uns. Da runde
* Zahlen doof sind, machen wir sie eben etwas unrund - falls es
* ueberhaupt eine nennenswerte Ernte gibt.
*/

geerntetesKorn = ernteProAcker * saeheKorn;
if (geerntetesKorn > 150) {
geerntetesKorn = geerntetesKorn + random.nextInt(99);
}
getKorn = getKorn + geerntetesKorn;

/*
* Nur noch neuen aktuellen Landpreis bestimmen
*/
bestimmeLandPreis();

}

public String getBericht() {

if (ende) {
return abbruchGrund;
}

StringBuilder info = new StringBuilder();
StringBuilder ernte = new StringBuilder("\nDas Wetter war ");

/*
* Sicher ist es besser den Text in einer Activity zu erzeugen, damit
* unsere Activities aber aus Platzgruenden schlank bleiben koennen,
* erledigen wir das hier. Please don't try this at home!
*/

switch (ernteProAcker) {

case 1:
case 2:
ernte.append("sehr schlecht. ");
break;
case 3:
ernte.append("schlecht. ");
break;
case 4:
case 5:
ernte.append("normal. ");
break;
case 6:
case 7:
ernte.append("gut. ");
break;
case 8:
case 9:
case 10:
ernte.append("besonders gut. ");
break;
default:
ernte.append("durchschnittlich. ");
}

if (jahr > 1 && geerntetesKorn > 0) {
ernte.append("Die Ernte betrug ");
ernte.append(geerntetesKorn);
ernte.append(" Scheffel Korn. ");
}

info.append("Wir schreiben das Jahr ");
info.append(jahr);
info.append(" Eurer Herrschaft. \n");
info.append("Euer Reich zählt ");
info.append(buerger);
info.append(" treue Bürger. \n");
if (neueBuerger > 0) {
info.append(neueBuerger);
info.append(" neue Bürger kamen in unser Land. \n");
}
if (verstorbeneBuerger > 0) {
info.append("Es starben ");
info.append(verstorbeneBuerger);
info.append(" Bürger. \n");
}
info.append(ernte);
info.append("In den Kornkammern lagern ");
info.append(getKorn);
info.append(" Scheffel Korn. ");
info.append("Ihr besitzt ");
info.append(land);
info.append(" Acker Land. ");
info.append("Ein Acker Land kostet ");
info.append(landPreis);
info.append(" Scheffel Korn. ");

return info.toString();

}

public String getAbbruchGrund() {

return abbruchGrund;
}

public boolean getEnde() {

return ende;
}

public int getKorn() {
return getKorn;
}

public int getLand() {
return land;
}

private boolean pruefeEnde() {

StringBuilder text = new StringBuilder();
/*
* Ist ein Abbruchgrund erreicht? Auch hier waere es sicher besser den
* Text in einer Activity zu erzeugen, So please don't try this at home!
*/
if (verstorbeneBuergerGesamt > 500) {
ende = true;
text.append("Eure Bürger haben sich gegen Eure Herrschaft erhoben. Zu viele Eurer Untertanen starben unter Eurer Herrschaft. ");
}
if (buerger < 10) {
ende = true;
text.append("Ihr habt zu wenige Untertanen. ");
}
if (getKorn < 10) {
ende = true;
text.append("Eure Kornkammern sind leer. ");
}
if (land < 10) {
ende = true;
text.append("Ihr habt zu wenig Land. ");
}
if (jahr > 24 && ende == false) {
ende = true;
text.append("Nach 25 Jahren ist das Ende Eurer Zeit als Herrscher gekommen.\nEuer Name soll auf ewig gerühmt werden! Ihr habt weise und gerecht regiert.");
}
if (ende) {
abbruchGrund = "\nEure Herrschaft ist beendet. " + text.toString();
}

return ende;
}

public String einEreignis() {

String Ereignis = "nichts";
int derGewinn = 0;

if (jahr > 5) {

switch (random.nextInt(15) + 1) {

case 1:
derGewinn = 25 + random.nextInt(500) + random.nextInt(500);
getKorn += derGewinn;
Ereignis = "Steuererhöhung\nEine Erhöhung der Steuern bringen Euch " + derGewinn + " Scheffel Korn.";
break;
case 2:
if (getKorn > 4000) {
if (alteEreignisse.contains(" 2")) {
alteEreignisse += " 2";
derGewinn = getKorn / 4;
getKorn -= derGewinn;
Ereignis = "Staatsbesuch!\nVerwandte besuchen Euch. Die Feierlichkeiten kosten Euch ein Viertel Eurer Kornvorräte.";
}
}
break;
case 3:
if (!alteEreignisse.contains(" 3")) {
alteEreignisse += " 3";
derGewinn = 500 + random.nextInt(500) + random.nextInt(500);
getKorn += derGewinn;
Ereignis = "Eine Gesandtschaft!\nEin fremder König erbittet Eure Freundschaft und sendet Euch wertvolle Geschenke. "
+ derGewinn + " Scheffel Korn füllen Euren Kornspeicher. ";
}
break;
case 4:
derGewinn = 100 + random.nextInt(900) + random.nextInt(900);
getKorn += derGewinn;
Ereignis = "Eine Vermählung!\nEin Angehöriger Eures Hauses heiratet. Eine Mitgift von " + derGewinn
+ " Scheffel Korn füllt Eure Kornspeicher. ";
break;
case 5:
if (verstorbeneBuergerGesamt < 50) {
derGewinn = 3 + random.nextInt(50);
buerger += derGewinn;
Ereignis = "Gütiger Herrscher!\nFlüchtlinge bitte um Aufnahme in Euer Land. " + derGewinn
+ " neue Einwohner zählt Euer Reich. ";
}
break;
case 6:
if (getKorn < 5000) {
if (!alteEreignisse.contains(" 6")) {
alteEreignisse += " 6";
derGewinn = getKorn * 2;
getKorn = derGewinn;
Ereignis = "Die Götter sind Euch gnädig!\nAuf wundersame verdoppelt sich das Korn in Euren Speichern";
}
}
break;
case 7:
if (land > 50) {
if (!alteEreignisse.contains(" 7")) {
alteEreignisse += " 7";
land = land - (random.nextInt(3) + 1);
derGewinn = 100 + random.nextInt(500);
getKorn += derGewinn;
Ereignis = "Opferfest!\nEine Opfergabe stimmt die Götter gnädig! " + derGewinn
+ " Scheffel Korn füllen Euren Kornspeicher. ";
}
}
break;
case 8:
if (plage == 0) {
plage = (random.nextInt(buerger + 1) + 1) / 10;
buerger = buerger - plage;
Ereignis = "Die Götter sind erzürnt!\nEine Plage ist über Euer Reich gekommen! " + plage
+ " Eurer Untertanen starben. ";
}
case 9:
derGewinn = 25 + random.nextInt(75) + random.nextInt(75);
land += derGewinn;
Ereignis = "Krieg!\nEin benachbarter Herrscher hat Euch hinterhältig überfallen! Eure tapferen Truppen aber waren siegreich und Ihr gewinnt "
+ derGewinn + " Acker fruchbares Land.";
break;
case 10:
if (getKorn < 5000 && land > 50) {
if (!alteEreignisse.contains("10")) {
alteEreignisse += "10";
land = land - (random.nextInt(10) + 1);
derGewinn = getKorn * 4 + 1500;
getKorn = derGewinn;
Ereignis = "Tempelbau!\nIhr opfert fruchtbaren Boden um einen neuen Tempel zu bauen. Die Götter sind Euch gnädig gestimmt! Auf wundersame Art füllen sich Eure Kornspeicher mit "
+ derGewinn + " Scheffel Korn.";
}
}
break;
default:
//
}
}
return Ereignis;
}

}

Keine Kommentare:

Kommentar veröffentlichen