Skip to content

Commit

Permalink
WIP adds 2414
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbrain-za committed Nov 24, 2023
1 parent f1a7f48 commit 9a48692
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "judge"
version = "2.3.2"
version = "2.3.3"
edition = "2021"
authors = ["Philip Barlow"]
description = "Tool for an in house code challenge server"
Expand Down
14 changes: 14 additions & 0 deletions src/generator/2414.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# File handling

## Problem

Given a binary file, do something

Examples:



## Instructions

Design a program/script that can do something with the given file

12 changes: 9 additions & 3 deletions src/generator/challenges.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Generator, G2331, G2332, G2333, G2334, G2411, G2412, G2413};
use super::{Generator, G2331, G2332, G2333, G2334, G2411, G2412, G2413, G2414};
use log::debug;
use std::fmt::Display;

Expand Down Expand Up @@ -69,9 +69,14 @@ impl Challenges {
table: String::from("24_1_3"),
doc: include_str!("2413.md").to_string(),
};

let c2414 = Challenge {
name: String::from("Input validation"),
command: String::from("2414"),
table: String::from("24_1_4"),
doc: include_str!("2414.md").to_string(),
};
Self {
challenges: vec![c2331, c2332, c2333, c2334, c2411, c2412, c2413],
challenges: vec![c2331, c2332, c2333, c2334, c2411, c2412, c2413, c2414],
}
}

Expand All @@ -89,6 +94,7 @@ impl Challenges {
"2411" => Some(Box::new(G2411::new(test))),
"2412" => Some(Box::new(G2412::new(test))),
"2413" => Some(Box::new(G2413::new(test))),
"2414" => Some(Box::new(G2414::new(test))),
_ => None,
}
}
Expand Down
194 changes: 194 additions & 0 deletions src/generator/g2414.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use std::fmt::Display;

use crate::generator::Generator;
use log::{debug, error};
use rand::seq::SliceRandom;
use rand::{thread_rng, Rng};
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::time::Instant;

use super::TestResult;

const TEST_SIZE: usize = 1_000;
const TEST_SAMPLES: usize = 10;
const ATTEMPT_SAMPLES: usize = 100_000;

type TestCase = Vec<u8>;
type Answer = usize;

pub struct G2414 {
pub count: usize,
pub test_cases: Vec<TestCase>,
pub answer: Vec<Answer>,
}

impl Display for G2414 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let json = serde_json::to_string(&self.test_cases).unwrap();
write!(f, "{}", json)
}
}

impl G2414 {
pub fn new(test: bool) -> Self {
let count = match test {
true => TEST_SAMPLES,
false => ATTEMPT_SAMPLES,
};
let mut s = Self {
count,
test_cases: Vec::new(),
answer: Vec::new(),
};
s.regenerate();
s
}

fn print_test_case(test_case: &TestCase) -> String {
let mut s = String::new();
for (i, n) in test_case.iter().enumerate() {
if i == test_case.len() - 1 {
s.push_str(&format!("{}\n", n));
} else {
s.push_str(&format!("{},", n));
}
}
s
}
}

impl Generator for G2414 {
fn get_test_cases(&self) -> String {
serde_json::to_string(&self.test_cases).unwrap()
}

fn regenerate(&mut self) {
let mut rng = thread_rng();
self.test_cases = Vec::new();

while self.test_cases.len() < self.count {
let mut test_case: TestCase = Vec::new();
let mut random;
for _ in 0..TEST_SIZE {
random = rng.gen_range(0..255);
test_case.push(random);
}

//TODO!

test_case.shuffle(&mut thread_rng());

self.test_cases.push(test_case);
}
debug!("answer: {:?}", self.answer);
}

fn save_to_file(&self, filename: &str) -> std::io::Result<()> {
use std::fs::File;
use std::io::prelude::*;
let mut file = File::create(filename)?;
file.write_all(self.to_string().as_bytes())?;
Ok(())
}

fn check_answer(&self, data: &str) -> Result<bool, Box<dyn std::error::Error>> {
let result: Vec<Answer> = serde_json::from_str(data).expect("JSON was not well-formatted");
if self.answer == result {
Ok(true)
} else {
debug!("expected: {:?}", self.answer);
debug!("received: {:?}", result);
Ok(false)
}
}

fn setup(&mut self) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run(&self, test: TestResult) -> Result<TestResult, Box<dyn std::error::Error>> {
if let TestResult::Success(score) = test {
let mut score = score;
let mut spinner = cliclack::spinner();
spinner.start("Preparing tests");

let mut answers: Vec<String> = Vec::new();

/* prep the test cases */
let mut tests: Vec<TestCase> = Vec::new();
for test in &self.test_cases {
let case = Self::print_test_case(test).clone().as_bytes().to_vec();
tests.push(case);
}

/* start the child process */
let mut child = Command::new(&score.command)
.stdout(Stdio::piped())
.stdin(Stdio::piped())
.spawn()
.unwrap();

let mut stdin = child.stdin.take().unwrap();
let mut stdout = child.stdout.take().unwrap();

spinner.stop("Running tests...");
/* Run the test */
let start = Instant::now();
for test in tests {
let _ = stdin.write_all(&test);
let mut buf = [0u8; 5];
let rx_count = stdout.read(&mut buf).unwrap();

if 2 > rx_count {
return Ok(TestResult::Fail(String::from(
"Your program sent back too few characters. Did you forget the newline?",
)));
}

let buf = String::from_utf8(buf.to_vec())?;
let buf = buf.trim_matches(char::from(0)).trim();
match buf.parse::<u32>() {
Ok(n) => {
answers.push(n.to_string());
}
Err(e) => {
error!("Error parsing output: {}", buf);
return Ok(TestResult::Fail(format!(
"Your program did not produce the correct result: {e}"
)));
}
}
}
let elapsed = start.elapsed().as_nanos();
let _ = stdin.write_all("q\n".as_bytes());
spinner.stop("Tests Complete");
/* End of test run */

let result = if elapsed > u64::MAX as u128 {
TestResult::Fail(String::from("Your program is way too slow"))
} else {
score.time_ns = elapsed as f64;

let mut answers_json = String::from("[");
for (i, answer) in answers.iter().enumerate() {
answers_json.push_str(answer);
if i != answers.len() - 1 {
answers_json.push_str(", ");
}
}
answers_json.push(']');

match self.check_answer(&answers_json)? {
false => TestResult::Fail(String::from(
"Your program did not produce the correct result",
)),
true => TestResult::Success(score),
}
};
Ok(result)
} else {
Err("Please start with a success variant".into())
}
}
}
2 changes: 2 additions & 0 deletions src/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod g2412;
pub use g2412::G2412;
mod g2413;
pub use g2413::G2413;
mod g2414;
pub use g2414::G2414;

pub mod challenges;
mod test_result;
Expand Down

0 comments on commit 9a48692

Please sign in to comment.