Skip to content

Commit a34fa0e

Browse files
committed
Port 12_Bombs_Away to Rust
1 parent d824b73 commit a34fa0e

File tree

3 files changed

+393
-0
lines changed

3 files changed

+393
-0
lines changed

12_Bombs_Away/rust/Cargo.lock

Lines changed: 75 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

12_Bombs_Away/rust/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "rust"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
rand = "0.8.5"

12_Bombs_Away/rust/src/main.rs

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
use std::{
2+
io::{self, Write},
3+
str::FromStr,
4+
};
5+
6+
use rand::Rng;
7+
8+
struct Italy;
9+
struct Allies;
10+
struct Japan;
11+
struct Germany;
12+
13+
#[derive(Debug, PartialEq, Eq)]
14+
struct ParseChoiceTargetError;
15+
16+
#[derive(PartialEq)]
17+
enum ThreeTarget {
18+
One,
19+
Two,
20+
Three,
21+
}
22+
23+
impl FromStr for ThreeTarget {
24+
type Err = ParseChoiceTargetError;
25+
26+
fn from_str(s: &str) -> Result<Self, Self::Err> {
27+
let n = s.parse::<u8>().map_err(|_| ParseChoiceTargetError)?;
28+
match n {
29+
1 => Ok(Self::One),
30+
2 => Ok(Self::Two),
31+
3 => Ok(Self::Three),
32+
_ => Err(ParseChoiceTargetError),
33+
}
34+
}
35+
}
36+
37+
enum FourTarget {
38+
One,
39+
Two,
40+
Three,
41+
Four,
42+
}
43+
44+
impl FromStr for FourTarget {
45+
type Err = ParseChoiceTargetError;
46+
47+
fn from_str(s: &str) -> Result<Self, Self::Err> {
48+
let n = s.parse::<u8>().map_err(|_| ParseChoiceTargetError)?;
49+
match n {
50+
1 => Ok(Self::One),
51+
2 => Ok(Self::Two),
52+
3 => Ok(Self::Three),
53+
4 => Ok(Self::Four),
54+
_ => Err(ParseChoiceTargetError),
55+
}
56+
}
57+
}
58+
59+
pub trait Brefing {
60+
type TargetOption;
61+
fn prompt<'a>(&self) -> &'a str;
62+
fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str;
63+
}
64+
65+
impl Brefing for Italy {
66+
type TargetOption = ThreeTarget;
67+
68+
fn prompt<'a>(&self) -> &'a str {
69+
"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)"
70+
}
71+
72+
fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {
73+
match target {
74+
ThreeTarget::One => "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.",
75+
ThreeTarget::Two => "BE CAREFUL!!!",
76+
ThreeTarget::Three => "YOU'RE GOING FOR THE OIL, EH?",
77+
}
78+
}
79+
}
80+
81+
impl Brefing for Allies {
82+
type TargetOption = FourTarget;
83+
84+
fn prompt<'a>(&self) -> &'a str {
85+
"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): "
86+
}
87+
88+
fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {
89+
match target {
90+
FourTarget::One => "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.",
91+
FourTarget::Two => "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.",
92+
FourTarget::Three => "YOU'RE CHASING THE BISMARK IN THE NORTH SEA.",
93+
FourTarget::Four => "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.",
94+
}
95+
}
96+
}
97+
98+
impl Brefing for Germany {
99+
type TargetOption = ThreeTarget;
100+
101+
fn prompt<'a>(&self) -> &'a str {
102+
"A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? "
103+
}
104+
105+
fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {
106+
match target {
107+
ThreeTarget::One => "YOU'RE NEARING STALINGRAD.",
108+
ThreeTarget::Two => "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.",
109+
ThreeTarget::Three => "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.",
110+
}
111+
}
112+
}
113+
114+
enum Side {
115+
Italy(Italy),
116+
Allies(Allies),
117+
Japan(Japan),
118+
Germany(Germany),
119+
}
120+
121+
impl From<FourTarget> for Side {
122+
fn from(value: FourTarget) -> Self {
123+
match value {
124+
FourTarget::One => Self::Italy(Italy),
125+
FourTarget::Two => Self::Allies(Allies),
126+
FourTarget::Three => Self::Japan(Japan),
127+
FourTarget::Four => Self::Germany(Germany),
128+
}
129+
}
130+
}
131+
132+
fn stdin_choice<C: FromStr>(prompt: &str) -> C {
133+
let mut buffer = String::new();
134+
135+
print!("{prompt}");
136+
io::stdout().flush().unwrap();
137+
io::stdin().read_line(&mut buffer).unwrap();
138+
loop {
139+
if let Ok(choice) = buffer.trim().parse::<C>() {
140+
return choice;
141+
}
142+
print!("TRY AGAIN...");
143+
io::stdout().flush().unwrap();
144+
io::stdin().read_line(&mut buffer).unwrap();
145+
}
146+
}
147+
148+
fn stdin_y_or_n(prompt: &str) -> bool {
149+
let mut buffer = String::new();
150+
151+
print!("{prompt}");
152+
io::stdout().flush().unwrap();
153+
io::stdin().read_line(&mut buffer).unwrap();
154+
buffer.trim().to_uppercase() == "Y"
155+
}
156+
157+
fn commence_non_kamikazi_attack() {
158+
let nmissions = loop {
159+
let nmissions = stdin_choice::<i32>("HOW MANY MISSIONS HAVE YOU FLOWN? ");
160+
if nmissions < 160 {
161+
break nmissions;
162+
}
163+
println!("MISSIONS, NOT MILES...");
164+
println!("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS");
165+
print!("NOW THEN, ");
166+
};
167+
168+
if nmissions >= 100 {
169+
println!("THAT'S PUSHING THE ODDS!");
170+
}
171+
172+
if nmissions < 25 {
173+
println!("FRESH OUT OF TRAINING, EH?");
174+
}
175+
176+
println!();
177+
178+
let mut rng = rand::thread_rng();
179+
let y: f32 = rng.gen();
180+
181+
if nmissions as f32 >= 160_f32 * y {
182+
mission_success();
183+
} else {
184+
mission_failure();
185+
}
186+
}
187+
188+
fn play_japan() {
189+
if !stdin_y_or_n("YOUR FIRST KAMIKAZE MISSION? (Y OR N): ") {
190+
player_death();
191+
return;
192+
}
193+
194+
let mut rng = rand::thread_rng();
195+
let y: f32 = rng.gen();
196+
if y > 0.65 {
197+
mission_success();
198+
} else {
199+
player_death();
200+
}
201+
}
202+
203+
fn player_death() {
204+
println!("* * * * BOOM * * * *");
205+
println!("YOU HAVE BEEN SHOT DOWN.....");
206+
println!("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR");
207+
println!("LAST TRIBUTE...");
208+
}
209+
210+
fn mission_success() {
211+
let mut rng = rand::thread_rng();
212+
let y: f32 = rng.gen();
213+
214+
let killed = (100f32 * y) as i32;
215+
println!("DIRECT HIT!!!! {killed} KILLED.");
216+
println!("MISSION SUCCESSFUL.");
217+
}
218+
219+
fn mission_failure() {
220+
let mut rng = rand::thread_rng();
221+
let y: f32 = rng.gen();
222+
let miles = 2 + (30f32 * y) as i32;
223+
println!("MISSED TARGET BY {miles} MILES!");
224+
println!("NOW YOU'RE REALLY IN FOR IT !!");
225+
println!();
226+
let enemy_weapons =
227+
stdin_choice::<ThreeTarget>("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ");
228+
229+
let enemy_gunner_accuracy = if enemy_weapons != ThreeTarget::Two {
230+
let m = loop {
231+
let m =
232+
stdin_choice::<i32>("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ");
233+
if m <= 50 {
234+
break m;
235+
}
236+
println!("TRY AGAIN...");
237+
};
238+
if m < 10 {
239+
println!("YOU LIE, BUT YOU'LL PAY...");
240+
player_death();
241+
return;
242+
}
243+
m
244+
} else {
245+
0
246+
};
247+
248+
let missile_threat_weighting = if enemy_weapons == ThreeTarget::One {
249+
0
250+
} else {
251+
35
252+
};
253+
254+
let death =
255+
death_with_chance((enemy_gunner_accuracy + missile_threat_weighting) as f32 / 100f32);
256+
257+
if death {
258+
player_death();
259+
} else {
260+
player_survived();
261+
}
262+
}
263+
264+
fn player_survived() {
265+
println!("YOU MADE IT THROUGH TREMENDOUS FLAK!!");
266+
}
267+
268+
fn death_with_chance(p_death: f32) -> bool {
269+
let mut rng = rand::thread_rng();
270+
let y: f32 = rng.gen();
271+
p_death > y
272+
}
273+
274+
fn main() {
275+
loop {
276+
println!("YOU ARE A PILOT IN A WORLD WAR II BOMBER.");
277+
let side: Side =
278+
stdin_choice::<FourTarget>("WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ")
279+
.into();
280+
281+
match side {
282+
Side::Japan(_) => {
283+
println!("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.");
284+
}
285+
Side::Italy(ref s) => {
286+
let target = stdin_choice(s.prompt());
287+
println!("{}", s.targets_to_messages(target));
288+
}
289+
Side::Allies(ref s) => {
290+
let target = stdin_choice(s.prompt());
291+
println!("{}", s.targets_to_messages(target));
292+
}
293+
Side::Germany(ref s) => {
294+
let target = stdin_choice(s.prompt());
295+
println!("{}", s.targets_to_messages(target));
296+
}
297+
}
298+
299+
match side {
300+
Side::Japan(_) => play_japan(),
301+
_ => commence_non_kamikazi_attack(),
302+
}
303+
304+
println!();
305+
if !stdin_y_or_n("ANOTHER MISSION? (Y OR N): ") {
306+
break;
307+
}
308+
}
309+
}

0 commit comments

Comments
 (0)