rust: final

This commit is contained in:
Uğur Küpeli
2022-05-06 16:04:34 +03:00
parent ece3fe0f52
commit 0f2360797b
5 changed files with 207 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
pub struct Disk { pub struct Disk {
size: u8, pub size: u8,
} }
impl Disk { impl Disk {

View File

@@ -1,33 +1,138 @@
use crate::{needle::Needle, util}; use crate::{
disk::Disk,
needle::Needle,
util::{self, prompt, PromptResult},
};
pub struct Game { pub struct Game {
pub needles: Vec<Needle>, pub needles: Vec<Needle>,
_moves: usize, disk_count: u8,
moves: usize,
} }
impl Game { impl Game {
pub fn new() -> Self { pub fn new() -> Self {
let mut needles = Vec::new(); let mut needles = Vec::new();
let disk_count = util::get_disk_count();
for i in 1..=3 { for i in 1..=3 {
let disks = match i { let disks = match i {
1 => util::generate_disks(4), 1 => {
2 => util::generate_disks(3), let mut disks = Vec::new();
_ => Vec::new(),
let mut half_size = 7;
for _ in (1..=disk_count).rev() {
disks.push(Disk::new(half_size * 2 + 1));
half_size -= 1;
}
disks
}
2 | 3 => Vec::new(),
_ => panic!("THERE MUST BE EXACTLY THREE NEEDLES!"),
}; };
needles.push(Needle { disks, number:i }); needles.push(Needle { disks, number: i });
} }
Game { needles, _moves: 0 } Game {
needles,
disk_count,
moves: 0,
}
}
pub fn update(&mut self) -> bool {
self.draw();
loop {
let (disk_index, from_needle_index) = self.get_disk_to_move();
let to_needle_index = self.ask_which_needle();
if from_needle_index == to_needle_index {
println!("DISK IS ALREADY AT THAT NEEDLE!");
break;
}
let to_needle = &self.needles[to_needle_index];
if to_needle.disks.len() == 0
|| to_needle.disks[0].size > self.needles[from_needle_index].disks[disk_index].size
{
self.move_disk(disk_index, from_needle_index, to_needle_index);
break;
} else {
println!("CAN'T PLACE ON A SMALLER DISK!");
}
}
if self.needles[2].disks.len() == self.disk_count as usize {
self.draw();
println!("CONGRATULATIONS!!");
println!("YOU HAVE PERFORMED THE TASK IN {} MOVES.", self.moves);
return true;
}
false
} }
pub fn draw(&self) { pub fn draw(&self) {
println!("");
for r in (1..=7).rev() { for r in (1..=7).rev() {
for n in &self.needles { for n in &self.needles {
n.draw(r) n.draw(r)
} }
println!(""); println!("");
} }
println!("");
}
fn get_disk_to_move(&self) -> (usize, usize) {
loop {
if let PromptResult::Number(n) = prompt(true, "WHICH DISK WOULD YOU LIKE TO MOVE?") {
let smallest_disk = 15 - ((self.disk_count - 1) * 2);
if n < smallest_disk as i32 || n > 15 || (n % 2) == 0 {
println!("PLEASE ENTER A VALID DISK!")
} else {
for (n_i, needle) in self.needles.iter().enumerate() {
if let Some((i, _)) = needle
.disks
.iter()
.enumerate()
.find(|(_, disk)| disk.size == n as u8)
{
if i == (needle.disks.len() - 1) {
return (i, n_i);
}
println!("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.");
}
}
}
}
}
}
fn ask_which_needle(&self) -> usize {
loop {
if let PromptResult::Number(n) = prompt(true, "PLACE DISK ON WHICH NEEDLE?") {
if n <= 0 || n > 3 {
println!("PLEASE ENTER A VALID NEEDLE.");
} else {
return (n - 1) as usize;
}
}
}
}
fn move_disk(&mut self, disk: usize, from: usize, to: usize) {
let from = &mut self.needles[from];
let size = from.disks[disk].size;
from.disks.remove(disk);
self.needles[to].add(size);
self.moves += 1;
} }
} }

View File

@@ -1,4 +1,5 @@
use game::Game; use game::Game;
use util::PromptResult;
mod disk; mod disk;
mod game; mod game;
@@ -6,6 +7,44 @@ mod needle;
mod util; mod util;
fn main() { fn main() {
let game = Game::new(); println!("\n\n\t\tTOWERS");
game.draw(); println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
println!("TOWERS OF HANOI PUZZLE\n");
println!("YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT");
println!("TOWER, ON AT A TIME, NEVER PUTTING A LARGER DISK ON A");
println!("SMALLER DISK.\n");
let mut quit = false;
while !quit {
let mut game = Game::new();
println!("");
println!(
r#"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.
3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,
7 THE NEXT, AND SO ON, UP TO 15. IF YOU DO THE PUZZLE WITH
2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15. WITH 3 DISKS
THE CODE NAMES WOULD BE 11, 13 AND 15, ETC. THE NEEDLES
ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3. WE WILL
START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM
TO NEEDLE 3.
GOOD LUCK!"#
);
loop {
if game.update() {
break;
}
}
if let PromptResult::YesNo(r) = util::prompt(false, "TRY AGAIN (YES OR NO)?") {
quit = !r;
}
}
println!("THANKS FOR THE GAME!");
} }

View File

@@ -7,8 +7,6 @@ pub struct Needle {
impl Needle { impl Needle {
pub fn draw(&self, row: u8) { pub fn draw(&self, row: u8) {
//println!("printing row: {}", row);
let row = row as usize; let row = row as usize;
if self.disks.len() >= row { if self.disks.len() >= row {
@@ -21,4 +19,8 @@ impl Needle {
print!("{offset} "); print!("{offset} ");
} }
} }
pub fn add(&mut self, size: u8) {
self.disks.push(Disk { size });
}
} }

View File

@@ -1,19 +1,51 @@
use crate::disk::Disk; use std::io;
pub fn generate_disks(amount: u8) -> Vec<Disk> { pub enum PromptResult {
if amount > 7 { Number(i32),
println!("CANNOT HAVE MORE THAN 7 DISKS!"); YesNo(bool),
} }
// check for if amount == 0 pub fn prompt(numeric: bool, msg: &str) -> PromptResult {
use PromptResult::*;
let mut disks = Vec::new(); loop {
println!("{}", msg);
let mut half_size = 7;
for _ in (1..=amount).rev() { let mut input = String::new();
disks.push(Disk::new(half_size * 2 + 1));
half_size -= 1; io::stdin()
} .read_line(&mut input)
.expect("Failed to read line.");
disks
let input = input.trim().to_string();
if numeric {
if let Ok(n) = input.parse::<i32>() {
return Number(n);
}
println!("PLEASE ENTER A NUMBER.")
} else {
match input.to_uppercase().as_str() {
"YES" | "Y" => return YesNo(true),
"NO" | "N" => return YesNo(false),
_ => println!("PLEASE ENTER (Y)ES OR (N)O."),
}
}
}
}
pub fn get_disk_count() -> u8 {
loop {
if let PromptResult::Number(n) =
prompt(true, "HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)?")
{
if n <= 2 {
println!("THERE MUST BE AT LEAST 3 DISKS!")
} else if n > 7 {
println!("THERE CAN'T BE MORE THAN 7 DISKS!")
} else {
return n as u8;
}
}
}
} }