Skip to main content

Level

Struct Level 

Source
pub struct Level {
Show 16 fields pub id: LevelId, pub title: String, pub kind: LevelKind, pub text: String, pub hints: Vec<String>, pub start: Start, pub optional: bool, pub success: String, pub fixture: Fixture, pub answer: Option<Answer>, pub requirements: Vec<Requirement>, pub allow_empty: bool, pub cd: Option<CdPolicy>, pub on_fd: Option<fn(&Fds) -> bool>, pub resets: Vec<Marker>, pub solution: Option<Solution>,
}
Expand description

A level. Build one with level or intro and chain the methods below.

use shellgame::engine::prelude::*;

let l = level(2, "Čtení souboru")
    .text("Přečtěte si `message.txt`.")
    .start("")
    .hints(["Použijte `cat`.", "Zadejte první slovo."])
    .file("message.txt", "Secret is the key.\n")
    .answer(exact("secret").ignore_case())
    .solution("shellgame submit \"$(cut -d' ' -f1 message.txt)\"");
assert_eq!(l.id.number, 2);

Fields§

§id: LevelId

The stable id. The section part is assigned when the level joins a Section.

§title: String

The title, without the id.

§kind: LevelKind

Regular task or section intro.

§text: String

The assignment, as Markdown. Pages of an intro are separated by \n---\n.

§hints: Vec<String>

Plain-text hints, revealed one at a time. Printed verbatim, never as Markdown.

§start: Start

Where the player is placed when the level starts.

§optional: bool

A bonus level never gates progress.

§success: String

Shown when the level is completed.

§fixture: Fixture

What the level’s files look like (applied after the section’s fixture).

§answer: Option<Answer>

How a submitted answer is judged, if the level takes one.

§requirements: Vec<Requirement>

Conditions that are always checked, before the answer.

§allow_empty: bool

Whether shellgame submit without an answer may complete the level.

§cd: Option<CdPolicy>

The level’s cd policy, if it teaches one movement command.

§on_fd: Option<fn(&Fds) -> bool>

Decides whether the hooked command’s output redirection counts as the drill.

§resets: Vec<Marker>

Extra markers cleared whenever the level is prepared.

§solution: Option<Solution>

A script that completes the level.

Implementations§

Source§

impl Level

Source

pub fn text(self, text: impl Into<String>) -> Self

The assignment text (Markdown).

Source

pub fn hints<I, S>(self, hints: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

The hints, replacing any set before.

Source

pub fn start(self, path: impl Into<String>) -> Self

Place the player in this section-relative directory when the level starts ("" or "." is the section root).

Source

pub fn start_at_workspace(self) -> Self

Place the player at the workspace root, above the section.

Source

pub fn optional(self) -> Self

Mark the level as a bonus: it never gates advancement.

Source

pub fn success(self, message: impl Into<String>) -> Self

The text shown on completion, instead of messages::CORRECT.

Source

pub fn dirs<I, S>(self, paths: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Declare directories; see Fixture::dirs.

Source

pub fn dir(self, path: impl Into<String>) -> Self

Declare a directory; see Fixture::dir.

Source

pub fn file(self, path: impl Into<String>, content: impl Into<Content>) -> Self

Declare a file; see Fixture::file.

Source

pub fn file_mode( self, path: impl Into<String>, content: impl Into<Content>, mode: u32, ) -> Self

Declare a file with an explicit mode; see Fixture::file_mode.

Source

pub fn keep_file( self, path: impl Into<String>, content: impl Into<Content>, ) -> Self

Declare a file that is only written when missing; see Fixture::keep_file.

Source

pub fn dir_mode(self, path: impl Into<String>, mode: u32) -> Self

Declare a directory mode; see Fixture::dir_mode.

Source

pub fn clean<I, S>(self, paths: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Declare paths to remove before anything is created; see Fixture::clean.

Source

pub fn fixture(self, fixture: Fixture) -> Self

Merge a prebuilt or generated fixture into this level’s.

Source

pub fn answer(self, answer: Answer) -> Self

How a submitted answer is judged.

Source

pub fn require(self, requirement: impl Into<Requirement>) -> Self

Add a condition that is always checked, in declaration order, before the answer.

Source

pub fn allow_empty(self) -> Self

Let shellgame submit without an answer complete the level (once the requirements hold).

Source

pub fn cd(self, policy: CdPolicy) -> Self

Give the level a cd policy; see CdPolicy.

Source

pub fn on_fd(self, predicate: fn(&Fds) -> bool) -> Self

Record the level’s fd evidence when this predicate holds for the hooked command’s descriptors; pair it with fd_evidence(..).

Source

pub fn resets<I>(self, markers: I) -> Self
where I: IntoIterator<Item = Marker>,

Markers to clear whenever the level is prepared, in addition to the ones the level already references (evidence, its cd/fd markers, after rules).

Source

pub fn solution(self, script: impl Into<String>) -> Self

A reference solution: a shell script valid in both bash and fish.

Source

pub fn solution_bash(self, script: impl Into<String>) -> Self

A reference solution that needs bash syntax; it is not replayed in fish.

Source

pub fn solution_with(self, generate: fn(&Ctx<'_>) -> String) -> Self

A reference solution generated from the machine (such as a walk down $HOME); the script must be valid in both bash and fish.

Source

pub fn is_intro(&self) -> bool

True for a section intro.

Source

pub fn is_bonus(&self) -> bool

True for a bonus level, which never gates advancement.

Source

pub fn display_title(&self) -> String

The title as shown to the player: "1.4: Návrat na základnu" for a regular level, the bare title for an intro.

Source

pub fn referenced_markers(&self) -> Vec<Marker>

Every marker this level reads or writes, without duplicates: evidence requirements, its own cd marker if it has a policy, its fd marker if it has an on_fd rule, the markers of after rules and the explicit Level::resets.

Source

pub fn prepare( &self, section: &Section, workspace: &Path, ) -> Result<(), FixtureError>

Put the level into its starting state: clear its markers and rebuild its files. Containment is verified first, so nothing is touched below a workspace or section directory that is a symlink.

  1. Every marker the level references is removed, so evidence from an earlier attempt (or an earlier visit) cannot complete it.
  2. The section root is repaired: a file in its place is made removable and deleted, a directory the player locked is made usable. (A symlink is refused. Section 0, whose root is the workspace itself, is never repaired this way.)
  3. The section’s fixture is applied, then the level’s own.

Used for the first visit, for shellgame reset and for jumps; see Fixture::apply for the repair rules that make it work after anything the player may have done.

Source

pub fn validate(&self, ctx: &Ctx<'_>, answer: Option<&str>) -> Check

Judge a submission: the requirements first, in order and unconditionally (the first failure wins), then the answer.

With no answer (None): the level passes if it allows empty submissions or takes no answer, and otherwise fails with the answer’s “required” message. With an answer, it is judged by the answer rule, or accepted when the level has none. On Pass, the session shows Level::success.

Source

pub fn start_dir( &self, workspace: &Path, section_root: &Path, ) -> Option<PathBuf>

The directory the player is placed in when the level starts, if it has one.

Source

pub fn returns_to_start(&self, mv: &CdMove<'_>) -> bool

True when this cd would bring the player back to the level’s start directory.

Strict cd rules always permit the recovery move, so a player can never be locked out of the level’s own workspace. The destination is resolved the way the shell will (CdMove::destination); where it cannot be (an unknown cd -), the answer is no.

Source

pub fn cd_enforcement_lifted(&self, mv: &CdMove<'_>) -> bool

True when a strict cd rule must not block this move: the level’s cd evidence exists (the player has shown the command) or the move returns to the start directory.

Without this, one extra step could leave a player in a directory from which every permitted move leads further away. Lifting waives blocking only; it never grants or denies evidence.

Source

pub fn cd_pre_move(&self, mv: &CdMove<'_>) -> CdDecision

Decide whether a cd about to happen is allowed. Levels without a cd policy allow everything. Printing the red panel and the recovery tip is the UI’s job.

Source

pub fn cd_post_move(&self, mv: &CdMove<'_>)

Record the outcome of a cd that succeeded (evidence, on_move).

Source

pub fn cd_legacy_pre_move(&self, mv: &CdMove<'_>) -> CdDecision

Level::cd_pre_move for a shell started by the Python version of the game, which only reports the move before it happens; see CdPolicy::legacy_pre_move.

Source

pub fn cd_legacy_post_move(&self, ctx: &Ctx<'_>, dest: &Path)

The post-move report of a Python-era shell; see CdPolicy::legacy_post_move.

Source

pub fn record_fd(&self, fds: &Fds, markers: &Markers<'_>) -> Result<bool>

Record the level’s fd evidence if its on_fd rule accepts these descriptors. Returns whether the marker was recorded.

Trait Implementations§

Source§

impl Clone for Level

Source§

fn clone(&self) -> Level

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Level

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Level

§

impl RefUnwindSafe for Level

§

impl Send for Level

§

impl Sync for Level

§

impl Unpin for Level

§

impl UnsafeUnpin for Level

§

impl UnwindSafe for Level

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.