a4 Quelltext
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
CMakeFiles
|
CMakeFiles
|
||||||
.cache
|
.cache
|
||||||
a[1-5]
|
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
|
O: Q 2 links, R 2 links, S 2 links
|
||||||
P: Q 1 links, R 1 links, S 1 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