#[non_exhaustive]pub enum FileFormat {
SokobanSLC,
Xsb,
Txt,
Hsb,
Tsb,
SokobanYASC,
Json,
}Expand description
All supported Sokoban file formats.
Depending on file format, following restrictions apply:
| File extension | restrictions |
|---|---|
.sok | Any Tessellation puzzles, allows mixing different Tessellation in the same file |
.hsb | Only Hexoban puzzles |
.tsb | Only Trioban puzzles |
.xsb | Only Sokoban puzzles |
.txt | Only Sokoban puzzles |
.slc | Only Sokoban puzzles |
.json | Any Tessellation puzzles, allows mixing different Tessellation in the same file |
If file format restricts Tessellation of Puzzle in it, sokoban_elements
will:
- refuse to save
Puzzleof differentTessellationinto these files - assume exact
TessellationforPuzzleloaded from these files
If file format doesn’t restrict Tessellation of Puzzle in it,
sokoban_elements will allow and implement it too.
§Todo
- make writing of metadata optional
- make writer for individual Puzzles
- with optional metadata
- with optional saved games
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
SokobanSLC
XML format associated with Sokoban for Windows.
Files typically end with .slc extension.
This is lossy format:
- it doesn’t support writing any tessellation except
Sokoban - it doesn’t support writing
Sokoban+, saved games, notes, etc… Collectionwriter reports error if trying to writePuzzlethat is notSokoban, but it silently skips writing unsupported data for supported tessellation.
Xsb
XSokoban file format.
Files typically end with .xsb extension.
This is lossy format:
- it doesn’t support writing any tessellation except
Sokoban - it doesn’t support writing
Sokoban+, saved games, notes, etc… Collectionwriter reports error if trying to writePuzzlethat is notSokoban, but it silently skips writing unsupported data for supported tessellation!
Txt
Same as FileFormat::Xsb, different file extension.
Files typically end with .txt extension.
This is lossy format:
- it doesn’t support writing any tessellation except
Sokoban - it doesn’t support writing
Sokoban+, saved games, notes, etc… Collectionwriter reports error if trying to writePuzzlethat is notSokoban, but it silently skips writing unsupported data for supported tessellation!
Hsb
File format base on Xsb but for Hexoban
puzzles.
Files typically end with .hsb
This is lossy format:
- it doesn’t support writing any tessellation except
Hexoban - it doesn’t support writing
Sokoban+, saved games, notes, etc… Collectionwriter reports error if trying to writePuzzlethat is notHexoban, but it silently skips writing unsupported data for supported tessellation!
Tsb
File format base on Xsb but for Trioban
puzzles.
Files typically end with .tsb
This is lossy format:
- it doesn’t support writing any tessellation except
Trioban - it doesn’t support writing
Sokoban+, saved games, notes, etc… Collectionwriter reports error if trying to writePuzzlethat is notTrioban, but it silently skips writing unsupported data for supported tessellation.
SokobanYASC
Plain text format defined by SokobanYASC.
Files typically end with .sok extension.
This is most versatile file format because it supports saving complete Collection,
Puzzle and SavedGame info along with
Sokoban+, differing Tessellations in the same file, author
and similar metadata etc..
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Sokoban (c) by Falcon Co., Ltd., Japan ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: File Format 0.17 ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: ::
:: File Notes Optional ::
:: Puzzle 1 Required ::
:: Title Optional* ::
:: Board See legend ::
:: Puzzle Notes Optional ::
:: Saved Game or Solution 1 Optional ::
:: Title Optional* ::
:: Moves See legend ::
:: Notes Optional ::
:: Saved Game or Solution 2 Optional ::
:: ... (more saved games and solutions) ::
:: Puzzle 2 Optional ::
:: ... (more puzzles) ::
:: ::
:: Remarks: ::
:: ::
:: File Notes ::
:: File notes consist of unstructured text and ::
:: key/value properties, such as "Author: Name". Lines ::
:: beginning with "::" are comments meant to be read ::
:: only by a person examining the file in a text ::
:: editor, and should not be displayed by the Sokoban ::
:: program. ::
:: ::
:: The optional but recommended property ::
:: "Collection: Name" assigns a name to the puzzle ::
:: collection. When a collection is copied from the ::
:: internet, for example, and pasted into a Sokoban ::
:: program, this information allows the collection to ::
:: be saved with the proper name. ::
:: ::
:: Titles ::
:: A title line is the last non-blank text line before ::
:: a board, a saved game, or a solution, provided the ::
:: line is preceded by a blank line or it is the only ::
:: text line at this position in the file. ::
:: ::
:: Title lines are optional unless a single or a last ::
:: text line from a preceding puzzle, saved game, ::
:: solution, or file header can be mistaken for a title ::
:: line. ::
:: ::
:: Puzzle Notes ::
:: Two special key/value pairs are supported in puzzle ::
:: notes: "Title" and "Author", hence, titles can ::
:: either come from a title line or from a key/value ::
:: pair. ::
:: ::
::::::::::::::::::::::::::: Board ::::::::::::::::::::::::::
:: Legend.................: :.................Legend ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Wall...................: # # :...................Wall ::
:: Pusher.................: p @ :.................Pusher ::
:: Pusher on goal square..: P + :..Pusher on goal square ::
:: Box....................: b $ :....................Box ::
:: Box on goal square.....: B * :.....Box on goal square ::
:: Goal square............: . . :............Goal square ::
:: Floor..................: :..................Floor ::
:: Floor..................: - _ :..................Floor ::
:: ::
:: Remarks: ::
:: ::
:: The first and the last non-empty square in each row ::
:: must be a wall or a box on a goal. An empty interior ::
:: row is written with at least one "-" or "_". ::
:: ::
:: Boards may be run-length encoded (RLE), e.g., ::
:: "###----p.#" may be encoded as "3#4-p.#", and ::
:: "#-#-#-##-#-#-#" may be encoded as "2(3(#-)#)". ::
:: A row cannot be split over multiple lines. ::
:: ::
:: Rows may be combined on a single line by using "|" ::
:: as a row separator, e.g., "--3#|3#-#|#pb.#|5#". ::
:: A "|" at the end of a line is optional and may be ::
:: omitted. ::
:: ::
::::::::::::::::::::::::::: Moves ::::::::::::::::::::::::::
:: Legend.................: :.................Legend ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Move pusher up.........: u U :.......Push/pull box up ::
:: Move pusher down.......: d D :.....Push/pull box down ::
:: Move pusher left.......: l L :.....Push/pull box left ::
:: Move pusher right......: r R :....Push/pull box right ::
:: Begin jump.............: [ ] :...............End jump ::
:: Begin pusher change....: { } :......End pusher change ::
:: Current position.......: * * :.......Current position ::
:: ::
:: Remarks: ::
:: ::
:: Moves may be run-length encoded, e.g., "3r4U" means ::
:: "rrrUUUU", and "2(3(dr)R)" means "drdrdrRdrdrdrR". ::
:: Each line must, however, have at least one proper ::
:: non-digit character. Spaces between moves are ::
:: allowed. ::
:: ::
:: Jumps and pulls: Only in reverse mode saved games ::
:: and solutions. ::
:: ::
:: Reverse mode saved games and solutions must begin ::
:: with a jump, even if it is empty. An example: ::
:: "[]U[rr]d". ::
:: ::
:: Pusher changes: Only in puzzles with multiple ::
:: pushers, e.g., Multiban. Moves inside the braces ::
:: depict the relative movement to get from the ::
:: currently active pusher to the next active pusher. ::
:: At game start, a "{...}" sequence activates the ::
:: pusher relative to the top-left pusher. An example: ::
:: "{rddd}Urr{uul}uLU". If the top-left pusher is the ::
:: first active pusher, then the empty "{}" can be ::
:: omitted. ::
:: ::
:: The current position is optional and defaults to the ::
:: position after the last move. ::
:: ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Json
JSON serialized Collection, available with the json cargo feature.
Files typically end with .json extension.
The document is exactly what serde_json produces for a Collection - there is no
envelope and no version field - written pretty printed. Like
SokobanYASC it is lossless and unrestricted: it stores complete
Collection, Puzzle and SavedGame data along
with Sokoban+, and it allows mixing Tessellations in one
file. See the # Serde sections of those types for the shape of each.
Unlike the other formats, this one has no options:
WriterSettings::print_visible_floor,WriterSettings::rle_encodeandWriterSettings::wrap_savegame_lines_atare ignored.print_visible_floorhas to be: boards are always serialized with visible floors, because trimming them loses board width.ReaderSettings::legacy_sokoban_plusis ignored.Sokoban+is stored as typed arrays rather than as text, so it has no99marker to reinterpret.
Two reading quirks are worth knowing:
- A board or saved game that fails to parse is reported as
JsonSyntaxError, not asBoardSyntaxError, becauseserdeflattens the underlying error into a message. To tell malformed JSON apart from JSON this crate’s types rejected, downcastError::sourcetoserde_json::Errorand inspect itsclassify(). - Every field of
Collectionis optional, so any JSON object at all reads as a valid - possibly empty - collection. That is not specific to this format: a.sokfile with no board in it also reads as an empty collection.
Implementations§
Source§impl FileFormat
impl FileFormat
Sourcepub fn file_extension(&self) -> &str
pub fn file_extension(&self) -> &str
File extension for given file format.
Sourcepub fn restricted_to_tessellation(&self) -> Option<Tessellation>
pub fn restricted_to_tessellation(&self) -> Option<Tessellation>
Some if file format restricts allowed Tessellation, otherwise None.
Sourcepub fn from_file_extension(path: impl AsRef<Path>) -> Option<Self>
pub fn from_file_extension(path: impl AsRef<Path>) -> Option<Self>
Some if there exists a FileFormat for file extension from path, otherwise
None.
Sourcepub fn read<R>(
src: &mut R,
settings: ReaderSettings,
) -> Result<Collection, IoReadError>
pub fn read<R>( src: &mut R, settings: ReaderSettings, ) -> Result<Collection, IoReadError>
Loads Collection.
⚠️ Expects source is UTF-8 encoded, but doesn’t validate that expectation.
§Examples
Reading from file:
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use sokoban_elements::*;
let path = Path::new("Original and Extra.sok");
let mut reader = BufReader::new(File::open(path)?);
let settings = ReaderSettings::default();
let collection = FileFormat::read(&mut reader, settings)?;Reading from in-memory string:
use std::io::Cursor;
use sokoban_elements::*;
let mut settings = ReaderSettings::default();
settings.file_format = FileFormat::Xsb;
let data: String = "sokoban collection data read from elsewhere...".to_string();
let mut reader = Cursor::new(data.as_bytes());
let collection = FileFormat::read(&mut reader, settings)?;
let puzzle = &collection.puzzles[0];Sourcepub fn read_from_path(
src_file_path: impl AsRef<Path>,
settings: Option<ReaderSettings>,
) -> Result<Collection, IoReadError>
pub fn read_from_path( src_file_path: impl AsRef<Path>, settings: Option<ReaderSettings>, ) -> Result<Collection, IoReadError>
Loads Collection from file.
⚠️ ReaderSettings::file_format is ignored and is instead constructed from
src_file_path.
Sourcepub fn write<W>(
dest: &mut W,
collection: &Collection,
settings: WriterSettings,
) -> Result<(), IoWriteError>where
W: Write,
pub fn write<W>(
dest: &mut W,
collection: &Collection,
settings: WriterSettings,
) -> Result<(), IoWriteError>where
W: Write,
Writes Collection.
Assumes dest is not buffered.
§Examples
Write collection to file:
use std::fs::File;
use std::path::Path;
use sokoban_elements::*;
let collection = Collection::new();
let settings = WriterSettings::default();
let file_with_extension =
format!("Original and Extra.{}", settings.file_format.file_extension());
let path = Path::new(&file_with_extension);
let mut file = File::create(path)?;
FileFormat::write(&mut file, &collection, settings)?;Write collection to in-memory string:
use std::io::Cursor;
use sokoban_elements::*;
let collection = Collection::new();
let settings = WriterSettings::default();
let mut bytes: Vec<u8> = Vec::new();
let mut writer = Cursor::new(&mut bytes);
FileFormat::write(&mut writer, &collection, settings)?;
let collection_text = String::from_utf8(bytes).unwrap();Write collection to stdout
use sokoban_elements::*;
let collection = Collection::new();
let settings = WriterSettings::default();
let mut stdout = std::io::stdout();
FileFormat::write(&mut stdout, &collection, settings)?;Sourcepub fn save_to_file(
&self,
collection: &Collection,
dest_file_path: impl AsRef<Path>,
settings: Option<WriterSettings>,
) -> Result<(), IoWriteError>
pub fn save_to_file( &self, collection: &Collection, dest_file_path: impl AsRef<Path>, settings: Option<WriterSettings>, ) -> Result<(), IoWriteError>
Writes Collection to file.
⚠️ WriterSettings::file_format is ignored and is instead constructed from
dest_file_path.
Trait Implementations§
Source§impl Clone for FileFormat
impl Clone for FileFormat
impl Copy for FileFormat
Source§impl Debug for FileFormat
impl Debug for FileFormat
Source§impl<'de> Deserialize<'de> for FileFormat
impl<'de> Deserialize<'de> for FileFormat
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for FileFormat
Source§impl Hash for FileFormat
impl Hash for FileFormat
Source§impl PartialEq for FileFormat
impl PartialEq for FileFormat
Source§impl Serialize for FileFormat
impl Serialize for FileFormat
impl StructuralPartialEq for FileFormat
Auto Trait Implementations§
impl Freeze for FileFormat
impl RefUnwindSafe for FileFormat
impl Send for FileFormat
impl Sync for FileFormat
impl Unpin for FileFormat
impl UnsafeUnpin for FileFormat
impl UnwindSafe for FileFormat
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.