Skip to content

Commit

Permalink
Added functionality to specify inputs to terry-statement tool
Browse files Browse the repository at this point in the history
  • Loading branch information
franv314 committed Dec 25, 2024
1 parent d4ad47c commit a1dfd66
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ ratatui = { workspace = true, features = ["termion"] }

# Typescript definition generation
typescript-definitions = { workspace = true }
serde_yaml.workspace = true

[dev-dependencies]
approx = { workspace = true }
Expand Down
69 changes: 56 additions & 13 deletions src/tools/terry_statement.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
use std::fs;
use std::path::PathBuf;

use anyhow::{anyhow, Context, Error};
use clap::Parser;
use serde::{Deserialize, Serialize};

use crate::LoggerOpt;
use task_maker_format::terry::{StatementSubtask, TerryTask};
use task_maker_format::terry::TerryTask;
use task_maker_format::{find_task, EvaluationConfig};

#[derive(Parser, Debug, Clone)]
pub struct TerryStatementOpt {
/// Path to statement template (uses task directory structure if omitted)
#[clap(long = "statement-path", short = 's')]
pub statement_path: Option<String>,

/// Path to subtasks files (none if omitted)
#[clap(long = "subtasks-path", short = 't')]
pub subtasks_path: Option<String>,

/// Path to store output statement (stdout if omitted)
#[clap(long = "output-path", short = 'o')]
pub output_path: Option<String>,

/// Look at most for this number of parents for searching the task
#[clap(long = "max-depth", default_value = "3")]
pub max_depth: u32,
}

/// A subtask has a maximum score and a list of testcases
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatementSubtask {
/// The maximum score on the subtask
pub max_score: f64,
/// The additional constraints, as seen by the contestant
pub constraints: String,
/// The testcases in the subtask
pub testcases: Vec<usize>,
}

pub fn main_terry_statement(opt: TerryStatementOpt, _logger_opt: LoggerOpt) -> Result<(), Error> {
let eval_config = EvaluationConfig {
solution_filter: vec![],
Expand All @@ -25,29 +50,47 @@ pub fn main_terry_statement(opt: TerryStatementOpt, _logger_opt: LoggerOpt) -> R
dry_run: false,
};

let task = find_task(None, opt.max_depth, &eval_config)?;
let path = task.path();
let task = TerryTask::new(path, &eval_config)
.with_context(|| format!("There is not Terry task at {}", path.display()))?;
let (statement_path, subtasks_path, output_path) =
if let Some(statement_path) = opt.statement_path {
(
PathBuf::from(statement_path),
opt.subtasks_path.map(PathBuf::from),
opt.output_path.map(PathBuf::from),
)
} else {
let task = find_task(None, opt.max_depth, &eval_config)?;
let path = task.path();
let task = TerryTask::new(path, &eval_config)
.with_context(|| format!("There is no Terry task at {}", path.display()))?;

let Some(statement) = task.statement else {
return Ok(());
};
let Some(statement) = task.statement else {
return Ok(());
};

let content = fs::read_to_string(statement.path)?;
(
statement.path,
statement.subtasks,
Some(path.join("statement/statement.md")),
)
};

let content = fs::read_to_string(statement_path)?;

let new_content = if content.contains("<subtasks-recap/>") {
let subtasks = statement
.subtasks
.ok_or(anyhow!("No subtasks.yaml file."))?;
let subtasks_path = subtasks_path.ok_or(anyhow!("No subtasks.yaml file."))?;
let subtasks_content = fs::read_to_string(subtasks_path)?;
let subtasks: Vec<_> = serde_yaml::from_str(&subtasks_content)?;
let subtasks = generate_md_table(&subtasks);

content.replace("<subtasks-recap/>", &subtasks)
} else {
content
};

fs::write(path.join("statement/statement.md"), new_content)?;
match output_path {
Some(output_file) => fs::write(output_file, new_content)?,
None => print!("{}", new_content),
}

Ok(())
}
Expand Down
31 changes: 9 additions & 22 deletions task-maker-format/src/terry/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use std::fs;
use std::path::Path;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context, Error};
use anyhow::{anyhow, bail, Error};
use serde::{Deserialize, Serialize};

use crate::terry::dag::{Checker, InputGenerator, InputValidator};
use crate::terry::sanity_checks::get_sanity_checks;
use crate::terry::{Statement, TerryTask};
use crate::terry::statement::Statement;
use crate::terry::TerryTask;
use crate::{find_source_file, EvaluationConfig, SourceFile, WriteBinTo};

lazy_static! {
Expand Down Expand Up @@ -73,27 +74,13 @@ fn get_statement_template(task_dir: &Path) -> Result<Option<Statement>, Error> {
}

let subtasks_path = task_dir.join("managers/subtasks.yaml");
let subtasks = if subtasks_path.exists() {
Some(subtasks_path)
} else {
None
};

if !subtasks_path.exists() {
return Ok(Some(Statement {
path,
subtasks: None,
}));
}

let subtasks =
serde_yaml::from_str(&fs::read_to_string(&subtasks_path).with_context(|| {
format!(
"While trying to read subtasks at {}",
subtasks_path.display()
)
})?)
.context("While trying to decode subtasks")?;

Ok(Some(Statement {
path,
subtasks: Some(subtasks),
}))
Ok(Some(Statement { path, subtasks }))
}

/// Search the specified manager in the managers/ folder of the task, returning the `SourceFile` if
Expand Down
22 changes: 2 additions & 20 deletions task-maker-format/src/terry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::solution::SolutionInfo;
use crate::terry::curses_ui::CursesUI;
use crate::terry::dag::{Checker, InputGenerator, InputValidator, Solution};
use crate::terry::format::parse_task;
use crate::terry::statement::Statement;
use crate::terry::ui_state::UIState;
use crate::ui::{JsonUI, PrintUI, RawUI, SilentUI, UIMessage, UIType, UI};
use crate::{list_files, EvaluationConfig, EvaluationData, SourceFile, TaskInfo, UISender};
Expand All @@ -25,6 +26,7 @@ mod dag;
pub(crate) mod finish_ui;
mod format;
pub(crate) mod sanity_checks;
pub(crate) mod statement;
pub(crate) mod task_info;
pub(crate) mod ui_state;

Expand Down Expand Up @@ -144,26 +146,6 @@ pub struct Subtask {
testcases: Vec<usize>,
}

/// A subtask has a maximum score and a list of testcases
#[derive(Debug, Clone, Serialize, Deserialize, TypeScriptify)]
pub struct StatementSubtask {
/// The maximum score on the subtask
pub max_score: f64,
/// The additional constraints, as seen by the contestant
pub constraints: String,
/// The testcases in the subtask
pub testcases: Vec<usize>,
}

/// A statement is a markdown template together with subtasks data
#[derive(Debug, Clone, Serialize, Deserialize, TypeScriptify)]
pub struct Statement {
/// The content of the statement template
pub path: PathBuf,
/// The subtasks if they exist
pub subtasks: Option<Vec<StatementSubtask>>,
}

impl TerryTask {
/// Try to make a `Task` from the specified path. Will return `Err` if the format of the task
/// is not Terry or if the task is corrupted and cannot be parsed.
Expand Down
12 changes: 12 additions & 0 deletions task-maker-format/src/terry/statement/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use typescript_definitions::TypeScriptify;

/// A statement is a markdown template together with subtasks data
#[derive(Debug, Clone, Serialize, Deserialize, TypeScriptify)]
pub struct Statement {
/// The path of the statement template
pub path: PathBuf,
/// The subtasks if they exist
pub subtasks: Option<PathBuf>,
}

0 comments on commit a1dfd66

Please sign in to comment.