a4 Quelltext
This commit is contained in:
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