initial
This commit is contained in:
commit
a99622cf92
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "bitsy_parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Max Bradbury <max@tinybird.info>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,36 @@
|
||||||
|
# bitsy_parser
|
||||||
|
|
||||||
|
a library for parsing Bitsy game data.
|
||||||
|
|
||||||
|
## done
|
||||||
|
|
||||||
|
### functions
|
||||||
|
|
||||||
|
* colour from
|
||||||
|
* colour to
|
||||||
|
* palette from
|
||||||
|
* palette to
|
||||||
|
* image from
|
||||||
|
* image to
|
||||||
|
|
||||||
|
## todo
|
||||||
|
|
||||||
|
### functions
|
||||||
|
* tile from
|
||||||
|
* tile to
|
||||||
|
* sprite from
|
||||||
|
* sprite to
|
||||||
|
* item from
|
||||||
|
* item to
|
||||||
|
* room from
|
||||||
|
* room to
|
||||||
|
* dialogue from
|
||||||
|
* dialogue to
|
||||||
|
* variable from
|
||||||
|
* variable to
|
||||||
|
* ending from
|
||||||
|
* ending to
|
||||||
|
* game from
|
||||||
|
* game to
|
||||||
|
|
||||||
|
###
|
|
@ -0,0 +1,348 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
struct Colour {
|
||||||
|
red: u8,
|
||||||
|
green: u8,
|
||||||
|
blue: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
struct Palette {
|
||||||
|
id: String, // base36 string (why??)
|
||||||
|
name: Option<String>,
|
||||||
|
colours: Vec<Colour>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
struct Image {
|
||||||
|
pixels: Vec<bool>, // 64 for SD, 256 for HD
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
struct Tile {
|
||||||
|
id: String, // base36 string
|
||||||
|
name: Option<String>,
|
||||||
|
wall: bool,
|
||||||
|
animation_frames: Vec<Image>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct Game {
|
||||||
|
name: String,
|
||||||
|
version: f64,
|
||||||
|
room_format: bool,
|
||||||
|
palettes: Vec<Palette>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Colour {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Colour")
|
||||||
|
.field("red", &self.red)
|
||||||
|
.field("green", &self.green)
|
||||||
|
.field("blue", &self.blue)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Palette {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Palette")
|
||||||
|
.field("id", &self.id)
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("colours", &self.colours)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Image {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Image")
|
||||||
|
.field("pixels", &self.pixels)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Tile {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Tile")
|
||||||
|
.field("id", &self.id)
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("wall", &self.wall)
|
||||||
|
.field("animation_frames", &self.animation_frames)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image_from_string(string: String) -> Image {
|
||||||
|
let string = string.replace("\n", "");
|
||||||
|
let pixels: Vec<&str> = string.split("").collect();
|
||||||
|
// the above seems to add an extra "" at the start and end of the vec, so strip them below
|
||||||
|
let pixels: Vec<bool> = pixels[1..(pixels.len() - 1)].iter().map(|&char| {char == "1"}).collect();
|
||||||
|
|
||||||
|
Image { pixels }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image_to_string(image: Image) -> String {
|
||||||
|
let mut string = String::new();
|
||||||
|
|
||||||
|
for line in image.pixels.chunks(8) {
|
||||||
|
for pixel in line {
|
||||||
|
string.push(if *pixel {'1'} else {'0'});
|
||||||
|
}
|
||||||
|
string.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
string.pop(); // remove trailing newline
|
||||||
|
|
||||||
|
string
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_image_from_string() {
|
||||||
|
let output = image_from_string(
|
||||||
|
"11111111\n11001111\n10111111\n11111111\n11111111\n11111111\n11111111\n11111111".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = Image {
|
||||||
|
pixels: vec![
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
true,true,false,false,true,true,true,true,
|
||||||
|
true,false,true,true,true,true,true,true,
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
true,true,true,true,true,true,true,true,
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(output, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_image_to_string() {
|
||||||
|
let output = image_to_string(Image {
|
||||||
|
pixels: vec![
|
||||||
|
true,false,true,false,true,false,true,false,
|
||||||
|
false,true,false,true,false,true,false,true,
|
||||||
|
true,false,true,false,true,false,true,false,
|
||||||
|
false,true,false,true,false,true,false,true,
|
||||||
|
true,false,true,false,true,false,true,false,
|
||||||
|
false,true,false,true,false,true,false,true,
|
||||||
|
true,false,true,false,true,false,true,false,
|
||||||
|
false,true,false,true,false,true,false,true,
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
let expected = "10101010\n01010101\n10101010\n01010101\n10101010\n01010101\n10101010\n01010101".to_string();
|
||||||
|
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tile_from_string(string: String) -> Tile {
|
||||||
|
let mut lines: Vec<&str> = string.split("\n").collect();
|
||||||
|
|
||||||
|
let id = lines[0].replace("TIL ", "");
|
||||||
|
|
||||||
|
let last_line = lines.pop().unwrap();
|
||||||
|
let wall = match last_line == "WAL true" {
|
||||||
|
true => true,
|
||||||
|
false => {
|
||||||
|
lines.push(last_line);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_line = lines.pop().unwrap();
|
||||||
|
let name = match last_line.starts_with("NAME") {
|
||||||
|
true => Some(last_line.replace("NAME ", "").to_string()),
|
||||||
|
false => {
|
||||||
|
lines.push(last_line);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let animation_frames = lines[1..].join("");
|
||||||
|
let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect();
|
||||||
|
let animation_frames: Vec<Image> = animation_frames.iter().map(|&frame| {
|
||||||
|
image_from_string(frame.to_string())
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
Tile {id, name, wall, animation_frames}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tile_from_string() {
|
||||||
|
let output = tile_from_string("TIL z\n11111111\n11111111\n11111111\n11111111\n11111111\n11111111\n11111111\n11111111\nNAME concrete 1\nWAL true".to_string());
|
||||||
|
|
||||||
|
let expected = Tile {
|
||||||
|
id: "z".to_string(),
|
||||||
|
name: Some("concrete 1".to_string()),
|
||||||
|
wall: true,
|
||||||
|
animation_frames: vec![
|
||||||
|
Image {
|
||||||
|
pixels: vec![true; 64]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tile_to_string(tile: Tile) -> String {
|
||||||
|
let mut animation_frames = String::new();
|
||||||
|
|
||||||
|
for (i, frame) in tile.animation_frames.into_iter().enumerate() {
|
||||||
|
animation_frames.push_str(&image_to_string(frame));
|
||||||
|
|
||||||
|
if i < animation_frames.len() - 1 {
|
||||||
|
animation_frames.push_str(&"\n>\n".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"TIL {}\n{}{}{}",
|
||||||
|
tile.id,
|
||||||
|
animation_frames,
|
||||||
|
if tile.name.is_some() {format!("\nNAME {}", tile.name.unwrap())} else {"".to_string()},
|
||||||
|
if tile.wall {"\nWAL true"} else {""}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_tile_to_string() {
|
||||||
|
// let output = tile_to_string(Tile {
|
||||||
|
// id: "7a".to_string(),
|
||||||
|
// name: Some("chequers".to_string()),
|
||||||
|
// wall: false,
|
||||||
|
// animation_frames: vec![
|
||||||
|
// Image { pixels: vec![
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// ]},
|
||||||
|
// Image { pixels: vec![
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// false,true,false,true,false,true,false,true,
|
||||||
|
// true,false,true,false,true,false,true,false,
|
||||||
|
// ]},
|
||||||
|
// ]
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// let expected = "TIL 7a\n10101010\n01010101\n10101010\n01010101\n10101010\n01010101\n10101010\n01010101\n>\n01010101\n10101010\n01010101\n10101010\n01010101\n10101010\n01010101\n10101010\nNAME chequers".to_string();
|
||||||
|
//
|
||||||
|
// assert_eq!(output, expected);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// todo support Bitsy HD?
|
||||||
|
// todo impl (Game::from_string etc.)
|
||||||
|
|
||||||
|
fn colour_from_string(colour: String) -> Colour {
|
||||||
|
let values: Vec<&str> = colour.split(',').collect();
|
||||||
|
|
||||||
|
let red: u8 = values[0].parse().unwrap_or(0);
|
||||||
|
let green: u8 = values[1].parse().unwrap_or(0);
|
||||||
|
let blue: u8 = values[2].parse().unwrap_or(0);
|
||||||
|
|
||||||
|
Colour { red, green, blue }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colour_to_string(colour: Colour) -> String {
|
||||||
|
format!("{},{},{}", colour.red, colour.green, colour.blue)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_colour_from_string() {
|
||||||
|
assert_eq!(
|
||||||
|
colour_from_string("0,255,0".to_string()),
|
||||||
|
Colour { red: 0, green: 255, blue: 0 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_colour_to_string() {
|
||||||
|
assert_eq!(
|
||||||
|
colour_to_string(Colour { red: 22, green: 33, blue: 44 }),
|
||||||
|
"22,33,44".to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn palette_from_string(palette: String) -> Palette {
|
||||||
|
let lines: Vec<&str> = palette.split('\n').collect();
|
||||||
|
|
||||||
|
let id = lines[0].replace("PAL ", "");
|
||||||
|
|
||||||
|
let name = match lines[1].starts_with("NAME") {
|
||||||
|
true => Some(lines[1].replace("NAME ", "").to_string()),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let colour_start_index = if name.is_some() {2} else {1};
|
||||||
|
|
||||||
|
let colours = lines[colour_start_index..].iter().map(|&line| {
|
||||||
|
colour_from_string(line.to_string())
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
Palette { id, name, colours }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_palette_from_string() {
|
||||||
|
let output = palette_from_string(
|
||||||
|
"PAL 1\nNAME lamplight\n45,45,59\n66,60,39\n140,94,1".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = Palette {
|
||||||
|
id: "1".to_string(),
|
||||||
|
name: Some("lamplight".to_string()),
|
||||||
|
colours: vec![
|
||||||
|
Colour {red: 45, green: 45, blue: 59},
|
||||||
|
Colour {red: 66, green: 60, blue: 39},
|
||||||
|
Colour {red: 140, green: 94, blue: 1 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_palette_from_string_no_name() {
|
||||||
|
let output = palette_from_string(
|
||||||
|
"PAL 9\n45,45,59\n66,60,39\n140,94,1".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = Palette {
|
||||||
|
id: "9".to_string(),
|
||||||
|
name: None,
|
||||||
|
colours: vec![
|
||||||
|
Colour {red: 45, green: 45, blue: 59},
|
||||||
|
Colour {red: 66, green: 60, blue: 39},
|
||||||
|
Colour {red: 140, green: 94, blue: 1 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn game_from_string(game: String ) -> Game {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn game_to_string(game: Game) -> String {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("why am I here?")
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue