Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Javakurs/Übungsaufgaben/Rennschnecke/Musterloesung

Rennschnecke - Musterlösung

Dies ist eine ausführliche Musterlösung der Aufgabenstellung. Vom Wettbüso gibt es zwei unterschiedliche Versionen, von denen die zweite die Zusatzaufgaben berücksichtigt.

Rennschnecke.java

package Schneckenrennen;

import java.util.Random;

/**
 * Eine Schnecke, welche an Rennen teilnehmen kann.
 * @author André Schulz
 * @version 1.0
 */
public class Rennschnecke
{
	private String name;
	private String rasse;
	private double vMax;
	private double strecke;// zurückgelegte Strcke am Startpunkt

	/**
	 * Konstruktor für Schnecken.
	 * @param name Name der Schnecke
	 * @param rasse Rasse der Schnecke
	 * @param vMax Maximalgeschwindigkeit der Schnecke
	 */
	public Rennschnecke(String name, String rasse, double vMax)
	{
		this.name = name;
		this.rasse = rasse;
		this.vMax = vMax;
		this.strecke = 0;
	}

	/**
	 * Bewegt die Schnecke mit einer zufälligen Geschwindigkeit (im Abhängigkeit von der Maximalgeschwindigkeit).
	 */
	public void krieche()
	{
		Random random = new Random();
		// Mximalgeschwindigkeit wird mit 0,01..1 multipliziert
		this.strecke += vMax * (random.nextInt(100) + 1) / 100;
	}

	/**
	 * Gibt den Namen der Schnecke zurück.
	 * @return Name
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * Gibt die Rasse der Schnecke zurück.
	 * @return Rasse
	 */
	public String getRasse()
	{
		return rasse;
	}

	/**
	 * Gibt die Maximalgeschwindigkeit zurück.
	 * @return Maximalgeschwindigkeit
	 */
	public double getVMax()
	{
		return vMax;
	}

	/**
	 * Gibt die bereits zurückgelegte Strecke zurück.
	 * @return zurückgelegt Strecke
	 */
	public double getStrecke()
	{
		return strecke;
	}

	public String toString()
	{
		return "(" + name + "." + rasse + ":" + vMax + "@" + strecke + ")";
	}

	/**
	 * Main-Methode (nur zum Testen)
	 * @param args (keine)
	 */
	public static void main(String[] args)
	{
		Rennschnecke snail = new Rennschnecke("andre", "human", 100);
		System.out.println(snail);
	}
}// class Rennschnecke


Rennen.java

package Schneckenrennen;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Ein Rennen, an dem Schnecken teilnehmen.
 * @author André Schulz
 * @version 1.0
 */
public class Rennen
{
	private String name;
	private ArrayList<Rennschnecke> schnecken;
	private double renndistanz;

	/**
	 * Konstruktor für Schneckenrennen<br>
	 * (Punkt 3) 
	 * @param name Name des Schneckenrennens
	 * @param renndistanz distance off the race
	 */
	public Rennen(String name, double renndistanz)
	{
		this.name = name;
		//leere ArrayList von Schnecken
		this.schnecken = new ArrayList<Rennschnecke>();
		this.renndistanz = renndistanz;
	}

	/**
	 * Fügt eine Schnecke dem Rennen hinzu.<br>
	 *(Punkt 4)
	 * @param schnecke eine zum Rennen hinzuzufügende Schnecke
	 * @throws IllegalArgumentException wenn versucht wird eine Schnecke mehrmals hinzuzufügen
	 */
	public void addRennschnecke(Rennschnecke schnecke)
	{
		//überprüfen, ob die Schnecke schon am Rennen teilnimmt (Doppelteilnahme verhindern)
		//(Zustazpunkt 1)
		if (this.schnecken.contains(schnecke))
		{
			//Exception werfen, wenn die Schnecke schon am Rennen teilnimmt
			throw new IllegalArgumentException("This snail is alredy at this race!");
		}
		
		this.schnecken.add(schnecke);
	}

	/**
	 * Entfernt eine Schnecke aus dem Rennen.<br>
	 * (entfernt alle Schnecken, die den jeweiligen Namen haben)<br>
	 * (Punkt 5)
	 * @param name Name der zu entfernende(n) Schnecke(n)
	 */
	public void removeRennschnecke(String name)
	{
		Rennschnecke schnecke;
		//Iterator um die ArrayList zu durchlaufen
		Iterator<Rennschnecke> iter = this.schnecken.iterator();

		//solange es noch Elemente in der ArrayList gibt...
		while (iter.hasNext())
		{
			//...sich den nächsten Eintrag nehmen...
			schnecke = iter.next();
			
			//...und überprüfen ob der Name mit dem zu entfernenden Namen übereinstimmt...
			if (schnecke.getName().equals(name))
			{
				//...wenn, dann diesen Eintrag aus der ArrayList entfernen
				iter.remove();
			}// if
		}// while
	}// removeSnail

	public String toString()
	{
		//(Punkt 6)
		
		//StringBuilder ist Classe um Strings zu "bauen"
		StringBuilder sb = new StringBuilder();
		
		//Metadaten des Rennens (Name, Teilnehmeranzahl, Distanz)
		sb.append(this.name + "(" + this.schnecken.size() + ") :" + this.renndistanz + "\n");

		//die gesamte ArrayList durchlaufen und alle Schnecke hinzufügen
		for (Rennschnecke snail : this.schnecken)
		{
			sb.append(snail);
			sb.append("\n");
		}// for

		//wenn es einen Gewinner gibt
		if (this.getGewinner() != null)
		{
			//...dann wird er hinzugefügt
			sb.append("Gewinner:");
			sb.append(this.getGewinner());
		}
		else
		{
			//..ansonsten nicht
			sb.append("Rennen noch nicht gestartet!");
		}

		sb.append("\n");

		//den gebauten String in eine echte Zeichenkette konvertieren
		return sb.toString();
	}// toString

	/**
	 * Methode liefert auch einen String, welcher das Rennen repräsentiert,
	 * doch ist der Aufbau etwas übersichtlicher. (tabellarisch)
	 * @return String-Repräsentation des Schneckenrennens
	 */
	public String getPrintString()
	{
		StringBuilder sb = new StringBuilder();

		sb.append("Rennen: '");
		sb.append(this.name);
		sb.append("' Teilnehmer: ");
		sb.append(this.schnecken.size());
		sb.append(" Distanz: ");
		sb.append(this.renndistanz);
		sb.append("\nSchnecken:\n");
		sb.append("+Name\t+Rasse\t+vMax\t+Strecke\n");
		
		for (Rennschnecke snail : this.schnecken)
		{
			sb.append(snail.getName());
			sb.append("\t");//zwischen den einzelnen Atributen der Schnecken wird ein TabStop eingefügt
			sb.append(snail.getRasse());
			sb.append("\t");
			sb.append(snail.getVMax());
			sb.append("\t");
			sb.append(snail.getStrecke());
			sb.append("\t\n");
		}// for
		
		if (this.getGewinner() != null)
		{
			sb.append("Gewinner:");
			sb.append(this.getGewinner());
		}
		else
		{
			sb.append("Rennen noch nicht gestartet!");
		}

		sb.append("\n");
		
		return sb.toString();
	}//getPrintString
	
	/**
	 * Gibt das Rennen tabellarisch auf der Konsole aus.
	 */
	public void print()
	{
		System.out.println(getPrintString());
	}// print

	/**
	 * Gibt den Gewinner des Rennens zurück.<br>
	 * (Gibt <code>null</code> zurück, wenn das Rennen noch nciht beendet wurde.)<br>
	 * (Punkt 8)
	 * @return Gewinner des Rennens
	 */
	public Rennschnecke getGewinner()
	{
		Rennschnecke gewinner = null;//bis jetzt ist noch keiner bekannt...
		
		//durchlaufe alle Schnecken...
		for (Rennschnecke schnecke : this.schnecken)
		{
			//...überprüfe ob eine die Renndistanz zurückgelegt hat
			if (schnecke.getStrecke() > this.renndistanz)
			{
				//wenn bisher noch kein gewinner ermittelt wurde...
				if (gewinner == null)
				{
					//...dann ist die Schnecke der gewinner
					gewinner = schnecke;
				}
				else
				{
					//...andernfalls ist die Schnecke welche weiter ist der Gewinner
					//(Zusatzpunkt 3)
					if (schnecke.getStrecke() > gewinner.getStrecke())
					{
						gewinner = schnecke;
					}
				}
			}// if
		}// for

		return gewinner;
	}//getWinner

	/**
	 * Gibt alle Schnecken zurück.
	 * @return alle Schnecken
	 */
	public ArrayList<Rennschnecke> getSchnecken()
	{
		return this.schnecken;
	}

	/**
	 * Gibt den Namen des Rennens zurück
	 * @return Rennname
	 */
	public String getName()
	{
		return this.name;
	}

	/**
	 * Lässt alle Schnecken ein mal kriechen.<br>
	 * (Punkt 9) 
	 */
	public void lasseSchneckenKriechen()
	{
		for (Rennschnecke snail : this.schnecken)
		{
			snail.krieche();
		}
	}

	/**
	 * Führt das Rennen durch<br>
	 * Bewegt alle Schnecken so lange, bis eine im Zeil ist.<br>
	 * (Punkt 10)
	 */
	public void durchfuehren()
	{
		System.out.println("Rennen '" + this.name + "' wird durchgeführt...");
		
		//so lange es keinen Gewinner gibt...
		while (this.getGewinner() == null)
		{
			//...alle Schnecken ein mal kriechen lassen.
			this.lasseSchneckenKriechen();
		}// while
	}

	/**
	 * Maim-Methode (nur zum Testen)
	 * @param args (keine)
	 */
	public static void main(String[] args)
	{
		Rennen testRennen = new Rennen("Test", 100000);

		testRennen.addRennschnecke(new Rennschnecke("andre", "human", 100));
		testRennen.addRennschnecke(new Rennschnecke("klaus", "human", 90));
		testRennen.addRennschnecke(new Rennschnecke("hans", "human", 75));

		System.out.println(testRennen);
		
		testRennen.durchfuehren();
		System.out.println(testRennen);
	}
}// class Rennen

Wettbuero.java

package Schneckenrennen;

import java.util.ArrayList;

/**
 * Wettbüro (einfache Version)
 * @author André Schulz
 * @version 1.0
 */
public class Wettbuero
{
	private Rennen rennen;
	private ArrayList<Wette> wetten;
	private double faktor;

	/**
	 * Konstruktor für ein Wettbüro.
	 * @param rennen das Rennen, welches dieses Wettbüro betreuen soll
	 * @param faktor der Faktor, welcher bei gewinnen ausgezahlt wird
	 * @throws IllegalArgumentException wenn versucht wird einen negativen Wetteinsatz zu verwenden
	 */
	public Wettbuero(Rennen rennen, double faktor)
	{
		// wenn der Wetteinsatz negativ sein soll => Fehler
		// (Zusatzpunkt 2)
		if (faktor < 0)
		{
			throw new IllegalArgumentException("Es dürfen keine Negativen Wetten abgeschlossen werden!");
		}

		this.rennen = rennen;
		this.faktor = faktor;
		this.wetten = new ArrayList<Wette>();
	}

	/**
	 * Fügt eine Wette hinzu.<br>
	 * (Punkt 2)
	 * @param schneckenname Name der Schnecke auf die gesetzt wird
	 * @param wetteinsatz der Wetteinsatz
	 * @param spielername Name des Spielers, welche doe Wette tätigt
	 */
	public void wetteAnnehmen(String schneckenname, double wetteinsatz, String spielername)
	{
		wetten.add(new Wette(schneckenname, wetteinsatz, spielername));
	}

	/**
	 * Führt das Rennen durch.<br>
	 * (Punkt 3)
	 */
	public void rennenDurchfuehren()
	{
		this.rennen.durchfuehren();
	}

	public String toString()
	{
		// (Punkt 4)

		StringBuilder sb = new StringBuilder();

		// zu erst das Rennen ausgeben
		sb.append("Renen:\n");
		sb.append(this.rennen);
		sb.append("Wetten:\n");

		// dann Wetten ausgeben, wenn vorhanden
		if (wetten.size() > 0)
		{
			for (Wette wette : this.wetten)
			{
				sb.append(wette);
				sb.append("\n");
			}// for
		}
		else
		{
			sb.append("(keine)");
		}

		return sb.toString();
	}// toString

	/**
	 * Gibt das Wettbüro, mit dem dazugehörigen Rennen aus.
	 */
	public void print()
	{
		StringBuilder sb = new StringBuilder();

		sb.append("Wettbüro für:\n");
		sb.append(this.rennen.getPrintString());
		sb.append("Wetten:\n");

		if (wetten.size() > 0)
		{
			for (Wette bet : this.wetten)
			{
				sb.append(bet);
				sb.append("\n");
			}// for
		}
		else
		{
			sb.append("(keine)");
		}

		System.out.println(sb.toString());
	}// print

	/**
	 * Main-Methode (nur zum Testen)
	 * @param args (keine)
	 */
	public static void main(String[] args)
	{
		Rennen rennen = new Rennen("testRace", 100000);

		rennen.addRennschnecke(new Rennschnecke("andre", "human", 100));
		rennen.addRennschnecke(new Rennschnecke("klaus", "human", 90));
		rennen.addRennschnecke(new Rennschnecke("hans", "human", 75));

		Wettbuero wettbuero = new Wettbuero(rennen, 1.5);

		// TODO Wetten hinzufügen

		wettbuero.print();

		wettbuero.rennenDurchfuehren();

		wettbuero.print();

	}// main

	/**
	 * Wette.
	 * @author André Schulz
	 * @version 1.0
	 */
	private class Wette
	{
		private String spielerName;
		private String schneckenName;
		private double wetteinsatz;

		/**
		 * Konstruktor erstellt eine neue Wette.
		 * @param schneckenName Name der Schnecke auf die gesetzt werden soll.
		 * @param wetteinsatz der Wetteinsatz für die Wette
		 * @param spielerName der Name des Spielers
		 */
		public Wette(String schneckenName, double wetteinsatz, String spielerName)
		{
			if (wetteinsatz < 0)
			{
				throw new IllegalArgumentException("betAmount must be >=0!");
			}

			this.spielerName = spielerName;
			this.schneckenName = schneckenName;
			this.wetteinsatz = wetteinsatz;
		}// Wette

		public String toString()
		{
			return this.spielerName + ":" + this.wetteinsatz + "@" + this.schneckenName;
		}

		/**
		 * Gibt den Namen des Spielers dieser Wette zurück.
		 * @return Name des Spielers
		 */
		public String getSpielername()
		{
			return spielerName;
		}

		/**
		 * Gibt den Namen der Schnecke zurück, auf die gesetzt wurde.
		 * @return Name der Schnecke
		 */
		public String getSchneckenname()
		{
			return schneckenName;
		}

		/**
		 * Gibt den Wetteinsatz zurück.
		 * @return Wetteinsatz
		 */
		public double getWetteinsatz()
		{
			return wetteinsatz;
		}
	}// class Wette
}// class Wettbuero


Wettbuero_2.java (verbesserte Version)

package Schneckenrennen;

import java.util.ArrayList;
import java.util.Collections;

/**
 * Wettbüro (verbesserte Version)
 * @author André Schulz
 * @version 2.0
 */
public class Wettbuero_2
{
	private Rennen rennen;
	private ArrayList<Spieler> spieler;
	private ArrayList<Wette> wetten;
	private double faktor;
	private Rennschnecke gewinner;

	/**
	 * Konstruktor für ein Wettbüro.
	 * @param rennen das Rennen, welches dieses Wettbüro betreuen soll
	 * @param faktor der Faktor, welcher bei gewinnen ausgezahlt wird
	 * @throws IllegalArgumentException wenn versucht wird einen negativen Wetteinsatz zu verwenden
	 */
	public Wettbuero_2(Rennen rennen, double faktor)
	{
		// wenn der Wetteinsatz negativ sein sollte => Fehler
		// (Zusatzpunkt 2)
		if (faktor < 0)
		{
			throw new IllegalArgumentException("Es dürfen keine Negativen Wetten abgeschlossen werden!");
		}

		this.rennen = rennen;
		this.faktor = faktor;
		this.spieler = new ArrayList<Spieler>();
		this.wetten = new ArrayList<Wette>();
	}// Wettbuero_2

	/**
	 * Fügt dem Wettbüro einen neuen Spieler hinzu.
	 * @param spielerName der Name des Spielers
	 */
	public Spieler addSpieler(String spielerName)
	{
		// neunen Spieler erstellen
		Spieler spieler = new Spieler(spielerName);

		// wenn der Spieler noch nicht vorhanden ist => hinzufügen
		if (!this.spieler.contains(spieler))
		{
			this.spieler.add(spieler);
		}

		return spieler;
	}// addSpieler

	/**
	 * Fügt eine Wette hinzu.
	 * @param schneckenName der Name der Schnecke, auf die gesetzt werden soll
	 * @param wetteinsatz der Wetteinsatz aud die Schnecke
	 * @param spielerName der Name des Spielers
	 */
	public void addWette(String schneckenName, double wetteinsatz, Spieler spieler)
	{
		for (Rennschnecke snail : this.rennen.getSchnecken())
		{
			if (snail.getName().equals(schneckenName))
			{
				wetten.add(new Wette(snail, wetteinsatz, spieler));
				return;
			}// if
		}// for

		throw new IllegalArgumentException("Eine Schnecke mit dem Namen '" + schneckenName + "' gibts in dem Rennen '" + this.rennen.getName() + " nicht!");
	}// addWette

	/**
	 * Führt das Rennen durch.
	 */
	public void rennenDurchfuehren()
	{
		this.rennen.durchfuehren();
		this.gewinner = this.rennen.getGewinner();
	}

	public String toString()
	{
		StringBuilder sb = new StringBuilder();

		sb.append("Rennen:\n");
		sb.append(this.rennen);
		sb.append("Wetten:\n");

		if (wetten.size() > 0)
		{
			for (Wette bet : this.wetten)
			{
				sb.append(bet);
				sb.append("\n");
			}// for
		}
		else
		{
			sb.append("(keine)");
		}

		return sb.toString();
	}// toString

	/**
	 * Methode wertet alle Wetten aus.
	 */
	public void wettenAuswerten()
	{
		for (Wette wette : this.wetten)
		{
			wette.setzeGewinn(this.gewinner, this.faktor);
		}
	}// wettenAuswerten

	/**
	 * Main-Mthode zum Testen.
	 * @param args (none)
	 */
	public static void main(String[] args)
	{
		// rennen erstellen
		Rennen race = new Rennen("Testrennen", 100000);

		// Schnecken hinzufügen
		race.addRennschnecke(new Rennschnecke("andre", "Mensch", 100));
		race.addRennschnecke(new Rennschnecke("klaus", "Mensch", 90));
		race.addRennschnecke(new Rennschnecke("hans", "Mensch", 75));

		// Wettbüro erstellen
		Wettbuero_2 wettbuero = new Wettbuero_2(race, 1.5);

		// Spieler erstellen
		Spieler spielerAndre = wettbuero.addSpieler("andre");
		Spieler spielerHans = wettbuero.addSpieler("hans");

		// wetten setzen
		wettbuero.addWette("andre", 100, spielerAndre);
		wettbuero.addWette("hans", 100, spielerHans);
		wettbuero.addWette("andre", 10, spielerHans);

		// Wettbüro ausgeben (vor dem Lauf)
		System.out.println(wettbuero);

		// Rennen durchführen udn auswerten
		wettbuero.rennenDurchfuehren();
		wettbuero.wettenAuswerten();

		// Wettbüro ausgeben (nach dem Lauf)
		System.out.println(wettbuero);

		// zeigt die einzelnen Spieler
		System.out.println("Spielerübersicht:");
		wettbuero.zeigeSpieler();
	}// main

	/**
	 * Methode gibt alle Spieler mit ihren jeweiligen Wetten übersichtlich aus.
	 */
	public void zeigeSpieler()
	{
		// sortieren aller Wetten (nach Spielername)
		Collections.sort(this.wetten);

		String oldSpielerName = "";
		double wetteinsatz = 0;// Gesamtwetteinsatz eines Spielers
		double wettgewinn = 0;// Gesamtwettgewinn eines Spielers

		System.out.println("Spieler\tSchnecke\tEinsatz\tGewinn\tSaldo");
		System.out.println("================================================");

		for (Wette wette : this.wetten)
		{
			if (wette.spieler.name == oldSpielerName)
			{
				System.out.println("\t" + wette.schnecke.getRasse() + "." + wette.schnecke.getName() + "\t" + wette.wetteinsatz + "\t" + wette.wettgewinn + "\t" + (wette.wettgewinn - wette.wetteinsatz));

				wetteinsatz += wette.wetteinsatz;
				wettgewinn += wette.wettgewinn;
			}
			else
			{
				if (oldSpielerName != "")
				{
					System.out.println("\t\t\t------------------------");
					System.out.println("\t\t\t" + wetteinsatz + "\t" + wettgewinn + "\t" + (wettgewinn - wetteinsatz));
				}// if

				System.out.println(wette.spieler.name);
				System.out.println("\t" + wette.schnecke.getRasse() + "." + wette.schnecke.getName() + "\t" + wette.wetteinsatz + "\t" + wette.wettgewinn + "\t" + (wette.wettgewinn - wette.wetteinsatz));

				oldSpielerName = wette.spieler.name;
				wetteinsatz = wette.wetteinsatz;
				wettgewinn = wette.wettgewinn;
			}// else
		}// for

		if (oldSpielerName != "")
		{
			System.out.println("\t\t\t------------------------");
			System.out.println("\t\t\t" + wetteinsatz + "\t" + wettgewinn + "\t" + (wettgewinn - wetteinsatz));
		}// if
	}// zeigeSpieler

	/**
	 * Eine Wette.
	 */
	private class Wette implements Comparable<Wette>
	{
		private Spieler spieler;
		private Rennschnecke schnecke;
		private double wetteinsatz;
		private double wettgewinn;

		/**
		 * Konstruktor für wetten.
		 * @param schnecke die Schnecke
		 * @param wetteinsatz der Wetteinsatz
		 * @param spieler der Spieler der wettet
		 */
		public Wette(Rennschnecke schnecke, double wetteinsatz, Spieler spieler)
		{
			if (wetteinsatz < 0)
			{
				throw new IllegalArgumentException("Wetteinsatz muss >=0 sein!");
			}

			this.spieler = spieler;
			this.schnecke = schnecke;
			this.wetteinsatz = wetteinsatz;
			this.wettgewinn = -1;
		}// Wette

		/**
		 * Methode setzt in Abhängigkeit vom Gewinner den Wettgewinn.
		 * @param gewinner die Schnecke, welce das Rennen gewonnen hat
		 * @param faktor der Gewinnfaktor
		 */
		public void setzeGewinn(Rennschnecke gewinner, double faktor)
		{
			if (this.schnecke.equals(gewinner))
			{
				// auf Gewinner gesetzt => Wettgewinn setzen
				this.wettgewinn = this.wetteinsatz * faktor;
			}
			else
			{
				// auf andere Schnecke gesetzt => kein Gewinn
				this.wettgewinn = 0;
			}
		}// setzeGewinn

		public String toString()
		{
			StringBuilder sb = new StringBuilder();
			sb.append(this.spieler);
			sb.append(":");
			sb.append(this.wetteinsatz);
			sb.append("@");
			sb.append(this.schnecke);

			if (this.wettgewinn != -1)
			{
				sb.append("->");
				sb.append(this.wettgewinn);
			}

			return sb.toString();
		}// toString

		@Override
		public int compareTo(Wette other)
		{
			return this.spieler.name.compareTo(other.spieler.name);
		}
	}// class Bet

	/**
	 * Ein Spieler welcher Wetten tätigt.
	 * @author André Schulz
	 * @version 1.0
	 */
	public class Spieler
	{
		private String name;

		public Spieler(String name)
		{
			this.name = name;
		}

		public String getName()
		{
			return this.name;
		}

		public String toString()
		{
			return name;
		}
	}// calss Spieler
}// class Wettbuero_2