Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### Test Image specific config

FROM rust:1.85-slim-bookworm
FROM rust:1.86-slim-bookworm

RUN apt-get update
RUN apt-get -y install pkg-config libssl-dev moreutils
Expand Down
152 changes: 36 additions & 116 deletions solutions/borrow_box/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,139 +1,59 @@
use std::cmp::Ordering;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct GameSession {
pub id: u32,
pub p1: (String, u16),
pub p2: (String, u16),
pub nb_games: u16,
pub p1: (String, u32),
pub p2: (String, u32),
pub nb_games: u32,
}

impl GameSession {
// create the box
pub fn new(id: u32, p1_name: String, p2_name: String, nb_games: u16) -> Box<GameSession> {
Box::new(GameSession {
#[inline]
pub fn new(id: u32, p1_name: String, p2_name: String, nb_games: u32) -> GameSession {
GameSession {
id,
p1: (p1_name, 0),
p2: (p2_name, 0),
p1: (p1_name, Default::default()),
p2: (p2_name, Default::default()),
nb_games,
})
}

// read from the box using the reference `&`
// return only the player that as the bigger score
pub fn read_winner(&self) -> (String, u16) {
if self.p1.1 > self.p2.1 {
self.p1.clone()
} else if self.p1.1 < self.p2.1 {
self.p2.clone()
} else {
(String::from("Same score! tied"), self.p2.1)
}
}

pub fn update_score(&mut self, user_name: String) {
if self.p1.1 + self.p2.1 < self.nb_games
&& self.p1.1 * 2 <= self.nb_games
&& self.p2.1 * 2 <= self.nb_games
{
if self.p1.0 == user_name {
self.p1.1 += 1;
} else if self.p2.0 == user_name {
self.p2.1 += 1;
}
#[inline]
pub fn read_winner(&self) -> Option<&(String, u32)> {
match self.p1.1.cmp(&self.p2.1) {
Ordering::Greater => Some(&self.p1),
Ordering::Less => Some(&self.p2),
Ordering::Equal => None,
}
}

pub fn delete(self) -> String {
String::from(format!("game deleted: id -> {:?}", self.id))
}
}

#[cfg(test)]
mod tests {
use super::*;

fn create_games() -> Vec<Box<GameSession>> {
vec![
GameSession::new(0, String::from("player1"), String::from("player2"), 1),
GameSession::new(1, String::from("Alice"), String::from("Mark"), 3),
GameSession::new(2, String::from("Jack"), String::from("Miller"), 5),
]
}

#[test]
fn test_create() {
let games = create_games();
assert_eq!(
*games[0],
GameSession {
id: 0,
p1: (String::from("player1"), 0),
p2: (String::from("player2"), 0),
nb_games: 1
}
);
assert_eq!(
*games[1],
GameSession {
id: 1,
p1: (String::from("Alice"), 0),
p2: (String::from("Mark"), 0),
nb_games: 3
}
);
assert_eq!(
*games[2],
GameSession {
id: 2,
p1: (String::from("Jack"), 0),
p2: (String::from("Miller"), 0),
nb_games: 5
}
);
#[inline]
fn game_ended(&self) -> bool {
self.p1.1 * 2 > self.nb_games
|| self.p2.1 * 2 > self.nb_games
|| self.p1.1 + self.p2.1 == self.nb_games
}

#[test]
fn test_update_and_read() {
let mut games = create_games();
games[0].update_score(String::from("player1"));
assert_eq!(games[0].read_winner(), (String::from("player1"), 1));

games[0].update_score(String::from("player2"));
// this will stay the same because the nb_games is 1 so if one
// of the players wins just once it will no longer increment the score
assert_eq!(games[0].read_winner(), (String::from("player1"), 1));
pub fn update_score(&mut self, user_name: &str) {
if self.game_ended() {
return;
}

games[2].update_score(String::from("Jack"));
games[2].update_score(String::from("Jack"));
games[2].update_score(String::from("Miller"));
games[2].update_score(String::from("Miller"));
// tie between players
assert_eq!(
games[2].read_winner(),
(String::from("Same score! tied"), 2)
);
let player = if self.p1.0 == user_name {
&mut self.p1
} else if self.p2.0 == user_name {
&mut self.p2
} else {
return;
};

games[2].update_score(String::from("Jack"));
assert_eq!(games[2].read_winner(), (String::from("Jack"), 3));
player.1 += 1;
}

#[test]
fn test_delete() {
let game = GameSession::new(0, String::from("Alice"), String::from("Mark"), 3);
let game1 = GameSession::new(23, String::from("Jack"), String::from("Miller"), 1);
pub fn delete(self) -> String {
let id = self.id;

assert_eq!(game.delete(), String::from("game deleted: id -> 0"));
assert_eq!(game1.delete(), String::from("game deleted: id -> 23"));
format!("game deleted: id -> {id}")
}

// #[test]
// #[should_panic]
// fn test_delete_ownership() {
// let game = new(0, String::from("Alice"), String::from("Mark"), 3);
// {
// let a = &game;
// // error! cant destroy boxed while the inner value is borrowed later in scope
// delete(game);
// read_winner(&a);
// }
// }
}
14 changes: 7 additions & 7 deletions solutions/bowling_score/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ pub enum Error {
}

pub struct BowlingGame {
rolls: Vec<u16>,
pins_left: u16,
rolls_in_frame: u16,
fill_balls: u16,
rolls: Vec<u32>,
pins_left: u32,
rolls_in_frame: u32,
fill_balls: u32,
}

impl BowlingGame {
Expand All @@ -21,7 +21,7 @@ impl BowlingGame {
}
}

pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
pub fn roll(&mut self, pins: u32) -> Result<(), Error> {
if pins > self.pins_left {
return Err(Error::NotEnoughPinsLeft);
} else if self.rolls.len() >= 20 && self.fill_balls == 0 {
Expand All @@ -48,7 +48,7 @@ impl BowlingGame {
Ok(())
}

fn strike_or_spare(&mut self, pins: u16) {
fn strike_or_spare(&mut self, pins: u32) {
if self.rolls_in_frame == 2 {
self.rolls_in_frame -= 1;
self.rolls.push(0);
Expand All @@ -61,7 +61,7 @@ impl BowlingGame {
}
}

pub fn score(&self) -> Option<u16> {
pub fn score(&self) -> Option<u32> {
if self.rolls.len() < 20 || self.fill_balls != 0 {
return None;
}
Expand Down
119 changes: 14 additions & 105 deletions solutions/box_it/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,106 +1,15 @@
/*
## box_it

### Instructions

Create the following functions:

- `transform_and_save_on_heap`, that receives a string with a number (that can or not have a k (kilo) suffix)
and transforms those numbers into `u32` and inserts it into a vector that must be saved in the heap using **Box**.

- `take_value_ownership`, that takes the value (unboxed value) form the box and returns it

### Notions

- https://doc.rust-lang.org/book/ch15-00-smart-pointers.html
- https://doc.rust-lang.org/book/ch15-01-box.html

*/
fn convert(s: &str) -> u32 {
let mut a = s.to_string();
a.pop();
let n = a.parse::<f32>().unwrap();
(n * 1000.0) as u32
}

pub fn transform_and_save_on_heap(s: String) -> Box<Vec<u32>> {
let mut v: Vec<u32> = Vec::new();

for token in s.split_whitespace() {
if token.contains("k") {
v.push(convert(token));
} else {
v.push(token.parse::<u32>().unwrap());
}
}
Box::new(v)
}

pub fn take_value_ownership(a: Box<Vec<u32>>) -> Vec<u32> {
*a
}

/*
// Example :

fn main() {
let new_str = String::from("5.5k 8.9k 32");

// creating a variable and we save it in the Heap
let a_h = transform_and_save_on_heap(new_str);
println!("Box value : {:?}", &a_h);
println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_h)));

let a_b_v = take_value_ownership(a_h);
println!("value : {:?}", &a_b_v);
println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_b_v)));
// output :
// | Box value : [6800, 13500]
// | size occupied in the stack : 8 bytes
// | value : [6800, 13500]
// | size occupied in the stack : 24 bytes

// whenever the box, in this case "a_h", goes out of scope it will be deallocated, freed
}
*/

#[cfg(test)]
mod tests {
use super::*;
use std::mem;

#[test]
fn test_transform() {
let new_str = String::from("5.5k 8.9k 32");
let new_str_1 = String::from("6.8k 13.5k");
let new_str_2 = String::from("20.3k 3.8k 7.7k 992");

let a = transform_and_save_on_heap(new_str);
let b = transform_and_save_on_heap(new_str_1);
let c = transform_and_save_on_heap(new_str_2);

assert_eq!(a, Box::new(vec![5500, 8900, 32]));
assert_eq!(b, Box::new(vec![6800, 13500]));
assert_eq!(c, Box::new(vec![20300, 3800, 7700, 992]));
assert_eq!(mem::size_of_val(&a), 8);
assert_eq!(mem::size_of_val(&b), 8);
assert_eq!(mem::size_of_val(&c), 8);
}

#[test]
fn test_take_value_from_box() {
let new_str = String::from("5.5k 8.9k 32");
let new_str_1 = String::from("6.8k 13.5k");
let new_str_2 = String::from("20.3k 3.8k 7.7k 992");
let a = take_value_ownership(transform_and_save_on_heap(new_str));
let b = take_value_ownership(transform_and_save_on_heap(new_str_1));
let c = take_value_ownership(transform_and_save_on_heap(new_str_2));

assert_eq!(a, vec![5500, 8900, 32]);
assert_eq!(b, vec![6800, 13500]);
assert_eq!(c, vec![20300, 3800, 7700, 992]);
assert_eq!(mem::size_of_val(&a), 24);
assert_eq!(mem::size_of_val(&b), 24);
assert_eq!(mem::size_of_val(&c), 24);
}
pub fn parse_into_boxed(s: String) -> Vec<Box<u32>> {
s.split_ascii_whitespace()
.map(|v| {
if let Some(v) = v.strip_suffix('k') {
Box::new((v.parse::<f64>().unwrap() * 1000.) as _)
} else {
Box::new(v.parse().unwrap())
}
})
.collect()
}

pub fn into_unboxed(a: Vec<Box<u32>>) -> Vec<u32> {
a.into_iter().map(|b| *b).collect()
}
Loading
Loading