<commit_before>#![feature(iterator_step_by)]

extern crate easy_hash;

use easy_hash::{Sha256, Hasher, HashResult};
use std::thread;
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};

const BASE: usize = 42;
const THREADS: usize = 4;
static DIFFICULTY: &'static str = "000000";

struct Solution(usize, String);

fn verify_number(number: usize) -> Option<Solution> {
    let hash: String = Sha256::hash((number * BASE).to_string().as_bytes()).hex();
    if hash.ends_with(DIFFICULTY) {
        Some(Solution(number, hash))
    } else {
        None
    }
}

fn search_for_solution(start_at: usize, sender: mpsc::Sender<Solution>, is_solution_found: Arc<AtomicBool>) {
    let mut iteration_no = 0;
    for number in (start_at..).step_by(THREADS) {
        if let Some(solution) = verify_number(number) {
            is_solution_found.store(true, Ordering::Relaxed);
            match sender.send(solution) {
                Ok(_)  => {},
                Err(_) => println!("Receiver has stopped listening, dropping worker number {}.", start_at),
            }
            break;
        } else if iteration_no % 1000 == 0 && is_solution_found.load(Ordering::Relaxed) {
            break;
        }
        iteration_no += 1;
    }
}

fn main() {
    println!("Attempting to find a number, which - while multiplied by {} and hashed using SHA-256 - will result in a hash ending with {}.", BASE, DIFFICULTY);
    println!("Please wait...");

    let is_solution_found = Arc::new(AtomicBool::new(false));
    let (sender, receiver) = mpsc::channel();
    
    /*
     * Here, we have 4 threads (as specified by the value of THREADS constant).
     * Thread 1 will start at number 1 and check 5, 9,  13 and so on.
     * Thread 2 will start at number 2 and check 6, 10, 14 and so on.
     * Thread 3 will start at number 3 and check 7, 11, 15 and so on.
     * Thread 4 will start at number 4 and check 8, 12, 16 and so on.
     * 
     * This way, we have 4 parallel threads of execution and we're sure
     * that each number will be examined exactly once.
     */
    for i in 1..THREADS+1 {
        let sender_n = sender.clone();
        let is_solution_found = is_solution_found.clone();
        thread::spawn(move || {
            search_for_solution(i, sender_n, is_solution_found);
        });
    }

    /*
     * In a loop, receive messages from the producers.
     * As long as there is no solution found (None is received),
     * spin the loop. When the message with a solution arrives
     * (Some(Solution(i, hash))), print out the result and break
     * out from the loop.
     * 
     * Note that breaking out from the loop drops the receiver,
     * so that producers will receive an Err(_) on a next attempt to
     * send a message. This way, producers will "know" that the solution
     * was found by one of the worker threads and the receiver does no
     * longer "listen", so they can stop their work too.
     */
    loop {
        match receiver.recv() {
            Ok(Solution(i, hash)) => {
                println!("Found the solution.");
                println!("The number is: {}.", i);
                println!("Result hash: {}.", hash);
                break;
            },
            Err(_) => panic!("Worker threads disconnected before the solution was found!"),
        }
    }
}<commit_msg>gets rid of the needless loop<commit_after>#![feature(iterator_step_by)]

extern crate easy_hash;

use easy_hash::{Sha256, Hasher, HashResult};
use std::thread;
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};

const BASE: usize = 42;
const THREADS: usize = 4;
static DIFFICULTY: &'static str = "000000";

struct Solution(usize, String);

fn verify_number(number: usize) -> Option<Solution> {
    let hash: String = Sha256::hash((number * BASE).to_string().as_bytes()).hex();
    if hash.ends_with(DIFFICULTY) {
        Some(Solution(number, hash))
    } else {
        None
    }
}

fn search_for_solution(start_at: usize, sender: mpsc::Sender<Solution>, is_solution_found: Arc<AtomicBool>) {
    let mut iteration_no = 0;
    for number in (start_at..).step_by(THREADS) {
        if let Some(solution) = verify_number(number) {
            is_solution_found.store(true, Ordering::Relaxed);
            match sender.send(solution) {
                Ok(_)  => {},
                Err(_) => println!("Receiver has stopped listening, dropping worker number {}.", start_at),
            }
            break;
        } else if iteration_no % 1000 == 0 && is_solution_found.load(Ordering::Relaxed) {
            break;
        }
        iteration_no += 1;
    }
}

fn main() {
    println!("Attempting to find a number, which - while multiplied by {} and hashed using SHA-256 - will result in a hash ending with {}.", BASE, DIFFICULTY);
    println!("Please wait...");

    let is_solution_found = Arc::new(AtomicBool::new(false));
    let (sender, receiver) = mpsc::channel();
    
    /*
     * Here, we have 4 threads (as specified by the value of THREADS constant).
     * Thread 1 will start at number 1 and check 5, 9,  13 and so on.
     * Thread 2 will start at number 2 and check 6, 10, 14 and so on.
     * Thread 3 will start at number 3 and check 7, 11, 15 and so on.
     * Thread 4 will start at number 4 and check 8, 12, 16 and so on.
     * 
     * This way, we have 4 parallel threads of execution and we're sure
     * that each number will be examined exactly once.
     */
    for i in 1..THREADS+1 {
        let sender_n = sender.clone();
        let is_solution_found = is_solution_found.clone();
        thread::spawn(move || {
            search_for_solution(i, sender_n, is_solution_found);
        });
    }
    
    match receiver.recv() {
        Ok(Solution(i, hash)) => {
            println!("Found the solution.");
            println!("The number is: {}.", i);
            println!("Result hash: {}.", hash);
        },
        Err(_) => panic!("Worker threads disconnected before the solution was found!"),
    }
}
{'fraction_non_alphanumeric': 0.12124231855173559, 'fraction_numerical': 0.018601561202458063, 'mean_word_length': 2.5528023598820058, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3651702', 'n_tokens_mistral': 1944, 'n_tokens_neox': 1799, 'n_words': 609}