Skip to main content
Inline image for better or worse
Source Link
Shepmaster
  • 8.8k
  • 27
  • 28
//! XternCoin Application
//! Casey Primozic - 2016
//!
//! Requires latest Rust nightly

// turn on the unstable testing feature
#![feature(test)]

extern crate rand;
extern crate test;

use std::sync::{Arc, Mutex};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};
use std::thread;
use std::convert::From;

/// The server which manages the Proof of Work check and dispenses the currency
///
/// The server is threadsafe and can be duplicated over an arbitary number of threads
/// so that any number of users can mine simultaneously.
#[derive(Clone)]
struct CoinServer {
    // concurrent hashmap to store the balances of all users
    // this allows shared mutable access to the balance database through `lock()`.
    pub balances: Arc<Mutex<HashMap<String, f64>>>, // only public for sake of the test
    pub random_num: Arc<AtomicUsize>,
}

impl CoinServer {
    /// Function which takes a user's id and a user's guess,
    /// and returns whether or not their guess was correct.
    pub fn handle_guess(&mut self, user_id: String, guess: u64) {
        // convert the String to a u64 for comparison
        if self.random_num.load(Ordering::Relaxed) == guess as usize {
            self.inc_balance(user_id);
            self.get_new_rand();
        }
    }
    
    /// Adds one to the user's balance, creating an entry for it if
    /// it doesn't exist.
    fn inc_balance(&mut self, user_id: String) {
        // lock the balances
        let mut balances = self.balances.lock().unwrap();

        // insert user if not already in database
        if !balances.contains_key(&user_id) {
            balances.insert(user_id, 1f64);
            return
        }

        // credit the user for the correct guess
        let balance = balances.get_mut(&user_id).unwrap();
        *balance += 1f64;
    }
    
    /// Function which takes a userid and returns
    /// how many coins they have.
    pub fn get_coins(&mut self, user_id: String) -> f64 {
        let balances = self.balances.lock().unwrap();
        
        if !balances.contains_key(&user_id) { return 0f64 }
        *balances.get(&user_id).unwrap()
    }
    
    pub fn new() -> CoinServer {
        let mut server = CoinServer {
            balances: Arc::new(Mutex::new(HashMap::new())),
            random_num: Arc::new(AtomicUsize::new(0))
        };
        server.get_new_rand();
        server
    } // I'm using a text editor to debug this: https://ameo.link/u/3ew.png
    
    /// Creates a new random number for users to try to guess
    fn get_new_rand(&mut self) {
        // entropy source
        let mut rng = rand::thread_rng();
        // generate random number from 0 to 100000
        let rand_num: usize = rng.gen_range(0, 100000);
        self.random_num.store(rand_num, Ordering::Relaxed);
    }
}


/// A function which, when called, pretends to be a user of
/// XternCoin and uses the other two functions you've written
/// to accumulate coins by guessing random numbers in a loop
fn start_guessing(user_id: String, mut server: CoinServer, iterations: usize) {
    // entropy source
    let mut rng = rand::thread_rng();

    for _ in 0..iterations {
        let guess: u64 = rng.gen_range(0, 100000);
        // make guess and let server verify it
        server.handle_guess(user_id.clone(), guess);
    }
}

fn main() {
    let server = CoinServer::new();
    
    // spawn 10 threads to start guessing
    for i in 0..10 {
        let mut server_clone = server.clone();
        thread::spawn(move || {
            let user_id = format!("{}", i);
            // initiate mining
            start_guessing(user_id.clone(), server_clone.clone(), 100000);
            println!("Balance for {} after this mining session: {}", user_id.clone(), server_clone.get_coins(user_id));
        });
    }
    
    // block so the miners can mine
    thread::park();
}

// TODO: tests1

/// Check to make sure that user balances are created and incremented
#[test]
fn test_mining() {
    let mut server = CoinServer {
        balances: Arc::new(Mutex::new(HashMap::new())),
        random_num: Arc::new(AtomicUsize::new(42)) // cheat for the test
    };
    
    let user_id = "Test".to_string();
    server.handle_guess(user_id.clone(), 42);

    // make sure we got credited
    assert_eq!(server.get_coins(user_id), 1f64);
    // server generated a new random number
    assert!(server.random_num.load(Ordering::Relaxed) != 42);
    // test passes: https://ameo.link/u/3ey.png
}

// program output: https://ameo.link/u/3ez.png

// Cargo.toml:
//
// [package]
// name = "xt"
// version = "0.1.0"
// authors = ["Casey Primozic <[email protected]>"]
//
// [dependencies]
// rand = "0.3"

Program output: https://ameo.link/u/3ez.png

Cargo.toml:

[package]
name = "xt"
version = "0.1.0"
authors = ["Casey Primozic <[email protected]>"]

[dependencies]
rand = "0.3"
//! XternCoin Application
//! Casey Primozic - 2016
//!
//! Requires latest Rust nightly

// turn on the unstable testing feature
#![feature(test)]

extern crate rand;
extern crate test;

use std::sync::{Arc, Mutex};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};
use std::thread;
use std::convert::From;

/// The server which manages the Proof of Work check and dispenses the currency
///
/// The server is threadsafe and can be duplicated over an arbitary number of threads
/// so that any number of users can mine simultaneously.
#[derive(Clone)]
struct CoinServer {
    // concurrent hashmap to store the balances of all users
    // this allows shared mutable access to the balance database through `lock()`.
    pub balances: Arc<Mutex<HashMap<String, f64>>>, // only public for sake of the test
    pub random_num: Arc<AtomicUsize>,
}

impl CoinServer {
    /// Function which takes a user's id and a user's guess,
    /// and returns whether or not their guess was correct.
    pub fn handle_guess(&mut self, user_id: String, guess: u64) {
        // convert the String to a u64 for comparison
        if self.random_num.load(Ordering::Relaxed) == guess as usize {
            self.inc_balance(user_id);
            self.get_new_rand();
        }
    }
    
    /// Adds one to the user's balance, creating an entry for it if
    /// it doesn't exist.
    fn inc_balance(&mut self, user_id: String) {
        // lock the balances
        let mut balances = self.balances.lock().unwrap();

        // insert user if not already in database
        if !balances.contains_key(&user_id) {
            balances.insert(user_id, 1f64);
            return
        }

        // credit the user for the correct guess
        let balance = balances.get_mut(&user_id).unwrap();
        *balance += 1f64;
    }
    
    /// Function which takes a userid and returns
    /// how many coins they have.
    pub fn get_coins(&mut self, user_id: String) -> f64 {
        let balances = self.balances.lock().unwrap();
        
        if !balances.contains_key(&user_id) { return 0f64 }
        *balances.get(&user_id).unwrap()
    }
    
    pub fn new() -> CoinServer {
        let mut server = CoinServer {
            balances: Arc::new(Mutex::new(HashMap::new())),
            random_num: Arc::new(AtomicUsize::new(0))
        };
        server.get_new_rand();
        server
    } // I'm using a text editor to debug this: https://ameo.link/u/3ew.png
    
    /// Creates a new random number for users to try to guess
    fn get_new_rand(&mut self) {
        // entropy source
        let mut rng = rand::thread_rng();
        // generate random number from 0 to 100000
        let rand_num: usize = rng.gen_range(0, 100000);
        self.random_num.store(rand_num, Ordering::Relaxed);
    }
}


/// A function which, when called, pretends to be a user of
/// XternCoin and uses the other two functions you've written
/// to accumulate coins by guessing random numbers in a loop
fn start_guessing(user_id: String, mut server: CoinServer, iterations: usize) {
    // entropy source
    let mut rng = rand::thread_rng();

    for _ in 0..iterations {
        let guess: u64 = rng.gen_range(0, 100000);
        // make guess and let server verify it
        server.handle_guess(user_id.clone(), guess);
    }
}

fn main() {
    let server = CoinServer::new();
    
    // spawn 10 threads to start guessing
    for i in 0..10 {
        let mut server_clone = server.clone();
        thread::spawn(move || {
            let user_id = format!("{}", i);
            // initiate mining
            start_guessing(user_id.clone(), server_clone.clone(), 100000);
            println!("Balance for {} after this mining session: {}", user_id.clone(), server_clone.get_coins(user_id));
        });
    }
    
    // block so the miners can mine
    thread::park();
}

// TODO: tests1

/// Check to make sure that user balances are created and incremented
#[test]
fn test_mining() {
    let mut server = CoinServer {
        balances: Arc::new(Mutex::new(HashMap::new())),
        random_num: Arc::new(AtomicUsize::new(42)) // cheat for the test
    };
    
    let user_id = "Test".to_string();
    server.handle_guess(user_id.clone(), 42);

    // make sure we got credited
    assert_eq!(server.get_coins(user_id), 1f64);
    // server generated a new random number
    assert!(server.random_num.load(Ordering::Relaxed) != 42);
    // test passes: https://ameo.link/u/3ey.png
}

// program output: https://ameo.link/u/3ez.png

// Cargo.toml:
//
// [package]
// name = "xt"
// version = "0.1.0"
// authors = ["Casey Primozic <[email protected]>"]
//
// [dependencies]
// rand = "0.3"
//! XternCoin Application
//! Casey Primozic - 2016
//!
//! Requires latest Rust nightly

// turn on the unstable testing feature
#![feature(test)]

extern crate rand;
extern crate test;

use std::sync::{Arc, Mutex};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};
use std::thread;
use std::convert::From;

/// The server which manages the Proof of Work check and dispenses the currency
///
/// The server is threadsafe and can be duplicated over an arbitary number of threads
/// so that any number of users can mine simultaneously.
#[derive(Clone)]
struct CoinServer {
    // concurrent hashmap to store the balances of all users
    // this allows shared mutable access to the balance database through `lock()`.
    pub balances: Arc<Mutex<HashMap<String, f64>>>, // only public for sake of the test
    pub random_num: Arc<AtomicUsize>,
}

impl CoinServer {
    /// Function which takes a user's id and a user's guess,
    /// and returns whether or not their guess was correct.
    pub fn handle_guess(&mut self, user_id: String, guess: u64) {
        // convert the String to a u64 for comparison
        if self.random_num.load(Ordering::Relaxed) == guess as usize {
            self.inc_balance(user_id);
            self.get_new_rand();
        }
    }
    
    /// Adds one to the user's balance, creating an entry for it if
    /// it doesn't exist.
    fn inc_balance(&mut self, user_id: String) {
        // lock the balances
        let mut balances = self.balances.lock().unwrap();

        // insert user if not already in database
        if !balances.contains_key(&user_id) {
            balances.insert(user_id, 1f64);
            return
        }

        // credit the user for the correct guess
        let balance = balances.get_mut(&user_id).unwrap();
        *balance += 1f64;
    }
    
    /// Function which takes a userid and returns
    /// how many coins they have.
    pub fn get_coins(&mut self, user_id: String) -> f64 {
        let balances = self.balances.lock().unwrap();
        
        if !balances.contains_key(&user_id) { return 0f64 }
        *balances.get(&user_id).unwrap()
    }
    
    pub fn new() -> CoinServer {
        let mut server = CoinServer {
            balances: Arc::new(Mutex::new(HashMap::new())),
            random_num: Arc::new(AtomicUsize::new(0))
        };
        server.get_new_rand();
        server
    } // I'm using a text editor to debug this: https://ameo.link/u/3ew.png
    
    /// Creates a new random number for users to try to guess
    fn get_new_rand(&mut self) {
        // entropy source
        let mut rng = rand::thread_rng();
        // generate random number from 0 to 100000
        let rand_num: usize = rng.gen_range(0, 100000);
        self.random_num.store(rand_num, Ordering::Relaxed);
    }
}


/// A function which, when called, pretends to be a user of
/// XternCoin and uses the other two functions you've written
/// to accumulate coins by guessing random numbers in a loop
fn start_guessing(user_id: String, mut server: CoinServer, iterations: usize) {
    // entropy source
    let mut rng = rand::thread_rng();

    for _ in 0..iterations {
        let guess: u64 = rng.gen_range(0, 100000);
        // make guess and let server verify it
        server.handle_guess(user_id.clone(), guess);
    }
}

fn main() {
    let server = CoinServer::new();
    
    // spawn 10 threads to start guessing
    for i in 0..10 {
        let mut server_clone = server.clone();
        thread::spawn(move || {
            let user_id = format!("{}", i);
            // initiate mining
            start_guessing(user_id.clone(), server_clone.clone(), 100000);
            println!("Balance for {} after this mining session: {}", user_id.clone(), server_clone.get_coins(user_id));
        });
    }
    
    // block so the miners can mine
    thread::park();
}

// TODO: tests1

/// Check to make sure that user balances are created and incremented
#[test]
fn test_mining() {
    let mut server = CoinServer {
        balances: Arc::new(Mutex::new(HashMap::new())),
        random_num: Arc::new(AtomicUsize::new(42)) // cheat for the test
    };
    
    let user_id = "Test".to_string();
    server.handle_guess(user_id.clone(), 42);

    // make sure we got credited
    assert_eq!(server.get_coins(user_id), 1f64);
    // server generated a new random number
    assert!(server.random_num.load(Ordering::Relaxed) != 42);
    // test passes: https://ameo.link/u/3ey.png
}

Program output: https://ameo.link/u/3ez.png

Cargo.toml:

[package]
name = "xt"
version = "0.1.0"
authors = ["Casey Primozic <[email protected]>"]

[dependencies]
rand = "0.3"
Source Link
Ameo
  • 175
  • 5

Internship coding challenge post-mortem

I wrote this in 78 minutes as part of an application to an internship program. We were allowed to use whatever language we wanted, so I picked Rust because that's what I use the most. I'm a Sophomore CS/Data Science major and I just wanted to get a feel for how you more experienced among us feel about what I made.

I'm not asking for detailed analysis (I know it works and that that it fits the prompt), I'm just looking for broad feedback and any random observations.

Prompt TL;DR:

  • server picks a random number

  • clients try to guess it

  • if client guesses it, server raises their balance by 1 and picks new number


//! XternCoin Application
//! Casey Primozic - 2016
//!
//! Requires latest Rust nightly

// turn on the unstable testing feature
#![feature(test)]

extern crate rand;
extern crate test;

use std::sync::{Arc, Mutex};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};
use std::thread;
use std::convert::From;

/// The server which manages the Proof of Work check and dispenses the currency
///
/// The server is threadsafe and can be duplicated over an arbitary number of threads
/// so that any number of users can mine simultaneously.
#[derive(Clone)]
struct CoinServer {
    // concurrent hashmap to store the balances of all users
    // this allows shared mutable access to the balance database through `lock()`.
    pub balances: Arc<Mutex<HashMap<String, f64>>>, // only public for sake of the test
    pub random_num: Arc<AtomicUsize>,
}

impl CoinServer {
    /// Function which takes a user's id and a user's guess,
    /// and returns whether or not their guess was correct.
    pub fn handle_guess(&mut self, user_id: String, guess: u64) {
        // convert the String to a u64 for comparison
        if self.random_num.load(Ordering::Relaxed) == guess as usize {
            self.inc_balance(user_id);
            self.get_new_rand();
        }
    }
    
    /// Adds one to the user's balance, creating an entry for it if
    /// it doesn't exist.
    fn inc_balance(&mut self, user_id: String) {
        // lock the balances
        let mut balances = self.balances.lock().unwrap();

        // insert user if not already in database
        if !balances.contains_key(&user_id) {
            balances.insert(user_id, 1f64);
            return
        }

        // credit the user for the correct guess
        let balance = balances.get_mut(&user_id).unwrap();
        *balance += 1f64;
    }
    
    /// Function which takes a userid and returns
    /// how many coins they have.
    pub fn get_coins(&mut self, user_id: String) -> f64 {
        let balances = self.balances.lock().unwrap();
        
        if !balances.contains_key(&user_id) { return 0f64 }
        *balances.get(&user_id).unwrap()
    }
    
    pub fn new() -> CoinServer {
        let mut server = CoinServer {
            balances: Arc::new(Mutex::new(HashMap::new())),
            random_num: Arc::new(AtomicUsize::new(0))
        };
        server.get_new_rand();
        server
    } // I'm using a text editor to debug this: https://ameo.link/u/3ew.png
    
    /// Creates a new random number for users to try to guess
    fn get_new_rand(&mut self) {
        // entropy source
        let mut rng = rand::thread_rng();
        // generate random number from 0 to 100000
        let rand_num: usize = rng.gen_range(0, 100000);
        self.random_num.store(rand_num, Ordering::Relaxed);
    }
}


/// A function which, when called, pretends to be a user of
/// XternCoin and uses the other two functions you've written
/// to accumulate coins by guessing random numbers in a loop
fn start_guessing(user_id: String, mut server: CoinServer, iterations: usize) {
    // entropy source
    let mut rng = rand::thread_rng();

    for _ in 0..iterations {
        let guess: u64 = rng.gen_range(0, 100000);
        // make guess and let server verify it
        server.handle_guess(user_id.clone(), guess);
    }
}

fn main() {
    let server = CoinServer::new();
    
    // spawn 10 threads to start guessing
    for i in 0..10 {
        let mut server_clone = server.clone();
        thread::spawn(move || {
            let user_id = format!("{}", i);
            // initiate mining
            start_guessing(user_id.clone(), server_clone.clone(), 100000);
            println!("Balance for {} after this mining session: {}", user_id.clone(), server_clone.get_coins(user_id));
        });
    }
    
    // block so the miners can mine
    thread::park();
}

// TODO: tests1

/// Check to make sure that user balances are created and incremented
#[test]
fn test_mining() {
    let mut server = CoinServer {
        balances: Arc::new(Mutex::new(HashMap::new())),
        random_num: Arc::new(AtomicUsize::new(42)) // cheat for the test
    };
    
    let user_id = "Test".to_string();
    server.handle_guess(user_id.clone(), 42);

    // make sure we got credited
    assert_eq!(server.get_coins(user_id), 1f64);
    // server generated a new random number
    assert!(server.random_num.load(Ordering::Relaxed) != 42);
    // test passes: https://ameo.link/u/3ey.png
}

// program output: https://ameo.link/u/3ez.png

// Cargo.toml:
//
// [package]
// name = "xt"
// version = "0.1.0"
// authors = ["Casey Primozic <[email protected]>"]
//
// [dependencies]
// rand = "0.3"