a4 Quelltext
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
CMakeFiles
|
||||
.cache
|
||||
a[1-5]
|
||||
Makefile
|
||||
target
|
||||
|
||||
@ -185,3 +185,72 @@ N: Q 1 links, R 1 links
|
||||
O: Q 2 links, R 2 links, S 2 links
|
||||
P: Q 1 links, R 1 links, S 1 links
|
||||
```
|
||||
|
||||
## Quelltext
|
||||
|
||||
```
|
||||
func main() {
|
||||
for i := range querAutos {
|
||||
var currentMoves []movedCar // enthält die Verschiebungen der Autos in die Richtung in der weniger Autos verschoben werden müssen
|
||||
var carLeastSteps uint32
|
||||
for _, direction := range []int{-1, 1} { // -1 steht für links und 1 für rechts
|
||||
movedCars, steps, success := move(i, direction, []movedCar{}, 0, 0)
|
||||
|
||||
/* Wenn das Verschieben der Autos in der jeweiligen Richtung erfolgreich ist und noch keine
|
||||
Verschiebungen abgespeichert wurden, d. h. gerade die Verschiebungen für links berechnet
|
||||
wurden oder das Verschieben nach links nicht erfolgreich war, da das Ende das Parkplatzes
|
||||
erreicht wurde, dann werden die Verschiebungen abgespeichert.
|
||||
Sollten allerdings bereits Verschiebungen für links vorhanden sein, wird das Verschieben nach
|
||||
rechts bevorzugt, wenn weniger Autos verschoben werden mussten oder die Autos weniger Plätze
|
||||
verschoben werden mussten. */
|
||||
if success && (currentMoves == nil || len(movedCars) < len(currentMoves) || len(movedCars) == len(currentMoves) && steps < carLeastSteps) {
|
||||
currentMoves = movedCars
|
||||
carLeastSteps = steps
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zur Berechung der Autos, die für einen Parkplatz verschoben werden müssen.
|
||||
func move(i, direction int, movedCars []movedCar, lastMoved byte, totalSteps uint32) ([]movedCar, uint32, bool) {
|
||||
querAuto := querAutos[i]
|
||||
|
||||
/* Wenn querAuto gleich 0 ist, ist kein Auto vor dem Parkplatz.
|
||||
Wenn es das gleiche Auto ist wie das zuletzt verschobene, ist auch das Verschieben beendet,
|
||||
da dieses Auto bereits ausreichend verschoben wurde. */
|
||||
if querAuto == 0 || querAuto == lastMoved {
|
||||
return movedCars, totalSteps, true
|
||||
}
|
||||
|
||||
/* Wenn neben unserem Auto in der jeweiligen Richtung kein Parkplatz mehr ist,
|
||||
dann können auch keine Autos in diese Richtung verschoben werden. */
|
||||
if outOfBounds(querAutos, i + direction) {
|
||||
return movedCars, totalSteps, false
|
||||
}
|
||||
var steps int
|
||||
/* Wenn sich eins nach der Verschiebungsrichtung auch unserer quer parkendes Auto befindet,
|
||||
muss es nur um einen Platz verschoben werden, ansonsten um zwei. */
|
||||
if querAutos[i + direction] == querAuto {
|
||||
steps = 1
|
||||
} else {
|
||||
steps = 2
|
||||
}
|
||||
endCar := i + direction * 2 // ist das Ende des verschobenen Autos, das realtiv zur verschobenen Richtung, vorne ist.
|
||||
|
||||
/* müsste das Auto ausserhalb des Parkplatzes geschoben werden,
|
||||
damit unser normale Parkplatz frei wird, ist das Verschieben in diese Richtung nicht möglich. */
|
||||
if outOfBounds(querAutos, endCar) {
|
||||
return movedCars, totalSteps, false
|
||||
}
|
||||
// fügt das gerade verschobene Auto der Slice mit den verschobenen Autos hinzu.
|
||||
movedCars = append(movedCars, movedCar{querAuto, steps, direction})
|
||||
/* ruft die Funktion recursive auf, mit dem Index des Parkplatzes an dem
|
||||
noch ein quer stehendes Auto stehen könnte, das verschoben werden müsste. */
|
||||
return move(endCar, direction, movedCars, querAuto, totalSteps + uint32(steps))
|
||||
}
|
||||
|
||||
// Funktion um zu überprüfen, ob ein Index innerhalb einer Slice liegt.
|
||||
func outOfBounds(slice []byte, i int) bool {
|
||||
return i < 0 || i >= len(slice)
|
||||
}
|
||||
```
|
||||
|
||||
107
a2-Vollgeladen/README.md
Normal file
107
a2-Vollgeladen/README.md
Normal file
@ -0,0 +1,107 @@
|
||||
# Vollgeladen
|
||||
|
||||
## Lösungsidee
|
||||
|
||||
Da die niedrigste Bewertung möglichst hoch sein soll, sollte zuerst versucht
|
||||
eine Route mit einer Mindestbewertung von 5.0 zu bilden. Scheitert dies wird
|
||||
es mit 4.9, 4.8, ..., 0.1 versucht. Das Routenbildung mit einer bestimmten
|
||||
Mindestbewertung kann aus zwei Gründen fehlschlagen:
|
||||
|
||||
- innerhalb der 6 Stunden Fahrzeit gibt es kein Hotel mit der Mindestbewertung
|
||||
- an mehr als 4 Hotels muss gehalten werden
|
||||
|
||||
## Umsetzung
|
||||
|
||||
Die Lösungsidee wird in C implementiert. Eine Hilfsfunktion der
|
||||
"advanced C standard library", die Textdateien ausliest, wird außerdem verwendet.
|
||||
Der Quelltext der Library ist im Ordner "lib/advanced_C_standard_library" oder
|
||||
[online](https://git.zinkel.org/MrGeorgen/advanced_C_standard_library) erhältlich.
|
||||
Das Programm erhält als Argumente eine beliebige Anzahl Dateipfade zu Eingabedateien.
|
||||
Mit einer for-Schleife wird über die Dateipfade iteriert. In der Schleife wird die
|
||||
Eingabedatei ausgelesen. Die Anzahl der Hotels und die Gesamtfahrzeit werden jeweils
|
||||
in einer Variable abgespeichert. Anschließend wird ein Array mit Strukturen die Hotels
|
||||
darstellen befüllt. In einer do-while-Schleife wird mit einer Bewertung von
|
||||
5.0, 4.9, ..., 0.1 eine Route zu bilden. Wenn dies bei einer Bewertung erfolgreich
|
||||
ist wird die Schleife beendet. In dieser Schleife ist wiederum eine for-Schleife
|
||||
die über die Hotels iteriert, worin das letzte Hotel gespeichert wird, das
|
||||
mindestens die angestrebte Bewertung hat.
|
||||
Ist das Hotel allerdings mehr als 6 Stunden vom letzten Haltepunkt entfernt,
|
||||
muss das letzte Hotel verwendet werden an dem das Halten möglich ist, falls dieses
|
||||
vorhanden ist und höchtens an drei Hotels schon gehalten wurde,
|
||||
ansonsten muss mit der nächsten Bewertung fortgefahren werden.
|
||||
Nachdem eine Route gefunden wurde, wird diese ausgeben und eventuell mit der
|
||||
näcshten Eingabedatei fortgefahren.
|
||||
|
||||
## Beispiele
|
||||
|
||||
Ergebnisse für die Beispieldaten:
|
||||
|
||||
```
|
||||
hotels1.txt:
|
||||
Entfernung vom Start: 347 Minuten, Bewertung: 2.7
|
||||
Entfernung vom Start: 687 Minuten, Bewertung: 4.4
|
||||
Entfernung vom Start: 1007 Minuten, Bewertung: 2.8
|
||||
Entfernung vom Start: 1360 Minuten, Bewertung: 2.8
|
||||
hotels2.txt:
|
||||
Entfernung vom Start: 341 Minuten, Bewertung: 2.3
|
||||
Entfernung vom Start: 700 Minuten, Bewertung: 3.0
|
||||
Entfernung vom Start: 1053 Minuten, Bewertung: 4.8
|
||||
Entfernung vom Start: 1380 Minuten, Bewertung: 5.0
|
||||
hotels3.txt:
|
||||
Entfernung vom Start: 360 Minuten, Bewertung: 1.0
|
||||
Entfernung vom Start: 717 Minuten, Bewertung: 0.3
|
||||
Entfernung vom Start: 1076 Minuten, Bewertung: 3.8
|
||||
Entfernung vom Start: 1433 Minuten, Bewertung: 1.7
|
||||
hotels4.txt:
|
||||
Entfernung vom Start: 340 Minuten, Bewertung: 4.6
|
||||
Entfernung vom Start: 676 Minuten, Bewertung: 4.6
|
||||
Entfernung vom Start: 1032 Minuten, Bewertung: 4.9
|
||||
Entfernung vom Start: 1316 Minuten, Bewertung: 4.9
|
||||
hotels5.txt:
|
||||
Entfernung vom Start: 317 Minuten, Bewertung: 5.0
|
||||
Entfernung vom Start: 636 Minuten, Bewertung: 5.0
|
||||
Entfernung vom Start: 987 Minuten, Bewertung: 5.0
|
||||
Entfernung vom Start: 1286 Minuten, Bewertung: 5.0
|
||||
```
|
||||
|
||||
## Quelltext
|
||||
|
||||
```
|
||||
int main() {
|
||||
uint_least8_t rating = 50;
|
||||
do {
|
||||
// Minuten die das letzte Hotel, bei dem angehalten wurde, vom Start entfertn ist
|
||||
uint_least16_t lastHotelMinutes = 0;
|
||||
// Zeiger zum letzten Hotel, dessen Bewertung mindestens "rating" ist.
|
||||
struct hotel *possibleStop = NULL;
|
||||
stoppedHotels = 0; // setzt Anzahl der Stops zurück
|
||||
|
||||
// iteriert über die Hotels
|
||||
for(struct hotel *currentHotel = hotels; currentHotel - hotels < numberHotels; ++currentHotel) {
|
||||
|
||||
/* Wenn das aktuelle Hotel mehr als 360 Minuten vom letzten Hotel entfernt ist,
|
||||
* muss das letzte Hotel verwendet werden an dem das Halten möglich war.*/
|
||||
if(currentHotel->minutes - lastHotelMinutes > 360) {
|
||||
/* Wenn das Halten nicht möglich ist oder bereits schon viermal
|
||||
* gehalten wurde, muss es mit einer niedrigeren Bewertung versucht
|
||||
* werden.*/
|
||||
if(possibleStop == NULL || stoppedHotels >= 4) break;
|
||||
// hängt das Hotel der Route an
|
||||
hotelRoute[stoppedHotels] = *possibleStop;
|
||||
lastHotelMinutes = possibleStop->minutes;
|
||||
// springt in der Schleife zurück zum Hotel, an dem gestoppt wurde
|
||||
currentHotel = possibleStop;
|
||||
++stoppedHotels;
|
||||
}
|
||||
// Wenn die Bewertung hoch genug ist, kann gestoppt werden.
|
||||
if(currentHotel->rating >= rating) possibleStop = currentHotel;
|
||||
}
|
||||
--rating;
|
||||
/* Schleife läuft solange "rating" mindestens Eins ist, da es keine niedrigeren Bewertungen
|
||||
* gibt. Wenn das letzte Hotel höchtens 360 Minuten vom Zielort entfernt ist, wurde
|
||||
* erfolgreich eine Route gefunden und die Schleife wird beendet. Allerdings wird dies nur
|
||||
* überprüft, wenn überhaupt an einem Hotel gehalten wurde, um den Zugriff auf nicht
|
||||
* definierten Speicher zu vermeiden.*/
|
||||
} while(rating && (!stoppedHotels || totalMinutes - hotelRoute[stoppedHotels - 1].minutes > 360));
|
||||
}
|
||||
```
|
||||
85
a4-Wuerfelglueck/Cargo.lock
generated
Normal file
85
a4-Wuerfelglueck/Cargo.lock
generated
Normal file
@ -0,0 +1,85 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "a4-Wuerfelglueck"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
9
a4-Wuerfelglueck/Cargo.toml
Normal file
9
a4-Wuerfelglueck/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "a4-Wuerfelglueck"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.4"
|
||||
5
a4-Wuerfelglueck/README.md
Normal file
5
a4-Wuerfelglueck/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Würfelglück
|
||||
|
||||
## Lösungsidee
|
||||
|
||||
|
||||
260
a4-Wuerfelglueck/src/main.rs
Normal file
260
a4-Wuerfelglueck/src/main.rs
Normal file
@ -0,0 +1,260 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::vec;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use std::collections::HashSet;
|
||||
|
||||
// Struktur für die Würfel
|
||||
struct Dice {
|
||||
wins: u32,
|
||||
defeats: u32,
|
||||
sides: vec::Vec<u8>,
|
||||
|
||||
// Iterator über Zufallszahlen von der "rand" Bibliothek
|
||||
rand_iter: rand::distributions::DistIter<Uniform<usize>, rand::rngs::ThreadRng, usize>,
|
||||
different_sides_count: u8 // wird benötigt, um festzustellen, ob ein Spieler stecken geblieben ist
|
||||
}
|
||||
|
||||
/* Struktur, die das Spielfeld darstellt. Die Member b, destination und pieces sind 2er-Arrays von
|
||||
* den eigentlichen Arrays (Die Elemente von b sind kein Array. Für diese gilt allerdings das
|
||||
* gleiche.) Das Array mit dem Index 0 gehört jeweils zu Spieler 0 und das andere zu
|
||||
* Spieler 1. Diesen Spielern sind keine Farben zugeordnet. Wichtig ist nur, dass sie gegenüber
|
||||
* liegen. */
|
||||
struct Field {
|
||||
b: [u8; 2], // Anzahl der Figuren auf den B Feldern
|
||||
|
||||
/* Laufbahn: Feld A von Spieler 0 ist bei Index 0 und von Spieler 1 bei Index 20.
|
||||
* 0 und 1 repräsentieren die Spieler und -1 ein leeres Feld. */
|
||||
main: [i8; 40],
|
||||
destination: [[i8; 4]; 2], // Zielfelder
|
||||
|
||||
/* Indexe der Figuren: 0-39 für die Laufbahn. -1 ist das Zielfeld, das man am schnellsten
|
||||
* erreicht und -4 das Letzte. -5 ist eine Figur auf Feld B. */
|
||||
pieces: [[i8; 4]; 2]
|
||||
}
|
||||
impl Field {
|
||||
|
||||
// Methode, die die Figuren laufen lässt. piece ist der Index im piece Array.
|
||||
fn step(&mut self, turn: usize, piece: usize, steps: u8) -> bool {
|
||||
let i_start = self.pieces[turn][piece]; // Feld auf dem die Figur momentan steht
|
||||
let i_end = if i_start >= 0 {
|
||||
|
||||
// Feld auf das Figur nach dem Zug steht, solange es keine Besonderheiten gibt.
|
||||
let i = i_start + steps as i8;
|
||||
if turn == 0 {
|
||||
let end = self.main.len() as i8 - 1;
|
||||
|
||||
// Sollte i abseits der Laufbahn liegen, so läuft Spieler 0 ins Ziel.
|
||||
if i > end {end - i} else {i}
|
||||
}
|
||||
else {
|
||||
if i >= 20 && i_start < 20 {19 - i} // Nach Index 19 ist für Spieler 1 das Ziel.
|
||||
|
||||
// Nach Index 39 muss Spieler 1 wieder bei Index 0 anfangen.
|
||||
else if i >= self.main.len() as i8 {i - self.main.len() as i8} else {i}
|
||||
}
|
||||
}
|
||||
else if i_start == -5 {(20 * turn) as i8} // startet die Figur auf einem B-Feld, muss sie auf Feld A.
|
||||
|
||||
/* ist die Figur bereits auf einem Zielfeld, muss sie in negativer Richtung laufen, da die
|
||||
* Zielfelder Indexe auch negativ sind. */
|
||||
else {i_start - steps as i8};
|
||||
|
||||
/* Würde die Figur außerhalb des Spielfelds laufen oder das Feld wird von einer eignen
|
||||
* Figur blockiert, kann sie nicht laufen. */
|
||||
if i_end < -4 || *self.at(turn, i_end) == turn as i8 {
|
||||
return false;
|
||||
}
|
||||
self.beat(turn, i_end); // schlägt mögliche gegnerische Figuren
|
||||
|
||||
// setzt die Figur an die neue Position
|
||||
self.pieces[turn][piece] = i_end;
|
||||
if i_start == -5 {self.b[turn] -= 1;}
|
||||
else {*self.at(turn, i_start) = -1;}
|
||||
*self.at(turn, i_end) = turn as i8;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Methode, die gegnerische Figuren schlägt, wenn eine an der angebenen Position steht.
|
||||
fn beat(&mut self, turn: usize, position: i8) {
|
||||
let not_turn = other_player(turn);
|
||||
if position >= 0 && self.main[position as usize] == not_turn as i8 {
|
||||
for piece in self.pieces[not_turn].iter_mut() {
|
||||
if *piece == position {
|
||||
*piece = -5;
|
||||
self.b[not_turn] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Methode, welche eine Referenz zu der Figur mit dem entsprechenden Index zurückgibt.
|
||||
fn at(&mut self, player: usize, position: i8) -> &mut i8 {
|
||||
if position >= 0 {&mut self.main[position as usize]}
|
||||
else {&mut self.destination[player][(-position - 1) as usize]}
|
||||
}
|
||||
|
||||
// sucht eine Figur mit der entsprechenden Position und gibt den piece Array Index zurück.
|
||||
fn field_i_to_piece_i(&self, player: usize, position: i8) -> Option<usize> {
|
||||
for (i, piece) in self.pieces[player].iter().enumerate() {
|
||||
if *piece == position {return Some(i);}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let runs = 100000; // Anzahl der Spiele, die für jede mögliche Würfelkombination simuliert wird
|
||||
for filepath in env::args().skip(1) { // for-Schleife, die über Dateipfade der Eingabedateien iteriert
|
||||
let mut dices: vec::Vec<Dice>;
|
||||
let content = fs::read_to_string(&filepath).unwrap(); // Eingabedatei wird gelesen.
|
||||
let mut line_iter = content.lines(); // Iterator über die Zeilen der Datei
|
||||
let mut no_move_possible: [HashSet<u8>; 2] = [HashSet::with_capacity(20), HashSet::with_capacity(20)];
|
||||
|
||||
// Speicher für die Würfel wird reserviert.
|
||||
dices = vec::Vec::with_capacity(line_iter.next().unwrap().parse().unwrap());
|
||||
for line in line_iter {
|
||||
let mut dice: Dice;
|
||||
{
|
||||
let mut dice_sides = line.split(" "); // Die Zahlen für einen Würfel werden mit einem Leerzeichen getrennt.
|
||||
let dice_sides_count = dice_sides.next().unwrap().parse().unwrap();
|
||||
dice = Dice {
|
||||
wins: 0,
|
||||
defeats: 0,
|
||||
sides: vec::Vec::with_capacity(dice_sides_count),
|
||||
|
||||
/* Zufallszahleniterator wird erstellt, der Zahlen von 0 (inklusive) bis zur
|
||||
* Anzahl der verschieden Seiten des Würfels (exklusive) generiert. */
|
||||
rand_iter: Uniform::new(0, dice_sides_count).sample_iter(rand::thread_rng()),
|
||||
different_sides_count: 0
|
||||
};
|
||||
for side in dice_sides {
|
||||
// Die Augenzahlen des Würfels werden im einen Vector gespeichert.
|
||||
dice.sides.push(side.parse().unwrap());
|
||||
}
|
||||
|
||||
// bestimmt die Anzahl der verschiedenen Augenzahlen
|
||||
{
|
||||
let mut different_sides_count = 0;
|
||||
let mut last_side: Option<u8> = None;
|
||||
for side in dice.sides.iter() {
|
||||
if last_side != Some(*side) {different_sides_count += 1;}
|
||||
last_side = Some(*side);
|
||||
}
|
||||
dice.different_sides_count = different_sides_count as u8;
|
||||
}
|
||||
}
|
||||
|
||||
// der Würfel tritt gegen alle bereits verarbeiteten an.
|
||||
for dice_other in dices.iter_mut() {
|
||||
let mut selected_dices = [&mut dice, dice_other]; // der Würfel mit dem Index 0, ist auch Spieler 0 und der andere Spieler 1.
|
||||
for begin in [0, 1] { // das Spiel wird von beiden Spieler gleich oft angefangen
|
||||
for _ in 0..runs {
|
||||
let mut turn = begin;
|
||||
let mut field = Field { // Spielfeld in der Ausgangsstellung
|
||||
b: [4; 2],
|
||||
main: [-1; 40],
|
||||
destination: [[-1; 4]; 2],
|
||||
pieces: [[-5; 4]; 2],
|
||||
};
|
||||
let mut win = false;
|
||||
while !win { // Schleife solange niemand gewonnen hat.
|
||||
|
||||
// würfelt mittels Zufallsgenerator.
|
||||
let dice_result = selected_dices[turn].sides[selected_dices[turn].rand_iter.next().unwrap()];
|
||||
let field_0_blocked = field.main[turn * 20] == turn as i8;
|
||||
|
||||
// Wenn eine Figur gezogen wurde
|
||||
if field.b[turn] != 0 && (field_0_blocked && // ist Feld A blockiert ...
|
||||
|
||||
// ... wird das Feld freigeräumt.
|
||||
field.step(turn, field.field_i_to_piece_i(turn, (turn * 20) as i8).unwrap() , dice_result) ||
|
||||
|
||||
// Bei einer 6 wird eine neue Figur herrausgezogen.
|
||||
dice_result == 6 && field.step(turn, field.field_i_to_piece_i(turn, -5).unwrap(), dice_result)) || {
|
||||
let mut result = false;
|
||||
|
||||
// die Figuren werden sortiert; die nah am Ziel sind kommen zuerst.
|
||||
field.pieces[turn].sort_by(|a, b| {
|
||||
let mut values = [*a, *b];
|
||||
if turn == 1 {
|
||||
for value in values.iter_mut() {
|
||||
if *value >= 0 && *value < 20 {*value += 40;}
|
||||
}
|
||||
}
|
||||
values[1].partial_cmp(&values[0]).unwrap()
|
||||
});
|
||||
|
||||
// Es wird versucht die Figuren zu ziehen.
|
||||
let pieces_turn = field.pieces[turn];
|
||||
for (i, position) in pieces_turn.iter().enumerate() {
|
||||
if *position == -5 {break;}
|
||||
if field.step(turn, i, dice_result) {result = true; break;}
|
||||
}
|
||||
result
|
||||
} {
|
||||
|
||||
// ein Spieler hat gewonnen wenn alle seine Figuren im Ziel sind.
|
||||
win = true;
|
||||
for piece in field.destination[turn] {
|
||||
win &= piece == turn as i8;
|
||||
}
|
||||
if win { // hat jemand gewonnen, werden die Sieges- und Niederlagenzähler erhöht.
|
||||
selected_dices[turn].wins += 1;
|
||||
selected_dices[other_player(turn)].defeats += 1;
|
||||
}
|
||||
|
||||
/* Da wieder eine Figur gezogen wurde, muss der HashSet mit den
|
||||
* Augenzahlen bei denen nicht gezogen werden kann, zurückgesetzt
|
||||
* werden. */
|
||||
for map in no_move_possible.iter_mut() {
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
/* Konnte keine Figur gezogen werden, wird die Augenzahl in einem
|
||||
* HashSet abgespeichert. */
|
||||
no_move_possible[turn].insert(dice_result);
|
||||
|
||||
/* Kann bei keiner möglichen Augenzahl gezogen beider Spieler
|
||||
* gezogen werden, ist das Spiel unentschieden. */
|
||||
if no_move_possible[turn].len() as u8 == selected_dices[turn].different_sides_count &&
|
||||
no_move_possible[other_player(turn)].len() as u8 == selected_dices[other_player(turn)].different_sides_count {
|
||||
break;
|
||||
}
|
||||
}
|
||||
turn = other_player(turn); // beim nächsten Zug ist der andere Spieler dran.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dices.push(dice);
|
||||
}
|
||||
|
||||
// sotiert die Würfel nach Gewinnen
|
||||
dices.sort_unstable_by(|a, b| b.wins.partial_cmp(&a.wins).unwrap());
|
||||
|
||||
|
||||
// gibt das Ergebnis aus
|
||||
let games_per_dice = ((dices.len() - 1) * runs * 2) as u32;
|
||||
println!("{}:", filepath);
|
||||
for (i, dice) in dices.iter().enumerate() {
|
||||
let ties = games_per_dice - dice.wins - dice.defeats;
|
||||
println!(concat!("{i}. Würfel: Würfelseiten: {würfelseiten:?}, ",
|
||||
"Siege: {siege}, Siegwahrscheinlichkeit: {siegwahrscheinlichkeit}, ",
|
||||
"Niederlagen: {niederlagen}, Niederlagewahrscheinlichkeit: {niederlagewahrscheinlichkeit}, ",
|
||||
"Unentschieden: {unentschieden}, Unentschiedenwahrscheinlichkeit: {unentschiedenwahrscheinlichkeit}"),
|
||||
i = i + 1, würfelseiten = dice.sides,
|
||||
siege = dice.wins, siegwahrscheinlichkeit = dice.wins as f64 / games_per_dice as f64,
|
||||
niederlagen = dice.defeats, niederlagewahrscheinlichkeit = dice.defeats as f64 / games_per_dice as f64,
|
||||
unentschieden = ties, unentschiedenwahrscheinlichkeit = ties as f64 / games_per_dice as f64
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion, um den anderen Spieler zu erhalten
|
||||
fn other_player(player: usize) -> usize {
|
||||
if player == 0 {1} else {0}
|
||||
}
|
||||
Reference in New Issue
Block a user