From af19e969a974d0e690d0dccb75af9f89f3276395 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 23 Feb 2022 23:39:06 -0800 Subject: [PATCH 01/21] rust port of Amazing --- 02_Amazing/rust/Cargo.toml | 9 ++ 02_Amazing/rust/src/main.rs | 197 ++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 02_Amazing/rust/Cargo.toml create mode 100644 02_Amazing/rust/src/main.rs diff --git a/02_Amazing/rust/Cargo.toml b/02_Amazing/rust/Cargo.toml new file mode 100644 index 00000000..276ea543 --- /dev/null +++ b/02_Amazing/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +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.5" \ No newline at end of file diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs new file mode 100644 index 00000000..cef8496c --- /dev/null +++ b/02_Amazing/rust/src/main.rs @@ -0,0 +1,197 @@ +use rand::{Rng, thread_rng, prelude::SliceRandom}; +use std::{io, collections::HashSet}; + +fn main() { + //DATA + enum Direction { + LEFT=0, + UP=1, + RIGHT=2, + DOWN=3, + } + impl Direction { + fn val(&self) -> usize { + match self { + Direction::LEFT=>0, + Direction::UP=>1, + Direction::RIGHT=>2, + Direction::DOWN=>3, + } + } + } + const EXIT_DOWN:usize = 1; + const EXIT_RIGHT:usize = 2; + let mut rng = thread_rng(); //rng + /* + vector of: + vectors of: + integers + Initially set to 0, unprocessed cells. + Filled in with consecutive non-zero numbers as cells are processed + */ + let mut used; //2d vector + /* + vector of: + vectors of: + integers + Remains 0 if there is no exit down or right + Set to 1 if there is an exit down + Set to 2 if there is an exit right + Set to 3 if there are exits down and right + */ + let mut walls; //2d vector + let width; + let height; + let entrance_column; //rng, column of entrance + let mut row; + let mut col; + let mut count; + + + + //print welcome message + println!(" + AMAZING PROGRAM + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n"); + + //prompt for input + width = get_user_input("What is your width?"); + print!("\n"); //one blank line below + height = get_user_input("What is your height?"); + print!("\n\n\n\n");//4 blank lines below + + //generate maze + //initialize used and wall vectors + //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) + used = vec![0; (width * height) as usize]; + let mut used: Vec<_> = used.as_mut_slice().chunks_mut(width as usize).collect(); + let used = used.as_mut_slice(); //accessible as used[][] + //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) + walls = vec![0; (width * height) as usize]; + let mut walls: Vec<_> = walls.as_mut_slice().chunks_mut(width as usize).collect(); + let walls = walls.as_mut_slice(); //accessible as walls[][] + + entrance_column=rng.gen_range(0..width-1); + row = 0; + col = entrance_column; + count = 1; + used[row][col] = count; + count += 1; + + while count != width*height + 1 { + //remove possible directions that are blocked or + //hit cells already processed + let mut possible_directions: HashSet = vec![Direction::LEFT.val(),Direction::UP.val(),Direction::RIGHT.val(),Direction::DOWN.val()].into_iter().collect(); + if col==0 || used[row][col-1]!=0 { + possible_directions.remove(&Direction::LEFT.val()); + } + if row==0 || used[row-1][col]!=0 { + possible_directions.remove(&Direction::UP.val()); + } + if col==width-1 || used[row][col+1]!=0 { + possible_directions.remove(&Direction::RIGHT.val()); + } + if row==height-1 || used[row+1][col]!=0 { + possible_directions.remove(&Direction::DOWN.val()); + } + + //If we can move in a direction, move and make opening + if possible_directions.len() != 0 { //all values in possible_directions are not NONE + let pos_dir_vec: Vec<_> = possible_directions.into_iter().collect(); // convert the set to a vector to get access to the choose method + //select a random direction + match pos_dir_vec.choose(&mut rng).expect("error") { + 0=> { + col -= 1; + walls[row][col] = EXIT_RIGHT; + }, + 1=> { + row -= 1; + walls[row][col] = EXIT_DOWN; + }, + 2=>{ + walls[row][col] = walls[row][col] + EXIT_RIGHT; + col += 1; + }, + 3=>{ + walls[row][col] = walls[row][col] + EXIT_DOWN; + row += 1; + }, + _=>{}, + } + used[row][col]=count; + count += 1; + } + //otherwise, move to the next used cell, and try again + else { + loop { + if col != width-1 {col += 1;} + else if row != height-1 {row+=1; col=0;} + else {row=0;col=0;} + + if used[row][col] != 0 {break;} + } + } + + } + // Add a random exit + col=rng.gen_range(0..width); + row=height-1; + walls[row][col]+=1; + + //print maze + //first line + for c in 0..width { + if c == entrance_column { + print!(". "); + } + else { + print!(".--"); + } + } + println!("."); + //rest of maze + for r in 0..height { + print!("I"); + for c in 0..width { + if walls[r][c]<2 {print!(" I");} + else {print!(" ");} + } + println!(); + for c in 0..width { + if walls[r][c] == 0 || walls[r][c]==2 {print!(":--");} + else {print!(": ");} + } + println!("."); + } + + + + + + +} + +fn get_user_input(prompt: &str) -> usize { + //DATA + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //input loop + return loop { + + //print prompt + println!("{}", prompt); + + //read user input from standard input, and store it to raw_input + raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + match raw_input.trim().parse::() { + Ok(i) => break i, // this escapes the loop, returning i + Err(e) => { + println!("MEANINGLESS DIMENSION. TRY AGAIN. {}", e.to_string().to_uppercase()); + continue; // run the loop again + } + }; + } +} From 35e01319311761f1238e54f10f7d470d17a786b3 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 23 Feb 2022 23:39:06 -0800 Subject: [PATCH 02/21] rust port of Amazing --- 02_Amazing/rust/Cargo.toml | 9 ++ 02_Amazing/rust/src/main.rs | 197 ++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 02_Amazing/rust/Cargo.toml create mode 100644 02_Amazing/rust/src/main.rs diff --git a/02_Amazing/rust/Cargo.toml b/02_Amazing/rust/Cargo.toml new file mode 100644 index 00000000..276ea543 --- /dev/null +++ b/02_Amazing/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +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.5" \ No newline at end of file diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs new file mode 100644 index 00000000..cef8496c --- /dev/null +++ b/02_Amazing/rust/src/main.rs @@ -0,0 +1,197 @@ +use rand::{Rng, thread_rng, prelude::SliceRandom}; +use std::{io, collections::HashSet}; + +fn main() { + //DATA + enum Direction { + LEFT=0, + UP=1, + RIGHT=2, + DOWN=3, + } + impl Direction { + fn val(&self) -> usize { + match self { + Direction::LEFT=>0, + Direction::UP=>1, + Direction::RIGHT=>2, + Direction::DOWN=>3, + } + } + } + const EXIT_DOWN:usize = 1; + const EXIT_RIGHT:usize = 2; + let mut rng = thread_rng(); //rng + /* + vector of: + vectors of: + integers + Initially set to 0, unprocessed cells. + Filled in with consecutive non-zero numbers as cells are processed + */ + let mut used; //2d vector + /* + vector of: + vectors of: + integers + Remains 0 if there is no exit down or right + Set to 1 if there is an exit down + Set to 2 if there is an exit right + Set to 3 if there are exits down and right + */ + let mut walls; //2d vector + let width; + let height; + let entrance_column; //rng, column of entrance + let mut row; + let mut col; + let mut count; + + + + //print welcome message + println!(" + AMAZING PROGRAM + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n"); + + //prompt for input + width = get_user_input("What is your width?"); + print!("\n"); //one blank line below + height = get_user_input("What is your height?"); + print!("\n\n\n\n");//4 blank lines below + + //generate maze + //initialize used and wall vectors + //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) + used = vec![0; (width * height) as usize]; + let mut used: Vec<_> = used.as_mut_slice().chunks_mut(width as usize).collect(); + let used = used.as_mut_slice(); //accessible as used[][] + //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) + walls = vec![0; (width * height) as usize]; + let mut walls: Vec<_> = walls.as_mut_slice().chunks_mut(width as usize).collect(); + let walls = walls.as_mut_slice(); //accessible as walls[][] + + entrance_column=rng.gen_range(0..width-1); + row = 0; + col = entrance_column; + count = 1; + used[row][col] = count; + count += 1; + + while count != width*height + 1 { + //remove possible directions that are blocked or + //hit cells already processed + let mut possible_directions: HashSet = vec![Direction::LEFT.val(),Direction::UP.val(),Direction::RIGHT.val(),Direction::DOWN.val()].into_iter().collect(); + if col==0 || used[row][col-1]!=0 { + possible_directions.remove(&Direction::LEFT.val()); + } + if row==0 || used[row-1][col]!=0 { + possible_directions.remove(&Direction::UP.val()); + } + if col==width-1 || used[row][col+1]!=0 { + possible_directions.remove(&Direction::RIGHT.val()); + } + if row==height-1 || used[row+1][col]!=0 { + possible_directions.remove(&Direction::DOWN.val()); + } + + //If we can move in a direction, move and make opening + if possible_directions.len() != 0 { //all values in possible_directions are not NONE + let pos_dir_vec: Vec<_> = possible_directions.into_iter().collect(); // convert the set to a vector to get access to the choose method + //select a random direction + match pos_dir_vec.choose(&mut rng).expect("error") { + 0=> { + col -= 1; + walls[row][col] = EXIT_RIGHT; + }, + 1=> { + row -= 1; + walls[row][col] = EXIT_DOWN; + }, + 2=>{ + walls[row][col] = walls[row][col] + EXIT_RIGHT; + col += 1; + }, + 3=>{ + walls[row][col] = walls[row][col] + EXIT_DOWN; + row += 1; + }, + _=>{}, + } + used[row][col]=count; + count += 1; + } + //otherwise, move to the next used cell, and try again + else { + loop { + if col != width-1 {col += 1;} + else if row != height-1 {row+=1; col=0;} + else {row=0;col=0;} + + if used[row][col] != 0 {break;} + } + } + + } + // Add a random exit + col=rng.gen_range(0..width); + row=height-1; + walls[row][col]+=1; + + //print maze + //first line + for c in 0..width { + if c == entrance_column { + print!(". "); + } + else { + print!(".--"); + } + } + println!("."); + //rest of maze + for r in 0..height { + print!("I"); + for c in 0..width { + if walls[r][c]<2 {print!(" I");} + else {print!(" ");} + } + println!(); + for c in 0..width { + if walls[r][c] == 0 || walls[r][c]==2 {print!(":--");} + else {print!(": ");} + } + println!("."); + } + + + + + + +} + +fn get_user_input(prompt: &str) -> usize { + //DATA + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //input loop + return loop { + + //print prompt + println!("{}", prompt); + + //read user input from standard input, and store it to raw_input + raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + match raw_input.trim().parse::() { + Ok(i) => break i, // this escapes the loop, returning i + Err(e) => { + println!("MEANINGLESS DIMENSION. TRY AGAIN. {}", e.to_string().to_uppercase()); + continue; // run the loop again + } + }; + } +} From 36bccfdbe3ff90e2c59bfcf88dc1a209131a9233 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Fri, 25 Feb 2022 13:29:29 -0800 Subject: [PATCH 03/21] start rust port of blackjack --- 10_Blackjack/rust/Cargo.toml | 9 +++ 10_Blackjack/rust/src/main.rs | 105 ++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 10_Blackjack/rust/Cargo.toml create mode 100644 10_Blackjack/rust/src/main.rs diff --git a/10_Blackjack/rust/Cargo.toml b/10_Blackjack/rust/Cargo.toml new file mode 100644 index 00000000..1c2935d4 --- /dev/null +++ b/10_Blackjack/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" \ No newline at end of file diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs new file mode 100644 index 00000000..8db2a0b3 --- /dev/null +++ b/10_Blackjack/rust/src/main.rs @@ -0,0 +1,105 @@ +use rand::{Rng, prelude::thread_rng}; +use std::{io}; + +//DATA +struct CARD { + name: String, + value: u8, +} +impl CARD { + +} +struct HAND { + cards: Vec, + total: u8, +} +impl HAND { + fn drawCard(deck: DECK) -> CARD { + //pull a random card from deck + + } +} +struct DECK { + cards: Vec, +} +struct PLAYER { + hand: HAND, +} + +struct GAME { + human_player: PLAYER, + computer_players: Vec, + dealer: PLAYER, + + deck: DECK, + discard_pile: DECK, +} +impl GAME { + fn start(num_players:u8) { + //ask user how many players there should be, not including them + let num_players = loop { + //input loop + + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + //print prompt + println!("How many other players should there by?"); + + //read user input from standard input, and store it to raw_input + raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + match raw_input.trim().parse::() { + Ok(i) => break i, // this escapes the loop, returning i + Err(e) => { + println!("MEANINGLESS NUMBER. TRY AGAIN. {}", e.to_string().to_uppercase()); + continue; // run the loop again + } + }; + }; + + + } +} + +const card_names: [&str;13] = ["Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"]; + +fn main() { + //DATA + //P(I,J) IS THE JTH CARD IN HAND I, Q(I) IS TOTAL OF HAND I + //C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE, + //T(I) IS THE TOTAL FOR PLAYER I, S(I) IS THE TOTAL THIS HAND FOR + //PLAYER I, B(I) IS TH BET FOR HAND I + //R(I) IS THE LENGTH OF P(I,*) + + //print welcome message + welcome(); + + +} + +fn welcome() { + //welcome message + println!(" + BLACK JACK + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + \n\n\n"); +} + +fn instructions() { + println!(" + THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE + GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE + PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE + DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE + FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE + PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS + STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/', + INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE + INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR + 'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING + DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR + BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'. + NUMBER OF PLAYERS + "); +} \ No newline at end of file From da8d704b499c3b1ff3bcfbefc11dd2a97ca9f190 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Fri, 25 Feb 2022 22:51:47 -0800 Subject: [PATCH 04/21] todo list --- 10_Blackjack/rust/src/main.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 8db2a0b3..8ad4cac3 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -1,6 +1,19 @@ use rand::{Rng, prelude::thread_rng}; use std::{io}; +/** + * todo list: + * + * make a 2 player game functional + * + * add more players + * + * use a 3 deck pool of cards instead of an infinite amount + * + * keep track of player bets + */ + + //DATA struct CARD { name: String, @@ -24,6 +37,12 @@ struct DECK { } struct PLAYER { hand: HAND, + balance: usize, +} +impl PLAYER { + fn new() -> PLAYER { + + } } struct GAME { @@ -35,7 +54,7 @@ struct GAME { discard_pile: DECK, } impl GAME { - fn start(num_players:u8) { + fn start(num_players:u8) -> GAME { //ask user how many players there should be, not including them let num_players = loop { //input loop @@ -59,6 +78,12 @@ impl GAME { }; + + + //return a game + return GAME { human_player: PLAYER::new(), computer_players: (), dealer: (), deck: (), discard_pile: () } + + } } From 66881c731340f162c6a9267aeac25aa1f1a0af16 Mon Sep 17 00:00:00 2001 From: David Lotts Date: Sun, 27 Feb 2022 03:02:27 -0500 Subject: [PATCH 05/21] Completed Rust version of Rocket --- 59_Lunar_LEM_Rocket/rust/README.md | 6 ++ 59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml | 10 ++ 59_Lunar_LEM_Rocket/rust/rocket/src/main.rs | 107 ++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 59_Lunar_LEM_Rocket/rust/README.md create mode 100644 59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml create mode 100644 59_Lunar_LEM_Rocket/rust/rocket/src/main.rs diff --git a/59_Lunar_LEM_Rocket/rust/README.md b/59_Lunar_LEM_Rocket/rust/README.md new file mode 100644 index 00000000..d05c9af4 --- /dev/null +++ b/59_Lunar_LEM_Rocket/rust/README.md @@ -0,0 +1,6 @@ +README.md + +Original source downloaded from Vintage Basic + +Conversion to Rust + diff --git a/59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml b/59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml new file mode 100644 index 00000000..e22d3e14 --- /dev/null +++ b/59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rocket" +version = "1.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +text_io = "0.1.10" +num-integer = "0.1" diff --git a/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs b/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs new file mode 100644 index 00000000..5aa9a9f4 --- /dev/null +++ b/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs @@ -0,0 +1,107 @@ +//Goal of this port is to keep Basic lang idioms where possible. Gotta have those single letter capital variables! +use num_integer::{sqrt}; +use std::io::{self, Write}; +use text_io::{read, try_read}; +#[allow(non_snake_case)] +fn main() { + println!("{:>30}", "ROCKET"); + println!("{:>15}", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + println!();println!();println!(); + println!("LUNAR LANDING SIMULATION"); + println!("----- ------- ----------");println!(); + let A= input("DO YOU WANT INSTRUCTIONS (YES OR NO) "); + if !(A=="NO") { + println!(); + println!("YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL"); + println!("CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-"); + println!("WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN."); + println!(); + println!("HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:"); println!(); + println!("(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL"); + println!(" WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER."); + println!("(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER"); + println!(" OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT"); + println!(" SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY"); + println!(" 1 FOOT/SEC."); + println!("(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC"); + println!(" OR 30 UNITS OF FUEL PER SECOND."); + println!("(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE"); + println!(" WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A"); + println!(" REPORT OF YOUR LANDING SPEED AND REMAINING FUEL."); + println!("(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR"); + println!(" BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL"); + println!(" YOU CONTACT THE LUNAR SURFACE.");println!(); + } + loop { + println!("BEGINNING LANDING PROCEDURE..........");println!(); + println!("G O O D L U C K ! ! !"); + println!();println!(); + println!("SEC FEET SPEED FUEL PLOT OF DISTANCE"); + println!(); + let mut T=0;let mut H:i32=1000;let mut V=50;let mut F=150; + let D:i32; let mut V1:i32; let mut B:i32; + 'falling: loop { + println!(" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}", T,H,V,F,high=(H/15) as usize,capsule="*"); + B = input_int(""); + if B<0 { B=0 } + else { if B>30 { B=30 } } + if B>F { B=F } + 'nofuel: loop { + V1=V-B+5; + F=F-B; + H=H- (V+V1)/2; + if H<=0 { break 'falling} + T=T+1; + V=V1; + if F>0 { break 'nofuel } + if B!=0 { + println!("**** OUT OF FUEL ****"); + } + println!(" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}", T,H,V,F,high=(H/12+29) as usize,capsule="*"); + B=0; + } + } + H=H+ (V1+V)/2; + if B==5 { + D=H/V; + } else { + D=(-V+sqrt(V*V+H*(10-2*B)))/(5-B); + V1=V+(5-B)*D; + } + println!("***** CONTACT *****"); + println!("TOUCHDOWN AT {} SECONDS.",T+D); + println!("LANDING VELOCITY={} FEET/SEC.",V1); + println!("{} UNITS OF FUEL REMAINING.", F); + if V1==0 { + println!("CONGRATULATIONS! A PERFECT LANDING!!"); + println!("YOUR LICENSE WILL BE RENEWED.......LATER."); + } + if V1.abs()>=2 { + println!("***** SORRY, BUT YOU BLEW IT!!!!"); + println!("APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN."); + } + println!();println!();println!(); + let A = input("ANOTHER MISSION"); + if !(A=="YES") { break }; + } + println!();println!( "CONTROL OUT.");println!(); +} + + +fn input(prompt:&str) -> String { + loop { + print!("{} ? ",prompt);io::stdout().flush().unwrap(); + let innn:String=read!("{}\n"); + let out:String = innn.trim().to_string(); + if out!="" {return out} + } +} +fn input_int(prompt:&str) -> i32 { + loop { + print!("{} ? ",prompt);io::stdout().flush().unwrap(); + match try_read!() { + Ok(n) => return n, + Err(_) => println!("Enter a number 0-30"), + } + } +} \ No newline at end of file From a12a5687037a6a4414e2ed30eba14ad6a30bc383 Mon Sep 17 00:00:00 2001 From: David Lotts Date: Sun, 27 Feb 2022 12:16:00 -0500 Subject: [PATCH 06/21] Add description of the three game folders. --- 59_Lunar_LEM_Rocket/rust/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/59_Lunar_LEM_Rocket/rust/README.md b/59_Lunar_LEM_Rocket/rust/README.md index d05c9af4..9ecf50dc 100644 --- a/59_Lunar_LEM_Rocket/rust/README.md +++ b/59_Lunar_LEM_Rocket/rust/README.md @@ -2,5 +2,11 @@ README.md Original source downloaded from Vintage Basic -Conversion to Rust +This folder for chapter #59 contains three different games. Three folders here contain the three games: + + - Rocket + - LEM + - lunar + +Conversion to [Rust](https://www.rust-lang.org) From 33008a1a68a83d19984c0c9c4ee6bdcbe392dc13 Mon Sep 17 00:00:00 2001 From: uMetalooper Date: Sun, 27 Feb 2022 21:57:41 +0000 Subject: [PATCH 07/21] Civil War Python added --- 27_Civil_War/python/Civilwar.py | 441 ++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 27_Civil_War/python/Civilwar.py diff --git a/27_Civil_War/python/Civilwar.py b/27_Civil_War/python/Civilwar.py new file mode 100644 index 00000000..956abe1f --- /dev/null +++ b/27_Civil_War/python/Civilwar.py @@ -0,0 +1,441 @@ +import math +import random + + +def tab(n): + return " "*n + + +battles = [["JULY 21, 1861. GEN. BEAUREGARD, COMMANDING THE SOUTH, MET", + "UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT", + "BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK."], + + ["APRIL 6-7, 1862. THE CONFEDERATE SURPRISE ATTACK AT", + "SHILOH FAILED DUE TO POOR ORGANIZATION."], + + ["JUNE 25-JULY 1, 1862. GENERAL LEE (CSA) UPHELD THE", + "OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN", + "AND THE UNION FORCES AWAY FROM RICHMOND."], + + ["AUG 29-30, 1862. THE COMBINED CONFEDERATE FORCES UNDER LEE", + "AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON."], + + ["SEPT 17, 1862. THE SOUTH FAILED TO INCORPORATE MARYLAND", + "INTO THE CONFEDERACY."], + + ["DEC 13, 1862. THE CONFEDERACY UNDER LEE SUCCESSFULLY", + "REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE."], + + ["DEC 31, 1862. THE SOUTH UNDER GEN. BRAGG WON A CLOSE BATTLE."], + + ["MAY 1-6, 1863. THE SOUTH HAD A COSTLY VICTORY AND LOST", + "ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON."], + + ["JULY 4, 1863. VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH", + "BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI."], + + ["JULY 1-3, 1863. A SOUTHERN MISTAKE BY GEN. LEE AT GETTYSBURG", + "COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR."], + + ["SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED", + "TO A COSTLY SOUTHERN VICTORY."], + + ["NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'", + "ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE."], + + ["MAY 5, 1864. GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO", + "FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG."], + + ["AUGUST, 1864. SHERMAN AND THREE VETERAN ARMIES CONVERGED", + "ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY."]] + +historical_data = [ + [], + ["BULL RUN", 18000, 18500, 1967, 2708, 1], + ["SHILOH", 40000., 44894., 10699, 13047, 3], + ["SEVEN DAYS", 95000., 115000., 20614, 15849, 3], + ["SECOND BULL RUN", 54000., 63000., 10000, 14000, 2], + ["ANTIETAM", 40000., 50000., 10000, 12000, 3], + ["FREDERICKSBURG", 75000., 120000., 5377, 12653, 1], + ["MURFREESBORO", 38000., 45000., 11000, 12000, 1], + ["CHANCELLORSVILLE", 32000, 90000., 13000, 17197, 2], + ["VICKSBURG", 50000., 70000., 12000, 19000, 1], + ["GETTYSBURG", 72500., 85000., 20000, 23000, 3], + ["CHICKAMAUGA", 66000., 60000., 18000, 16000, 2], + ["CHATTANOOGA", 37000., 60000., 36700., 5800, 2], + ["SPOTSYLVANIA", 62000., 110000., 17723, 18000, 2], + ["ATLANTA", 65000., 100000., 8500, 3700, 1]] +sa = {} +da = {} +fa = {} +ha = {} +ba = {} +oa = {} +print(tab(26) + "CIVIL WAR") +print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") +print() +print() +print() +# Original game design: Cram, Goodie, Hibbard Lexington H.S. +# Modifications: G. Paul, R. Hess (Ties), 1973 +# Union info on likely confederate strategy +sa[1] = 25 +sa[2] = 25 +sa[3] = 25 +sa[4] = 25 +d = -1 # number of players in the game +print() +while True: + X = input("DO YOU WANT INSTRUCTIONS? ") + if (X == "YES" or X == "NO"): + break + print("YES OR NO -- ") + +if X == "YES": + print() + print() + print() + print() + print("THIS IS A CIVIL WAR SIMULATION.") + print("TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.") + print("REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR") + print("RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE") + print("BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT") + print("AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!") + print() + print("THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS ") + print("POSSIBLE.") + print() + print("YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:") + print(" (1) ARTILLERY ATTACK") + print(" (2) FORTIFICATION AGAINST FRONTAL ATTACK") + print(" (3) FORTIFICATION AGAINST FLANKING MANEUVERS") + print(" (4) FALLING BACK") + print(" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:") + print(" (1) ARTILLERY ATTACK") + print(" (2) FRONTAL ATTACK") + print(" (3) FLANKING MANEUVERS") + print(" (4) ENCIRCLEMENT") + print("YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.") + +print() +print() +print() +print("ARE THERE TWO GENERALS PRESENT ", end="") +while True: + bs = input("(ANSWER YES OR NO) ") + if bs == "YES": + d = 2 + break + elif bs == "NO": + d = 1 + print() + print("YOU ARE THE CONFEDERACY. GOOD LUCK!") + print() + break + +print("SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON") +print("REQUEST. TYPE ANY OTHER NUMBER TO END THE SIMULATION.") +print("BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION") +print("ALLOWING YOU TO REPLAY IT") +print() +print("NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO ") +print("USE THE ENTRIES FROM THE PREVIOUS BATTLE") +print() +print("AFTER REQUESTING A BATTLE, DO YOU WISH ", end="") +print("BATTLE DESCRIPTIONS ", end="") +while True: + xs = input("(ANSWER YES OR NO) ") + if xs == "YES" or xs == "NO": + break +l = 0 +w = 0 +r1 = 0 +q1 = 0 +m3 = 0 +m4 = 0 +p1 = 0 +p2 = 0 +t1 = 0 +t2 = 0 +for i in range(1, 3): + da[i] = 0 + fa[i] = 0 + ha[i] = 0 + ba[i] = 0 + oa[i] = 0 +r2 = 0 +q2 = 0 +c6 = 0 +f = 0 +w0 = 0 +y = 0 +y2 = 0 +u = 0 +u2 = 0 +while True: + print() + print() + print() + a = int(input("WHICH BATTLE DO YOU WISH TO SIMULATE? ")) + if a < 1 or a > 14: + break + if a != 0 or r == 0: + cs = historical_data[a][0] + m1 = historical_data[a][1] + m2 = historical_data[a][2] + c1 = historical_data[a][3] + c2 = historical_data[a][4] + m = historical_data[a][5] + u = 0 + # Inflation calc + i1 = 10 + (l - w) * 2 + i2 = 10 + (w - l) * 2 + # Money available + da[1] = 100 * math.floor((m1 * (100 - i1) / 2000) + * (1 + (r1 - q1) / (r1 + 1)) + 0.5) + da[2] = 100 * math.floor(m2 * (100 - i2) / 2000 + 0.5) + if bs == "YES": + da[2] = 100 * math.floor((m2 * (100 - i2) / 2000) + * (1 + (r2 - q2) / (r2 + 1)) + 0.5) + # Men available + m5 = math.floor(m1 * (1 + (p1 - t1) / (m3 + 1))) + m6 = math.floor(m2 * (1 + (p2 - t2) / (m4 + 1))) + f1 = 5 * m1 / 6 + print() + print() + print() + print() + print() + print(f"THIS IS THE BATTLE OF {cs}") + if xs != "NO": + print("\n".join(battles[a-1])) + + else: + print(cs + " INSTANT REPLAY") + + print() + print(" \tCONFEDERACY\t UNION") + print(f"MEN\t {m5}\t\t {m6}") + print(f"MONEY\t ${da[1]}\t\t${da[2]}") + print(f"INFLATION\t {i1 + 15}%\t {i2}%") + print() + # ONLY IN PRINTOUT IS CONFED INFLATION = I1 + 15 % + # IF TWO GENERALS, INPUT CONFED, FIRST + for i in range(1, d+1): + if bs == "YES" and i == 1: + print("CONFEDERATE GENERAL---", end="") + print("HOW MUCH DO YOU WISH TO SPEND FOR") + while True: + f = int(input(" - FOOD...... ? ")) + if f < 0: + if r1 == 0: + print("NO PREVIOUS ENTRIES") + continue + print("ASSUME YOU WANT TO KEEP SAME ALLOCATIONS") + print() + break + fa[i] = f + while True: + ha[i] = int(input(" - SALARIES.. ? ")) + if ha[i] >= 0: + break + print("NEGATIVE VALUES NOT ALLOWED.") + while True: + ba[i] = int(input(" - AMMUNITION ? ")) + if ba[i] >= 0: + break + print("NEGATIVE VALUES NOT ALLOWED.") + print() + if fa[i] + ha[i] + ba[i] > da[i]: + print("THINK AGAIN! YOU HAVE ONLY $" + da[i]) + else: + break + + if bs != "YES" or i == 2: + break + print("UNION GENERAL---", end="") + + for z in range(1, d+1): + if bs == "YES": + if z == 1: + print("CONFEDERATE ", end="") + else: + print(" UNION ", end="") + # Find morale + o = ((2 * math.pow(fa[z], 2) + + math.pow(ha[z], 2)) / math.pow(f1, 2) + 1) + if o >= 10: + print("MORALE IS HIGH") + elif o >= 5: + print("MORALE IS FAIR") + else: + print("MORALE IS POOR") + if bs != "YES": + break + oa[z] = o + + o2 = oa[2] + o = oa[1] + print("CONFEDERATE GENERAL---") + # Actual off/def battle situation + if m == 3: + print("YOU ARE ON THE OFFENSIVE") + elif m == 1: + print("YOU ARE ON THE DEFENSIVE") + else: + print("BOTH SIDES ARE ON THE OFFENSIVE") + + print() + # Choose strategies + if bs != "YES": + while True: + y = int(input("YOUR STRATEGY ")) + if (abs(y - 3) < 3): + break + print(f"STRATEGY {y} NOT ALLOWED.") + if y == 5: + print("THE CONFEDERACY HAS SURRENDERED.") + break + # Union strategy is computer chosen + if a == 0: + while True: + y2 = int(input("UNION STRATEGY IS ")) + if y2 > 0 and y2 < 5: + break + print("ENTER 1, 2, 3, OR 4 (USUALLY PREVIOUS UNION STRATEGY)") + else: + s0 = 0 + r = math.random() * 100 + for i in range(1, 5): + s0 += sa[i] + # If actual strategy info is in program data statements + # then r-100 is extra weight given to that strategy. + if r < s0: + break + y2 = i + print(y2) + else: + for i in range(1, 3): + if (i == 1): + print("CONFEDERATE STRATEGY ? ", end="") + while True: + y = int(input()) + if abs(y - 3) < 3: + break + print(f"STRATEGY {y} NOT ALLOWED.") + print("YOUR STRATEGY ? ", end="") + if (i == 2): + y2 = y + y = y1 + if (y2 != 5): + break + else: + y1 = y + print("UNION STRATEGY ? ", end="") + # Simulated losses - North + c6 = (2 * c2 / 5) * (1 + 1 / (2 * (abs(y2 - y) + 1))) + c6 = c6 * (1.28 + (5 * m2 / 6) / (ba[2] + 1)) + c6 = math.floor(c6 * (1 + 1 / o2) + 0.5) + # If loss > men present, rescale losses + e2 = 100 / o2 + if math.floor(c6 + e2) >= m6: + c6 = math.floor(13 * m6 / 20) + e2 = 7 * c6 / 13 + u2 = 1 + # Calculate simulated losses + print() + print() + print() + print("\t\tCONFEDERACY\tUNION") + c5 = (2 * c1 / 5) * (1 + 1 / (2 * (abs(y2 - y) + 1))) + c5 = math.floor(c5 * (1 + 1 / o) * (1.28 + f1 / (ba[1] + 1)) + 0.5) + e = 100 / o + if c5 + 100 / o >= m1 * (1 + (p1 - t1) / (m3 + 1)): + c5 = math.floor(13 * m1 / 20 * (1 + (p1 - t1) / (m3 + 1))) + e = 7 * c5 / 13 + u = 1 + + if (d == 1): + c6 = math.floor(17 * c2 * c1 / (c5 * 20)) + e2 = 5 * o + + print("CASUALTIES\t" + str(c5) + "\t\t" + str(c6)) + print("DESERTIONS\t" + str(math.floor(e)) + "\t\t" + str(math.floor(e2))) + print() + if (bs == "YES"): + print("COMPARED TO THE ACTUAL CASUALTIES AT " + str(cs)) + print("CONFEDERATE: " + str(math.floor(100 * + (c5 / c1) + 0.5)) + "% OF THE ORIGINAL") + print("UNION: " + str(math.floor(100 * + (c6 / c2) + 0.5)) + "% OF THE ORIGINAL") + + print() + # Find who won + if (u == 1 and u2 == 1 or (u != 1 and u2 != 1 and c5 + e == c6 + e2)): + print("BATTLE OUTCOME UNRESOLVED") + w0 += 1 + elif (u == 1 or (u != 1 and u2 != 1 and c5 + e > c6 + e2)): + print("THE UNION WINS " + str(cs)) + if a != 0: + l += 1 + else: + print("THE CONFEDERACY WINS " + str(cs)) + if (a != 0): + w += 1 + + # Lines 2530 to 2590 from original are unreachable. + if (a != 0): + t1 += c5 + e + t2 += c6 + e2 + p1 += c1 + p2 += c2 + q1 += fa[1] + ha[1] + ba[1] + q2 += fa[2] + ha[2] + ba[2] + r1 += m1 * (100 - i1) / 20 + r2 += m2 * (100 - i2) / 20 + m3 += m1 + m4 += m2 + # Learn present strategy, start forgetting old ones + # present startegy of south gains 3*s, others lose s + # probability points, unless a strategy falls below 5 % . + s = 3 + s0 = 0 + for i in range(1, 5): + if (sa[i] <= 5): + continue + sa[i] -= 5 + s0 += s + sa[y] += s0 + + u = 0 + u2 = 0 + print("---------------") + continue + +print() +print() +print() +print() +print() +print() +print(f"THE CONFEDERACY HAS WON {w} BATTLES AND LOST {l}") +if (y == 5 or (y2 != 5 and w <= l)): + print("THE UNION HAS WON THE WAR") +else: + print("THE CONFEDERACY HAS WON THE WAR") +print() +if (r1 > 0): + print(f"FOR THE {w + l + w0} BATTLES FOUGHT (EXCLUDING RERUNS)") + print(" \t \t ") + print("CONFEDERACY\t UNION") + print(f"HISTORICAL LOSSES\t{math.floor(p1 + 0.5)}\t{math.floor(p2 + 0.5)}") + print(f"SIMULATED LOSSES\t{math.floor(t1 + 0.5)}\t{math.floor(t2 + 0.5)}") + print() + print( + f" % OF ORIGINAL\t{math.floor(100 * (t1 / p1) + 0.5)}\t{math.floor(100 * (t2 / p2) + 0.5)}") + if (bs != "YES"): + print() + print("UNION INTELLIGENCE SUGGEST THAT THE SOUTH USED") + print("STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES") + print(f"{sa[1]} {sa[2]} {sa[3]} {sa[4]}") From b7fa6c523750311542b2fc389f8d382b708450c5 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 18:42:05 -0800 Subject: [PATCH 08/21] rust port of blackjack (missing features) todo list: * allow splitting * keep track of player bets * allow doubling down --- 10_Blackjack/rust/src/main.rs | 572 ++++++++++++++++++++++++++++++---- 1 file changed, 506 insertions(+), 66 deletions(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 8ad4cac3..73ed5134 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -1,108 +1,473 @@ -use rand::{Rng, prelude::thread_rng}; -use std::{io}; +use rand::{prelude::{thread_rng, SliceRandom}}; +use std::{io, collections::HashSet}; /** * todo list: * - * make a 2 player game functional - * - * add more players - * - * use a 3 deck pool of cards instead of an infinite amount + * allow splitting * * keep track of player bets + * + * allow doubling down */ //DATA -struct CARD { - name: String, +//enums +enum PlayerType { + Player, + Dealer, +} +enum Play { + Stand, + Hit, +} +impl ToString for Play { + fn to_string(&self) -> String { + match self { + &Play::Hit => return String::from("Hit"), + &Play::Stand => return String::from("Stand"), + } + } +} +//structs +struct CARD<'a> { + name: &'a str, value: u8, } -impl CARD { +impl<'a> CARD<'a> { + /** + * creates a new card from the passed card name + */ + fn new(card_name: &str) -> CARD { + return CARD { name: card_name, value: CARD::determine_value_from_name(card_name) }; + } + + /** + * returns the value associated with a card with the passed name + * return 0 if the passed card name doesn't exist + */ + fn determine_value_from_name(card_name: &str) -> u8 { + //DATA + let value:u8; + + match card_name.to_ascii_uppercase().as_str() { + "ACE" => value = 11, + "2" => value = 2, + "3" => value = 3, + "4" => value = 4, + "5" => value = 5, + "6" => value = 6, + "7" => value = 7, + "8" => value = 8, + "9" => value = 9, + "10" => value = 10, + "JACK" => value = 10, + "QUEEN" => value = 10, + "KING" => value = 10, + _ => value = 0, + } + + return value; + } +} +struct HAND<'a> { + cards: Vec>, +} +impl<'a> HAND<'a> { + /** + * returns a new empty hand + */ + fn new() -> HAND<'a> { + return HAND { cards: Vec::new()}; + } -} -struct HAND { - cards: Vec, - total: u8, -} -impl HAND { - fn drawCard(deck: DECK) -> CARD { - //pull a random card from deck + /** + * add a passed card to this hand + */ + fn add_card(&mut self, card: CARD<'a>) { + self.cards.push(card); + } + /** + * returns the total points of the cards in this hand + */ + fn get_total(&self) -> usize { + let mut total:usize = 0; + for card in &self.cards { + total += card.value as usize; + } + + //if there is an ACE, and the hand would otherwise bust, treat the ace like it's worth 1 + if total > 21 && self.cards.iter().any(|c| -> bool {*c.name == *"ACE"}) { + total -= 10; + } + + return total; + } + + /** + * adds the cards in hand into the discard pile + */ + fn discard_hand(&mut self, deck: &mut DECKS<'a>) { + let len = self.cards.len(); + for _i in 0..len { + deck.discard_pile.push(self.cards.pop().expect("hand empty")); + } } } -struct DECK { - cards: Vec, +struct DECKS<'a> { + deck: Vec>, //cards in the deck + discard_pile: Vec> //decks discard pile } -struct PLAYER { - hand: HAND, - balance: usize, -} -impl PLAYER { - fn new() -> PLAYER { +impl<'a> DECKS<'a> { + /** + * creates a new full and shuffled deck, and an empty discard pile + */ + fn new() -> DECKS<'a> { + //returns a number of full decks of 52 cards, shuffles them + //DATA + let mut deck = DECKS{deck: Vec::new(), discard_pile: Vec::new()}; + let number_of_decks = 3; + //fill deck + for _n in 0..number_of_decks { //fill deck with number_of_decks decks worth of cards + for card_name in CARD_NAMES { //add 4 of each card, totaling one deck with 4 of each card + deck.deck.push( CARD::new(card_name) ); + deck.deck.push( CARD::new(card_name) ); + deck.deck.push( CARD::new(card_name) ); + deck.deck.push( CARD::new(card_name) ); + } + } + + //shuffle deck + deck.shuffle(); + + //return deck + return deck; } -} -struct GAME { - human_player: PLAYER, - computer_players: Vec, - dealer: PLAYER, + /** + * shuffles the deck + */ + fn shuffle(&mut self) { + self.deck.shuffle(&mut thread_rng()); + } - deck: DECK, - discard_pile: DECK, -} -impl GAME { - fn start(num_players:u8) -> GAME { - //ask user how many players there should be, not including them - let num_players = loop { - //input loop + /** + * draw card from deck, and return it + * if deck is empty, shuffles discard pile into it and tries again + */ + fn draw_card(&mut self) -> CARD<'a> { + match self.deck.pop() { + Some(card) => return card, + None => { + let len = self.discard_pile.len(); - let mut raw_input = String::new(); // temporary variable for user input that can be parsed later - //print prompt - println!("How many other players should there by?"); - - //read user input from standard input, and store it to raw_input - raw_input.clear(); //clear input - io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); - - //from input, try to read a number - match raw_input.trim().parse::() { - Ok(i) => break i, // this escapes the loop, returning i - Err(e) => { - println!("MEANINGLESS NUMBER. TRY AGAIN. {}", e.to_string().to_uppercase()); - continue; // run the loop again + if len > 0 {//deck is empty, shuffle discard pile into deck and try again + println!("deck is empty, shuffling"); + for _i in 0..len { + self.deck.push( self.discard_pile.pop().expect("discard pile empty") ) + } + self.shuffle(); + return self.draw_card(); + } else { //discard pile and deck are empty, should never happen + panic!("discard pile empty"); } - }; - }; + } + } + } +} +struct PLAYER<'a> { + hand: HAND<'a>, + _balance: usize, + wins: usize, + player_type: PlayerType, +} +impl<'a> PLAYER<'a> { + /** + * creates a new player of the given type + */ + fn new(player_type: PlayerType) -> PLAYER<'a> { + return PLAYER { hand: HAND::new(), _balance: STARTING_BALANCE, wins: 0, player_type: player_type}; + } + /** + * returns a string of the players hand + * + * if player is a dealer, returns the first card in the hand followed by *'s for every other card + * if player is a player, returns every card and the total + */ + fn print_hand(&self, hide_dealer:bool) -> String { + if !hide_dealer { + return format!( + "{}\n\ttotal points = {}", //message + { //cards in hand + let mut s:String = String::new(); + for cards_in_hand in self.hand.cards.iter().rev() { + s += format!("{}\t", cards_in_hand.name).as_str(); + } + s + }, + self.hand.get_total() //total points in hand + ); + } + match &self.player_type { + &PlayerType::Dealer => { //if this is a dealer + return format!( + "{}*",//message + { //*'s for other cards + let mut s:String = String::new(); + let mut cards_in_hand = self.hand.cards.iter(); + cards_in_hand.next();//consume first card drawn + for c in cards_in_hand.rev() { + s += format!("{}\t", c.name).as_str(); + } + s + } + ); + }, + &PlayerType::Player => { //if this is a player + return format!( + "{}\n\ttotal points = {}", //message + { //cards in hand + let mut s:String = String::new(); + for cards_in_hand in self.hand.cards.iter().rev() { + s += format!("{}\t", cards_in_hand.name).as_str(); + } + s + }, + self.hand.get_total() //total points in hand + ); + } + } + } + + /** + * get the players 'play' + */ + fn get_play(&self) -> Play { + /* + do different things depending on what type of player this is: + if it's a dealer, use an algorithm to determine the play + if it's a player, ask user for input + */ + match &self.player_type { + &PlayerType::Dealer => { + if self.hand.get_total() > 16 { // if total value of hand is greater than 16, stand + return Play::Stand; + } else { //otherwise hit + return Play::Hit; + } + }, + &PlayerType::Player => { + let play = get_char_from_user_input("\tWhat is your play?", &vec!['s','S','h','H']); + match play { + 's' | 'S' => return Play::Stand, + 'h' | 'H' => return Play::Hit, + _ => panic!("get_char_from_user_input() returned invalid character"), + } + }, + } + } +} + +struct GAME<'a> { + players: Vec>, //last item in this is the dealer + decks: DECKS<'a>, + rounds:usize, + games_played:usize, +} +impl<'a> GAME<'a> { + /** + * creates a new game + */ + fn new(num_players:usize) -> GAME<'a> { + //DATA + let mut players: Vec = Vec::new(); + + //add dealer + players.push(PLAYER::new(PlayerType::Dealer)); + //create human player(s) (at least one) + players.push(PLAYER::new(PlayerType::Player)); + for _i in 1..num_players { //one less than num_players players + players.push(PLAYER::new(PlayerType::Player)); + } + + //ask if they want instructions + if let 'y'|'Y' = get_char_from_user_input("Do you want instructions? (y/n)", &vec!['y','Y','n','N']) { + instructions(); + } + println!(); //return a game - return GAME { human_player: PLAYER::new(), computer_players: (), dealer: (), deck: (), discard_pile: () } - - + return GAME { players: players, decks: DECKS::new(), rounds: 0, games_played: 0} } + + /** + * prints the score of every player + */ + fn print_wins(&self) { + println!("Scores:"); + for player in self.players.iter().enumerate() { + match player.1.player_type { + PlayerType::Player => println!("Player{} wins:\t{}", player.0, player.1.wins), + PlayerType::Dealer => println!("Dealer wins:\t{}", player.1.wins) + } + } + } + + /** + * plays a round of blackjack + */ + fn play_game(&mut self) { + //deal cards to each player + for _i in 0..2 { // do this twice + //draw card for each player + self.players.iter_mut().for_each(|player| {player.hand.add_card( self.decks.draw_card() );}); + } + + let mut players_playing: HashSet = HashSet::new(); // the numbers presenting each player still active in the round + for i in 0..self.players.len() { //runs number of players times + players_playing.insert(i); + } + //round loop (each player either hits or stands) + loop { + //increment rounds + self.rounds += 1; + + //print game state + println!("\n\t\t\tGame {}\tRound {}", self.games_played, self.rounds); + + self.players.iter().enumerate().for_each(|player| { + match player.1.player_type { + PlayerType::Player => println!("Player{} Hand:\t{}", player.0, player.1.print_hand(true)), + PlayerType::Dealer => println!("Dealer Hand:\t{}", player.1.print_hand(true)) + } + }); + + print!("\n"); //empty line + + //get the moves of all remaining players + for player in self.players.iter_mut().enumerate() { + match player.1.player_type {//print the player name + PlayerType::Player => print!("Player{}:", player.0), + PlayerType::Dealer => print!("Dealer:"), + } + + //check their hand value for a blackjack(21) or bust + let score = player.1.hand.get_total(); + if score >= 21 { + if score == 21 { // == 21 + println!("\tBlackjack (21 points)"); + } else { // > 21 + println!("\tBust ({} points)", score); + } + players_playing.remove(&player.0);//remove player from playing list + continue; + } + + //get play + let play = player.1.get_play(); + + //process play + match play { + Play::Stand => { + println!("\t{}s", play.to_string()); + players_playing.remove(&player.0);//remove player from playing list + }, + Play::Hit => { + println!("\t{}s", play.to_string()); + //give them a card + player.1.hand.add_card( self.decks.draw_card() ); + }, + } + } + + //loop end condition + if players_playing.is_empty() {break;} + } + + //determine winner + let mut top_score = 0; //player with the highest points + let mut num_winners = 1; + for player in self.players.iter_mut().enumerate().filter( |x| -> bool {x.1.hand.get_total()<=21}) { //players_who_didnt_bust + let score = player.1.hand.get_total(); + if score > top_score { + top_score = score; + num_winners = 1; + } else if score == top_score { + num_winners += 1; + } + } + + //print everyones hand + println!(""); + self.players.iter().enumerate().for_each(|player| { + match player.1.player_type { + PlayerType::Player => println!("Player{} Hand:\t{}", player.0, player.1.print_hand(false)), + PlayerType::Dealer => println!("Dealer Hand:\t{}", player.1.print_hand(false)) + } + }); + println!(""); + //for each player with the top score + self.players.iter_mut().enumerate().filter(|x|->bool{x.1.hand.get_total()==top_score}).for_each(|x| { + match x.1.player_type { + PlayerType::Player => print!("Player{}\t", x.0), + PlayerType::Dealer => print!("Dealer\t"), + } + //increment their wins + x.1.wins += 1; + }); + if num_winners > 1 {println!("all tie with {}\n\n\n", top_score);} + else {println!("wins with {}!\n\n\n",top_score);} + + //discard hands + self.players.iter_mut().for_each(|player| {player.hand.discard_hand(&mut self.decks);}); + + //increment games_played + self.games_played += 1; + } + + + } -const card_names: [&str;13] = ["Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"]; +const CARD_NAMES: [&str;13] = ["ACE","2","3","4","5","6","7","8","9","10","JACK","QUEEN","KING"]; +const STARTING_BALANCE: usize = 100; fn main() { //DATA - //P(I,J) IS THE JTH CARD IN HAND I, Q(I) IS TOTAL OF HAND I - //C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE, - //T(I) IS THE TOTAL FOR PLAYER I, S(I) IS THE TOTAL THIS HAND FOR - //PLAYER I, B(I) IS TH BET FOR HAND I - //R(I) IS THE LENGTH OF P(I,*) + let mut game: GAME; //print welcome message welcome(); - + //create game + game = GAME::new( get_number_from_user_input("How many players should there be (at least 1)?", 1, 7) ); + + //game loop, play game until user wants to stop + loop { + //print score of every user + game.print_wins(); + + //play round + game.play_game(); + + //ask if they want to play again + match get_char_from_user_input("Play Again? (y/n)", &vec!['y','Y','n','N']) { + 'y' | 'Y' => continue, + 'n' | 'N' => break, + _ => break, + } + } } +/** + * prints the welcome screen + */ fn welcome() { //welcome message println!(" @@ -111,6 +476,9 @@ fn welcome() { \n\n\n"); } +/** + * prints the instructions + */ fn instructions() { println!(" THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE @@ -126,5 +494,77 @@ fn instructions() { DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'. NUMBER OF PLAYERS + + NOTE: Currently only H and S are implemented properly "); -} \ No newline at end of file +} + +/** + * gets a usize integer from user input + */ +fn get_number_from_user_input(prompt: &str, min:usize, max:usize) -> usize { + //input loop + return loop { + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //print prompt + println!("{}", prompt); + + //read user input from standard input, and store it to raw_input + //raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + match raw_input.trim().parse::() { + Ok(i) => { + if i < min || i > max { //input out of desired range + println!("INPUT OUT OF VALID RANGE. TRY AGAIN."); + continue; // run the loop again + } + else { + println!(); + break i;// this escapes the loop, returning i + } + }, + Err(e) => { + println!("INVALID INPUT. TRY AGAIN. {}", e.to_string().to_uppercase()); + continue; // run the loop again + } + }; + }; +} + +/** + * gets a character from user input + * returns the first character they type + */ +fn get_char_from_user_input(prompt: &str, valid_results: &Vec) -> char { + //input loop + return loop { + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //print prompt + println!("{}", prompt); + + //read user input from standard input, and store it to raw_input + //raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a valid character + match raw_input.trim().chars().nth(0) { + Some(i) => { + if !valid_results.contains(&i) { //input out of desired range + println!("INPUT IS NOT VALID CHARACTER. TRY AGAIN."); + continue; // run the loop again + } + else { + break i;// this escapes the loop, returning i + } + }, + None => { + println!("INVALID INPUT. TRY AGAIN."); + continue; // run the loop again + } + }; + }; +} From 04de91c14c5e5b3df470b2642d5655c481145652 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 20:06:17 -0800 Subject: [PATCH 09/21] readme's added --- 02_Amazing/rust/README.md | 3 +++ 10_Blackjack/rust/README.md | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 02_Amazing/rust/README.md create mode 100644 10_Blackjack/rust/README.md diff --git a/02_Amazing/rust/README.md b/02_Amazing/rust/README.md new file mode 100644 index 00000000..f84e546c --- /dev/null +++ b/02_Amazing/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file diff --git a/10_Blackjack/rust/README.md b/10_Blackjack/rust/README.md new file mode 100644 index 00000000..f84e546c --- /dev/null +++ b/10_Blackjack/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file From cd1dfd92fdcd1d751eb6d6b2a551078bbde5dd74 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 20:07:18 -0800 Subject: [PATCH 10/21] readme's added --- 02_Amazing/rust/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 02_Amazing/rust/README.md diff --git a/02_Amazing/rust/README.md b/02_Amazing/rust/README.md new file mode 100644 index 00000000..f84e546c --- /dev/null +++ b/02_Amazing/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file From 98da0cf49e0dff9238c4b228ca2cea35f3ddfc3e Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 20:31:46 -0800 Subject: [PATCH 11/21] 10_blackjack rust more improvements --- 10_Blackjack/rust/src/main.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 73ed5134..72d3188e 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -323,12 +323,16 @@ impl<'a> GAME<'a> { * plays a round of blackjack */ fn play_game(&mut self) { + //print score of every user + self.print_wins(); + //deal cards to each player for _i in 0..2 { // do this twice //draw card for each player self.players.iter_mut().for_each(|player| {player.hand.add_card( self.decks.draw_card() );}); } + //keep track of player who haven't busted or stood yet let mut players_playing: HashSet = HashSet::new(); // the numbers presenting each player still active in the round for i in 0..self.players.len() { //runs number of players times players_playing.insert(i); @@ -369,6 +373,9 @@ impl<'a> GAME<'a> { continue; } + //check if player is still playing + if !players_playing.contains(&player.0) {print!("\n");continue;}//print a line and skip to the next iteration of the loop + //get play let play = player.1.get_play(); @@ -429,6 +436,8 @@ impl<'a> GAME<'a> { //increment games_played self.games_played += 1; + //reset rounds + self.rounds = 0; } @@ -450,9 +459,6 @@ fn main() { //game loop, play game until user wants to stop loop { - //print score of every user - game.print_wins(); - //play round game.play_game(); From 020fb6271fee2d22e4beff516c941367b27eac3c Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 20:37:43 -0800 Subject: [PATCH 12/21] bug fix didn't have a minimum accepted input size, and panicked during testing --- 02_Amazing/rust/src/main.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs index bc85189f..a1471a6a 100644 --- a/02_Amazing/rust/src/main.rs +++ b/02_Amazing/rust/src/main.rs @@ -163,12 +163,6 @@ fn main() { } println!("."); } - - - - - - } fn get_user_input(prompt: &str) -> usize { @@ -187,7 +181,15 @@ fn get_user_input(prompt: &str) -> usize { //from input, try to read a number match raw_input.trim().parse::() { - Ok(i) => break i, // this escapes the loop, returning i + Ok(i) => { + if i>1 { //min size 1 + break i; // this escapes the loop, returning i + } + else { + println!("INPUT OUT OF RANGE. TRY AGAIN."); + continue;// run the loop again + } + } Err(e) => { println!("MEANINGLESS DIMENSION. TRY AGAIN. {}", e.to_string().to_uppercase()); continue; // run the loop again From 099a5be209952755f5d43a25c458884893b7f995 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 20:49:25 -0800 Subject: [PATCH 13/21] added exit condition when running this as a .exe, it would close immediately after generating the maze, this is no longer the case. --- 02_Amazing/rust/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs index a1471a6a..7abc67cf 100644 --- a/02_Amazing/rust/src/main.rs +++ b/02_Amazing/rust/src/main.rs @@ -131,7 +131,6 @@ fn main() { if used[row][col] != 0 {break;} } } - } // Add a random exit col=rng.gen_range(0..width); @@ -163,6 +162,10 @@ fn main() { } println!("."); } + + //stops the program from ending until you give input, useful when running a compiled .exe + println!("\n\npress ENTER to exit"); + io::stdin().read_line(&mut String::new()).expect("closing"); } fn get_user_input(prompt: &str) -> usize { From 13f180260165414e9f97c2bc68c3e8ad1e0b77c0 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 23:27:23 -0800 Subject: [PATCH 14/21] 10_blackjack rust implemented betting --- 10_Blackjack/rust/src/main.rs | 268 +++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 119 deletions(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 72d3188e..0302527f 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -1,13 +1,11 @@ use rand::{prelude::{thread_rng, SliceRandom}}; -use std::{io, collections::HashSet}; +use std::{io, io::{stdout, Write}}; /** * todo list: * * allow splitting * - * keep track of player bets - * * allow doubling down */ @@ -18,6 +16,14 @@ enum PlayerType { Player, Dealer, } +impl ToString for PlayerType { + fn to_string(&self) -> String { + match self { + &PlayerType::Dealer => return String::from("Dealer"), + &PlayerType::Player => return String::from("Player"), + } + } +} enum Play { Stand, Hit, @@ -181,16 +187,36 @@ impl<'a> DECKS<'a> { struct PLAYER<'a> { hand: HAND<'a>, - _balance: usize, + balance: usize, + bet: usize, wins: usize, player_type: PlayerType, + index: usize, + } impl<'a> PLAYER<'a> { /** * creates a new player of the given type */ - fn new(player_type: PlayerType) -> PLAYER<'a> { - return PLAYER { hand: HAND::new(), _balance: STARTING_BALANCE, wins: 0, player_type: player_type}; + fn new(player_type: PlayerType, index: usize) -> PLAYER<'a> { + return PLAYER { hand: HAND::new(), balance: STARTING_BALANCE, bet: 0, wins: 0, player_type: player_type, index: index}; + } + + fn get_name(&self) -> String { + format!("{}{}", self.player_type.to_string(),self.index) + } + + /** + * gets a bet from the player + */ + fn get_bet(&mut self) { + if let PlayerType::Player = self.player_type { + if self.balance < 1 { + println!("{} is out of money :(", self.get_name()); + self.bet = 0; + } + self.bet = get_number_from_user_input(format!("{}\tBet?",self.get_name()).as_str(), 1, self.balance); + } } /** @@ -199,7 +225,7 @@ impl<'a> PLAYER<'a> { * if player is a dealer, returns the first card in the hand followed by *'s for every other card * if player is a player, returns every card and the total */ - fn print_hand(&self, hide_dealer:bool) -> String { + fn hand_as_string(&self, hide_dealer:bool) -> String { if !hide_dealer { return format!( "{}\n\ttotal points = {}", //message @@ -213,34 +239,35 @@ impl<'a> PLAYER<'a> { self.hand.get_total() //total points in hand ); } - - match &self.player_type { - &PlayerType::Dealer => { //if this is a dealer - return format!( - "{}*",//message - { //*'s for other cards - let mut s:String = String::new(); - let mut cards_in_hand = self.hand.cards.iter(); - cards_in_hand.next();//consume first card drawn - for c in cards_in_hand.rev() { - s += format!("{}\t", c.name).as_str(); + else { + match &self.player_type { + &PlayerType::Dealer => { //if this is a dealer + return format!( + "{}*",//message + { //*'s for other cards + let mut s:String = String::new(); + let mut cards_in_hand = self.hand.cards.iter(); + cards_in_hand.next();//consume first card drawn + for c in cards_in_hand.rev() { + s += format!("{}\t", c.name).as_str(); + } + s } - s - } - ); - }, - &PlayerType::Player => { //if this is a player - return format!( - "{}\n\ttotal points = {}", //message - { //cards in hand - let mut s:String = String::new(); - for cards_in_hand in self.hand.cards.iter().rev() { - s += format!("{}\t", cards_in_hand.name).as_str(); - } - s - }, - self.hand.get_total() //total points in hand - ); + ); + }, + &PlayerType::Player => { //if this is a player + return format!( + "{}\n\ttotal points = {}", //message + { //cards in hand + let mut s:String = String::new(); + for cards_in_hand in self.hand.cards.iter().rev() { + s += format!("{}\t", cards_in_hand.name).as_str(); + } + s + }, + self.hand.get_total() //total points in hand + ); + } } } } @@ -277,7 +304,6 @@ impl<'a> PLAYER<'a> { struct GAME<'a> { players: Vec>, //last item in this is the dealer decks: DECKS<'a>, - rounds:usize, games_played:usize, } impl<'a> GAME<'a> { @@ -289,11 +315,11 @@ impl<'a> GAME<'a> { let mut players: Vec = Vec::new(); //add dealer - players.push(PLAYER::new(PlayerType::Dealer)); + players.push(PLAYER::new(PlayerType::Dealer,0)); //create human player(s) (at least one) - players.push(PLAYER::new(PlayerType::Player)); - for _i in 1..num_players { //one less than num_players players - players.push(PLAYER::new(PlayerType::Player)); + players.push(PLAYER::new(PlayerType::Player,1)); + for i in 2..=num_players { //one less than num_players players + players.push(PLAYER::new(PlayerType::Player,i)); } //ask if they want instructions @@ -303,98 +329,102 @@ impl<'a> GAME<'a> { println!(); //return a game - return GAME { players: players, decks: DECKS::new(), rounds: 0, games_played: 0} + return GAME { players: players, decks: DECKS::new(), games_played: 0} } /** * prints the score of every player */ - fn print_wins(&self) { - println!("Scores:"); - for player in self.players.iter().enumerate() { - match player.1.player_type { - PlayerType::Player => println!("Player{} wins:\t{}", player.0, player.1.wins), - PlayerType::Dealer => println!("Dealer wins:\t{}", player.1.wins) - } - } + fn _print_stats(&self) { + println!("{}", self.stats_as_string()); + } + + /** + * returns a string of the wins, balance, and bets of every player + */ + fn stats_as_string(&self) -> String { + format!("Scores:\n{}",{ + let mut s = String::new(); + self.players.iter().for_each(|p| { + //format the presentation of player stats + match p.player_type { + PlayerType::Player => s+= format!("{} Wins:\t{}\t\tBalance:\t{}\t\tBet\t{}\n",p.get_name(),p.wins,p.balance,p.bet).as_str(), + PlayerType::Dealer => s+= format!("{} Wins:\t{}\n",p.get_name(),p.wins).as_str() + } + }); + s + }) } /** * plays a round of blackjack */ fn play_game(&mut self) { - //print score of every user - self.print_wins(); - + //DATA + let scores; + let game = self.games_played; //save it here so we don't have borrowing issues + let mut player_hands_message: String = String::new();//cache it here so we don't have borrowing issues + //deal cards to each player for _i in 0..2 { // do this twice //draw card for each player self.players.iter_mut().for_each(|player| {player.hand.add_card( self.decks.draw_card() );}); } - //keep track of player who haven't busted or stood yet - let mut players_playing: HashSet = HashSet::new(); // the numbers presenting each player still active in the round - for i in 0..self.players.len() { //runs number of players times - players_playing.insert(i); - } - //round loop (each player either hits or stands) - loop { - //increment rounds - self.rounds += 1; + //get everyones bets + self.players.iter_mut().for_each(|player| player.get_bet()); + scores = self.stats_as_string(); //save it here so we don't have borrowing issues later + + //play game for each player + for player in self.players.iter_mut() { + //turn loop, ends when player finishes their turn + loop{ + //clear screen + clear(); + //print welcome + welcome(); + //print game state + println!("\n\t\t\tGame {}", game); + //print scores + println!("{}",scores); + //print hands of all players + print!("{}", player_hands_message); + println!("{} Hand:\t{}", player.get_name(), player.hand_as_string(true)); - //print game state - println!("\n\t\t\tGame {}\tRound {}", self.games_played, self.rounds); - - self.players.iter().enumerate().for_each(|player| { - match player.1.player_type { - PlayerType::Player => println!("Player{} Hand:\t{}", player.0, player.1.print_hand(true)), - PlayerType::Dealer => println!("Dealer Hand:\t{}", player.1.print_hand(true)) - } - }); - - print!("\n"); //empty line - - //get the moves of all remaining players - for player in self.players.iter_mut().enumerate() { - match player.1.player_type {//print the player name - PlayerType::Player => print!("Player{}:", player.0), - PlayerType::Dealer => print!("Dealer:"), + if player.bet == 0 { //player is out of money + break; //exit turn loop } + //play through turn //check their hand value for a blackjack(21) or bust - let score = player.1.hand.get_total(); + let score = player.hand.get_total(); if score >= 21 { if score == 21 { // == 21 - println!("\tBlackjack (21 points)"); + println!("\tBlackjack! (21 points)"); } else { // > 21 println!("\tBust ({} points)", score); } - players_playing.remove(&player.0);//remove player from playing list - continue; + break; //end turn } - //check if player is still playing - if !players_playing.contains(&player.0) {print!("\n");continue;}//print a line and skip to the next iteration of the loop - - //get play - let play = player.1.get_play(); - + //get player move + let play = player.get_play(); //process play match play { Play::Stand => { - println!("\t{}s", play.to_string()); - players_playing.remove(&player.0);//remove player from playing list + println!("\t{}", play.to_string()); + break; //end turn }, Play::Hit => { - println!("\t{}s", play.to_string()); + println!("\t{}", play.to_string()); //give them a card - player.1.hand.add_card( self.decks.draw_card() ); + player.hand.add_card( self.decks.draw_card() ); }, } } - - //loop end condition - if players_playing.is_empty() {break;} + + //add player to score cache thing + player_hands_message += format!("{} Hand:\t{}\n", player.get_name(), player.hand_as_string(true)).as_str(); } //determine winner @@ -410,34 +440,25 @@ impl<'a> GAME<'a> { } } - //print everyones hand - println!(""); - self.players.iter().enumerate().for_each(|player| { - match player.1.player_type { - PlayerType::Player => println!("Player{} Hand:\t{}", player.0, player.1.print_hand(false)), - PlayerType::Dealer => println!("Dealer Hand:\t{}", player.1.print_hand(false)) - } - }); - println!(""); - //for each player with the top score - self.players.iter_mut().enumerate().filter(|x|->bool{x.1.hand.get_total()==top_score}).for_each(|x| { - match x.1.player_type { - PlayerType::Player => print!("Player{}\t", x.0), - PlayerType::Dealer => print!("Dealer\t"), - } - //increment their wins - x.1.wins += 1; + //print winner(s) + self.players.iter_mut().filter(|x|->bool{x.hand.get_total()==top_score}).for_each(|x| {//for each player with the top score + print!("{} ", x.get_name());//print name + x.wins += 1;//increment their wins }); if num_winners > 1 {println!("all tie with {}\n\n\n", top_score);} else {println!("wins with {}!\n\n\n",top_score);} + //handle bets + //remove money from losers + self.players.iter_mut().filter(|p| p.hand.get_total()!=top_score).for_each( |p| p.balance -= p.bet); //for every player who didn't get the winning score, remove their bet from their balance + //add money to winner + self.players.iter_mut().filter(|p| p.hand.get_total()==top_score).for_each(|p| p.balance += p.bet); //for each player who got the winning score, add their bet to their balance + //discard hands self.players.iter_mut().for_each(|player| {player.hand.discard_hand(&mut self.decks);}); //increment games_played self.games_played += 1; - //reset rounds - self.rounds = 0; } @@ -476,10 +497,10 @@ fn main() { */ fn welcome() { //welcome message - println!(" + print!(" BLACK JACK CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - \n\n\n"); + \n\n"); } /** @@ -502,7 +523,10 @@ fn instructions() { NUMBER OF PLAYERS NOTE: Currently only H and S are implemented properly + + PRESS ENTER TO CONTINUE "); + io::stdin().read_line(&mut String::new()).expect("Failed to read line"); } /** @@ -515,7 +539,7 @@ fn get_number_from_user_input(prompt: &str, min:usize, max:usize) -> usize { //print prompt println!("{}", prompt); - + stdout().flush().expect("Failed to flush to stdout."); //read user input from standard input, and store it to raw_input //raw_input.clear(); //clear input io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); @@ -524,11 +548,10 @@ fn get_number_from_user_input(prompt: &str, min:usize, max:usize) -> usize { match raw_input.trim().parse::() { Ok(i) => { if i < min || i > max { //input out of desired range - println!("INPUT OUT OF VALID RANGE. TRY AGAIN."); + println!("INPUT OUT OF VALID RANGE. TRY AGAIN. {}-{}",min,max); continue; // run the loop again } else { - println!(); break i;// this escapes the loop, returning i } }, @@ -551,7 +574,7 @@ fn get_char_from_user_input(prompt: &str, valid_results: &Vec) -> char { //print prompt println!("{}", prompt); - + stdout().flush().expect("Failed to flush to stdout."); //read user input from standard input, and store it to raw_input //raw_input.clear(); //clear input io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); @@ -574,3 +597,10 @@ fn get_char_from_user_input(prompt: &str, valid_results: &Vec) -> char { }; }; } + +/** + * clear std out + */ +fn clear() { + println!("\x1b[2J\x1b[0;0H"); +} From 8bfef01d058f6968188cf70083941d7fdb476239 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 23:31:43 -0800 Subject: [PATCH 15/21] 10_blackjack implement doubling down --- 10_Blackjack/rust/src/main.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 0302527f..622756e9 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -27,12 +27,16 @@ impl ToString for PlayerType { enum Play { Stand, Hit, + DoubleDown, + Split, } impl ToString for Play { fn to_string(&self) -> String { match self { &Play::Hit => return String::from("Hit"), &Play::Stand => return String::from("Stand"), + &Play::DoubleDown => return String::from("Double Down"), + &Play::Split => return String::from("Split") } } } @@ -290,10 +294,12 @@ impl<'a> PLAYER<'a> { } }, &PlayerType::Player => { - let play = get_char_from_user_input("\tWhat is your play?", &vec!['s','S','h','H']); + let play = get_char_from_user_input("\tWhat is your play?", &vec!['s','S','h','H','d','D','/']); match play { 's' | 'S' => return Play::Stand, 'h' | 'H' => return Play::Hit, + 'd' | 'D' => return Play::DoubleDown, + '/' => return Play::Split, _ => panic!("get_char_from_user_input() returned invalid character"), } }, @@ -420,6 +426,22 @@ impl<'a> GAME<'a> { //give them a card player.hand.add_card( self.decks.draw_card() ); }, + Play::DoubleDown => { + println!("\t{}", play.to_string()); + + //double their balance if there's enough money, othewise go all-in + if player.bet * 2 < player.balance { + player.bet *= 2; + } + else { + player.bet = player.balance; + } + //give them a card + player.hand.add_card( self.decks.draw_card() ); + }, + Play::Split => { + + }, } } From becf0599ad1af444a98d1e1949617af995eec9a0 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 23:33:01 -0800 Subject: [PATCH 16/21] update instructions --- 10_Blackjack/rust/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 622756e9..7e3c8c37 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -5,8 +5,6 @@ use std::{io, io::{stdout, Write}}; * todo list: * * allow splitting - * - * allow doubling down */ @@ -544,7 +542,7 @@ fn instructions() { BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'. NUMBER OF PLAYERS - NOTE: Currently only H and S are implemented properly + NOTE:'/' (splitting) is not currently implemented, and does nothing PRESS ENTER TO CONTINUE "); From 6ba2139574f949d08cd46fb0c434de7984ccb8a7 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 23:37:48 -0800 Subject: [PATCH 17/21] bug fix --- 10_Blackjack/rust/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index 7e3c8c37..e1d9a29d 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -292,7 +292,13 @@ impl<'a> PLAYER<'a> { } }, &PlayerType::Player => { - let play = get_char_from_user_input("\tWhat is your play?", &vec!['s','S','h','H','d','D','/']); + let valid_results:Vec; + if self.hand.cards.len() > 2 {//if there are more than 2 cards in the hand, at least one turn has happened, so splitting and doubling down are not allowed + valid_results = vec!['s','S','h','H']; + } else { + valid_results = vec!['s','S','h','H','d','D','/']; + } + let play = get_char_from_user_input("\tWhat is your play?", &valid_results); match play { 's' | 'S' => return Play::Stand, 'h' | 'H' => return Play::Hit, From 23153f8cbda23bcc0ce8960516545103eb562bfd Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Sun, 27 Feb 2022 23:44:18 -0800 Subject: [PATCH 18/21] bug fix dealer wasn't playing because of a logic error, fixed --- 10_Blackjack/rust/src/main.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/10_Blackjack/rust/src/main.rs b/10_Blackjack/rust/src/main.rs index e1d9a29d..e3a0a459 100644 --- a/10_Blackjack/rust/src/main.rs +++ b/10_Blackjack/rust/src/main.rs @@ -401,8 +401,10 @@ impl<'a> GAME<'a> { print!("{}", player_hands_message); println!("{} Hand:\t{}", player.get_name(), player.hand_as_string(true)); - if player.bet == 0 { //player is out of money - break; //exit turn loop + if let PlayerType::Player = player.player_type { //player isn't the dealer + if player.bet == 0 {//player is out of money + break;//exit turn loop + } } //play through turn From 7977ce8cc288d0512b8c40f3ea3fdf0116c9944f Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 2 Mar 2022 21:50:35 -0800 Subject: [PATCH 19/21] remove stuff that is in rust-port-amazing branch --- 02_Amazing/rust/Cargo.toml | 9 -- 02_Amazing/rust/README.md | 3 - 02_Amazing/rust/src/main.rs | 197 ------------------------------------ 3 files changed, 209 deletions(-) delete mode 100644 02_Amazing/rust/Cargo.toml delete mode 100644 02_Amazing/rust/README.md delete mode 100644 02_Amazing/rust/src/main.rs diff --git a/02_Amazing/rust/Cargo.toml b/02_Amazing/rust/Cargo.toml deleted file mode 100644 index 276ea543..00000000 --- a/02_Amazing/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "rust" -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.5" \ No newline at end of file diff --git a/02_Amazing/rust/README.md b/02_Amazing/rust/README.md deleted file mode 100644 index f84e546c..00000000 --- a/02_Amazing/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs deleted file mode 100644 index bc85189f..00000000 --- a/02_Amazing/rust/src/main.rs +++ /dev/null @@ -1,197 +0,0 @@ -use rand::{Rng, thread_rng, prelude::SliceRandom}; -use std::{io, collections::HashSet}; - -fn main() { - //DATA - enum Direction { - LEFT=0, - UP=1, - RIGHT=2, - DOWN=3, - } - impl Direction { - fn val(&self) -> usize { - match self { - Direction::LEFT=>0, - Direction::UP=>1, - Direction::RIGHT=>2, - Direction::DOWN=>3, - } - } - } - const EXIT_DOWN:usize = 1; - const EXIT_RIGHT:usize = 2; - let mut rng = thread_rng(); //rng - /* - vector of: - vectors of: - integers - Initially set to 0, unprocessed cells. - Filled in with consecutive non-zero numbers as cells are processed - */ - let mut used; //2d vector - /* - vector of: - vectors of: - integers - Remains 0 if there is no exit down or right - Set to 1 if there is an exit down - Set to 2 if there is an exit right - Set to 3 if there are exits down and right - */ - let mut walls; //2d vector - let width; - let height; - let entrance_column; //rng, column of entrance - let mut row; - let mut col; - let mut count; - - - - //print welcome message - println!(" - AMAZING PROGRAM - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n"); - - //prompt for input - width = get_user_input("What is your width?"); - print!("\n"); //one blank line below - height = get_user_input("What is your height?"); - print!("\n\n\n\n");//4 blank lines below - - //generate maze - //initialize used and wall vectors - //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) - used = vec![0; (width * height) as usize]; - let mut used: Vec<_> = used.as_mut_slice().chunks_mut(width as usize).collect(); - let used = used.as_mut_slice(); //accessible as used[][] - //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) - walls = vec![0; (width * height) as usize]; - let mut walls: Vec<_> = walls.as_mut_slice().chunks_mut(width as usize).collect(); - let walls = walls.as_mut_slice(); //accessible as walls[][] - - entrance_column=rng.gen_range(0..width-1); - row = 0; - col = entrance_column; - count = 1; - used[row][col] = count; - count += 1; - - while count != width*height + 1 { - //remove possible directions that are blocked or - //hit cells already processed - let mut possible_directions: HashSet = vec![Direction::LEFT.val(),Direction::UP.val(),Direction::RIGHT.val(),Direction::DOWN.val()].into_iter().collect(); //create it as a vector bc that's easy, then convert it to a hashset - if col==0 || used[row][col-1]!=0 { - possible_directions.remove(&Direction::LEFT.val()); - } - if row==0 || used[row-1][col]!=0 { - possible_directions.remove(&Direction::UP.val()); - } - if col==width-1 || used[row][col+1]!=0 { - possible_directions.remove(&Direction::RIGHT.val()); - } - if row==height-1 || used[row+1][col]!=0 { - possible_directions.remove(&Direction::DOWN.val()); - } - - //If we can move in a direction, move and make opening - if possible_directions.len() != 0 { //all values in possible_directions are not NONE - let pos_dir_vec: Vec<_> = possible_directions.into_iter().collect(); // convert the set to a vector to get access to the choose method - //select a random direction - match pos_dir_vec.choose(&mut rng).expect("error") { - 0=> { - col -= 1; - walls[row][col] = EXIT_RIGHT; - }, - 1=> { - row -= 1; - walls[row][col] = EXIT_DOWN; - }, - 2=>{ - walls[row][col] = walls[row][col] + EXIT_RIGHT; - col += 1; - }, - 3=>{ - walls[row][col] = walls[row][col] + EXIT_DOWN; - row += 1; - }, - _=>{}, - } - used[row][col]=count; - count += 1; - } - //otherwise, move to the next used cell, and try again - else { - loop { - if col != width-1 {col += 1;} - else if row != height-1 {row+=1; col=0;} - else {row=0;col=0;} - - if used[row][col] != 0 {break;} - } - } - - } - // Add a random exit - col=rng.gen_range(0..width); - row=height-1; - walls[row][col]+=1; - - //print maze - //first line - for c in 0..width { - if c == entrance_column { - print!(". "); - } - else { - print!(".--"); - } - } - println!("."); - //rest of maze - for r in 0..height { - print!("I"); - for c in 0..width { - if walls[r][c]<2 {print!(" I");} - else {print!(" ");} - } - println!(); - for c in 0..width { - if walls[r][c] == 0 || walls[r][c]==2 {print!(":--");} - else {print!(": ");} - } - println!("."); - } - - - - - - -} - -fn get_user_input(prompt: &str) -> usize { - //DATA - let mut raw_input = String::new(); // temporary variable for user input that can be parsed later - - //input loop - return loop { - - //print prompt - println!("{}", prompt); - - //read user input from standard input, and store it to raw_input - raw_input.clear(); //clear input - io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); - - //from input, try to read a number - match raw_input.trim().parse::() { - Ok(i) => break i, // this escapes the loop, returning i - Err(e) => { - println!("MEANINGLESS DIMENSION. TRY AGAIN. {}", e.to_string().to_uppercase()); - continue; // run the loop again - } - }; - } -} From 2b48798f203462f1bd1499e5392d0e2cfc1e480a Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Thu, 3 Mar 2022 12:04:57 -0800 Subject: [PATCH 20/21] remove stuff that is in rust-port-amazing branch --- 02_Amazing/rust/Cargo.toml | 9 -- 02_Amazing/rust/README.md | 3 - 02_Amazing/rust/src/main.rs | 202 ------------------------------------ 3 files changed, 214 deletions(-) delete mode 100644 02_Amazing/rust/Cargo.toml delete mode 100644 02_Amazing/rust/README.md delete mode 100644 02_Amazing/rust/src/main.rs diff --git a/02_Amazing/rust/Cargo.toml b/02_Amazing/rust/Cargo.toml deleted file mode 100644 index 276ea543..00000000 --- a/02_Amazing/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "rust" -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.5" \ No newline at end of file diff --git a/02_Amazing/rust/README.md b/02_Amazing/rust/README.md deleted file mode 100644 index f84e546c..00000000 --- a/02_Amazing/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file diff --git a/02_Amazing/rust/src/main.rs b/02_Amazing/rust/src/main.rs deleted file mode 100644 index 7abc67cf..00000000 --- a/02_Amazing/rust/src/main.rs +++ /dev/null @@ -1,202 +0,0 @@ -use rand::{Rng, thread_rng, prelude::SliceRandom}; -use std::{io, collections::HashSet}; - -fn main() { - //DATA - enum Direction { - LEFT=0, - UP=1, - RIGHT=2, - DOWN=3, - } - impl Direction { - fn val(&self) -> usize { - match self { - Direction::LEFT=>0, - Direction::UP=>1, - Direction::RIGHT=>2, - Direction::DOWN=>3, - } - } - } - const EXIT_DOWN:usize = 1; - const EXIT_RIGHT:usize = 2; - let mut rng = thread_rng(); //rng - /* - vector of: - vectors of: - integers - Initially set to 0, unprocessed cells. - Filled in with consecutive non-zero numbers as cells are processed - */ - let mut used; //2d vector - /* - vector of: - vectors of: - integers - Remains 0 if there is no exit down or right - Set to 1 if there is an exit down - Set to 2 if there is an exit right - Set to 3 if there are exits down and right - */ - let mut walls; //2d vector - let width; - let height; - let entrance_column; //rng, column of entrance - let mut row; - let mut col; - let mut count; - - - - //print welcome message - println!(" - AMAZING PROGRAM - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n"); - - //prompt for input - width = get_user_input("What is your width?"); - print!("\n"); //one blank line below - height = get_user_input("What is your height?"); - print!("\n\n\n\n");//4 blank lines below - - //generate maze - //initialize used and wall vectors - //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) - used = vec![0; (width * height) as usize]; - let mut used: Vec<_> = used.as_mut_slice().chunks_mut(width as usize).collect(); - let used = used.as_mut_slice(); //accessible as used[][] - //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :) - walls = vec![0; (width * height) as usize]; - let mut walls: Vec<_> = walls.as_mut_slice().chunks_mut(width as usize).collect(); - let walls = walls.as_mut_slice(); //accessible as walls[][] - - entrance_column=rng.gen_range(0..width-1); - row = 0; - col = entrance_column; - count = 1; - used[row][col] = count; - count += 1; - - while count != width*height + 1 { - //remove possible directions that are blocked or - //hit cells already processed - let mut possible_directions: HashSet = vec![Direction::LEFT.val(),Direction::UP.val(),Direction::RIGHT.val(),Direction::DOWN.val()].into_iter().collect(); //create it as a vector bc that's easy, then convert it to a hashset - if col==0 || used[row][col-1]!=0 { - possible_directions.remove(&Direction::LEFT.val()); - } - if row==0 || used[row-1][col]!=0 { - possible_directions.remove(&Direction::UP.val()); - } - if col==width-1 || used[row][col+1]!=0 { - possible_directions.remove(&Direction::RIGHT.val()); - } - if row==height-1 || used[row+1][col]!=0 { - possible_directions.remove(&Direction::DOWN.val()); - } - - //If we can move in a direction, move and make opening - if possible_directions.len() != 0 { //all values in possible_directions are not NONE - let pos_dir_vec: Vec<_> = possible_directions.into_iter().collect(); // convert the set to a vector to get access to the choose method - //select a random direction - match pos_dir_vec.choose(&mut rng).expect("error") { - 0=> { - col -= 1; - walls[row][col] = EXIT_RIGHT; - }, - 1=> { - row -= 1; - walls[row][col] = EXIT_DOWN; - }, - 2=>{ - walls[row][col] = walls[row][col] + EXIT_RIGHT; - col += 1; - }, - 3=>{ - walls[row][col] = walls[row][col] + EXIT_DOWN; - row += 1; - }, - _=>{}, - } - used[row][col]=count; - count += 1; - } - //otherwise, move to the next used cell, and try again - else { - loop { - if col != width-1 {col += 1;} - else if row != height-1 {row+=1; col=0;} - else {row=0;col=0;} - - if used[row][col] != 0 {break;} - } - } - } - // Add a random exit - col=rng.gen_range(0..width); - row=height-1; - walls[row][col]+=1; - - //print maze - //first line - for c in 0..width { - if c == entrance_column { - print!(". "); - } - else { - print!(".--"); - } - } - println!("."); - //rest of maze - for r in 0..height { - print!("I"); - for c in 0..width { - if walls[r][c]<2 {print!(" I");} - else {print!(" ");} - } - println!(); - for c in 0..width { - if walls[r][c] == 0 || walls[r][c]==2 {print!(":--");} - else {print!(": ");} - } - println!("."); - } - - //stops the program from ending until you give input, useful when running a compiled .exe - println!("\n\npress ENTER to exit"); - io::stdin().read_line(&mut String::new()).expect("closing"); -} - -fn get_user_input(prompt: &str) -> usize { - //DATA - let mut raw_input = String::new(); // temporary variable for user input that can be parsed later - - //input loop - return loop { - - //print prompt - println!("{}", prompt); - - //read user input from standard input, and store it to raw_input - raw_input.clear(); //clear input - io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); - - //from input, try to read a number - match raw_input.trim().parse::() { - Ok(i) => { - if i>1 { //min size 1 - break i; // this escapes the loop, returning i - } - else { - println!("INPUT OUT OF RANGE. TRY AGAIN."); - continue;// run the loop again - } - } - Err(e) => { - println!("MEANINGLESS DIMENSION. TRY AGAIN. {}", e.to_string().to_uppercase()); - continue; // run the loop again - } - }; - } -} From d30b6bac150d00b128338bd0d403d07ea05a87e3 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Thu, 3 Mar 2022 13:14:49 -0800 Subject: [PATCH 21/21] rust port of 61_Math_Dice --- 61_Math_Dice/rust/Cargo.toml | 9 +++ 61_Math_Dice/rust/README.md | 5 ++ 61_Math_Dice/rust/src/main.rs | 134 ++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 61_Math_Dice/rust/Cargo.toml create mode 100644 61_Math_Dice/rust/README.md create mode 100644 61_Math_Dice/rust/src/main.rs diff --git a/61_Math_Dice/rust/Cargo.toml b/61_Math_Dice/rust/Cargo.toml new file mode 100644 index 00000000..3b1d02f5 --- /dev/null +++ b/61_Math_Dice/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/61_Math_Dice/rust/README.md b/61_Math_Dice/rust/README.md new file mode 100644 index 00000000..881f0dc1 --- /dev/null +++ b/61_Math_Dice/rust/README.md @@ -0,0 +1,5 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) + +If you wish to give the user more than 2 attempts to get the number, change value assigned to the num_tries variable at the start of the main function \ No newline at end of file diff --git a/61_Math_Dice/rust/src/main.rs b/61_Math_Dice/rust/src/main.rs new file mode 100644 index 00000000..35216933 --- /dev/null +++ b/61_Math_Dice/rust/src/main.rs @@ -0,0 +1,134 @@ +use rand::{Rng, prelude::{thread_rng}}; +use std::io; + +fn main() { + //DATA + let num_tries:u8 = 2; //number of tries the player gets each round, must be at least 1 + let mut rng = thread_rng(); + let mut user_guess: u8; + let mut dice_1:u8; + let mut dice_2:u8; + + //print welcome message + welcome(); + + //game loop + loop { + //roll dice + dice_1 = rng.gen_range(1..=6); + dice_2 = rng.gen_range(1..=6); + + //print dice + print_dice(dice_1); + println!(" +"); + print_dice(dice_2); + println!(" ="); + + //get user guess, they have 2 tries + for t in 0..num_tries { + //get guess + user_guess = get_number_from_user_input("", "That's not a valid number!", 1, 12); + + //if they get it wrong + if user_guess != (dice_1+dice_2) { + //print different message depending on what try they're on + if t < num_tries-1 { // user has tries left + println!("NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER."); + println!(" ="); + } + else { //this is their last try + println!("NO, THE ANSWER IS {}", dice_1+dice_2); + } + } + else { + println!("RIGHT!"); + break; + } + } + + //play again + println!("\nThe dice roll again...."); + } + +} + +/** + * prints the welcome message to the console + */ +fn welcome() { + println!(" + MATH DICE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + \n\n + THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE. + WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION + MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY. + TO CONCLUDE THE LESSON, PRESS Ctrl+C AS YOUR ANSWER.\n + "); +} + +/** + * print the dice, + */ +fn print_dice(dice_value:u8) { + //data + + //top + println!(" ----- "); + //first layer + match dice_value { + 4|5|6 => println!("| * * |"), + 2|3 => println!("| * |"), + _=>println!("| |"), + } + + //second layer + match dice_value { + 1|3|5 => println!("| * |"), + 2|4 => println!("| |"), + _=>println!("| * * |"), + } + + //third layer + match dice_value { + 4|5|6 => println!("| * * |"), + 2|3 => println!("| * |"), + _=>println!("| |"), + } + + //bottom + println!(" ----- "); +} + +/** + * gets a integer from user input + */ +fn get_number_from_user_input(prompt: &str, error_message: &str, min:u8, max:u8) -> u8 { + //input loop + return loop { + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //print prompt + println!("{}", prompt); + //read user input from standard input, and store it to raw_input + //raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + match raw_input.trim().parse::() { + Ok(i) => { + if i < min || i > max { //input out of desired range + println!("{} ({}-{})", error_message, min,max); + continue; // run the loop again + } + else { + break i;// this escapes the loop, returning i + } + }, + Err(e) => { + println!("{} {}", error_message, e.to_string().to_uppercase()); + continue; // run the loop again + } + }; + }; +} \ No newline at end of file