peachy/src/lib.rs

505 lines
13 KiB
Rust
Raw Normal View History

2020-09-02 16:50:13 +00:00
use std::collections::HashMap;
use std::fs;
use serde_derive::{Serialize, Deserialize};
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Colour {
red: u8,
green: u8,
blue: u8,
alpha: u8,
}
impl Colour {
pub fn from(colours: Vec<u8>) -> Colour {
const ZERO: u8 = 0;
Colour {
red: *colours.get(0).unwrap_or(&ZERO),
green: *colours.get(1).unwrap_or(&ZERO),
blue: *colours.get(2).unwrap_or(&ZERO),
alpha: *colours.get(3).unwrap_or(&255),
}
}
pub fn to_vec(&self) -> Vec<u8> {
vec![self.red, self.green, self.blue, self.alpha]
}
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Palette {
name: String,
colours: Vec<Colour>,
}
impl Palette {
pub fn from(name: &str, toml: &str) -> Self {
let intermediate: IntermediatePalette = toml::from_str(toml).unwrap();
println!("palette name: {}", name);
for colour in &intermediate.colours {
println!("palette colour: {}{}{}", colour[0], colour[1], colour[2]);
}
Palette {
name: name.to_string(),
colours: intermediate.colours.iter().map(|vec| {
Colour::from(vec.clone())
}).collect(),
}
}
pub fn from_file(path: String) -> Self {
// todo get name without extension
let name = "blah";
let toml = fs::read_to_string(path).unwrap();
Self::from(name, &toml)
}
}
/// for toml purposes
#[derive(Serialize, Deserialize)]
struct IntermediatePalette {
colours: Vec<Vec<u8>>,
}
/// for toml purposes
#[derive(Serialize, Deserialize)]
struct IntermediatePalettes {
/// singular so each palette section is named "palette" instead of "palettes" in toml
palette: Vec<IntermediatePalette>,
}
impl IntermediatePalettes {
pub fn from_dir() -> Self {
Self {
palette: vec![]
}
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Position {
x: u8,
y: u8,
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Image {
name: String,
/// colour indexes
pixels: Vec<u8>,
}
impl Image {
fn from(intermediate: IntermediateImage) -> Image {
Image {
name: intermediate.name.to_owned(),
pixels: intermediate.pixels.split_whitespace().collect::<String>().chars().map(
|char|char as u8
).collect()
}
}
}
/// for toml purposes
#[derive(Debug, Serialize, Deserialize)]
struct IntermediateImages {
/// singular so each image is named "image" instead of "images" in toml
image: Vec<IntermediateImage>,
}
impl IntermediateImages {
fn to_images(&self) -> Vec<Image> {
self.image.iter().map(|intermediate|
Image::from(intermediate.clone())
).collect()
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
struct IntermediateImage {
name: String,
pixels: String,
}
impl IntermediateImage {
// todo refactor
fn from(image: Image) -> IntermediateImage {
let mut string = "\n".to_string();
let sqrt = (image.pixels.len() as f64).sqrt() as usize;
for line in image.pixels.chunks(sqrt) {
for pixel in line {
string.push_str(&format!("{}", *pixel));
}
string.push('\n');
}
IntermediateImage {
name: image.name.to_owned(),
/// todo wtf? I guess this crate doesn't handle multiline strings correctly
pixels: format!("\"\"{}\"\"", string),
}
}
}
// #[derive(Serialize, Deserialize)]
// pub struct Thing {
// name: Option<String>,
// /// image name
// image: String,
// }
//
pub struct Room {
name: String,
width: u8,
height: u8,
/// thing names and their positions
background: HashMap<Position, String>,
foreground: HashMap<Position, String>,
}
#[derive(Serialize, Deserialize)]
struct IntermediateRoom {
name: String,
background: Vec<String>,
foreground: Vec<String>,
}
impl IntermediateRoom {
fn from(room: Room) -> IntermediateRoom {
fn hashmap_to_vec(hash: HashMap<Position, String>, width: u8, height: u8) -> Vec<String> {
let mut thing_ids = Vec::new();
while thing_ids.len() < (width * height) as usize {
thing_ids.push(String::new());
}
thing_ids
}
IntermediateRoom {
name: "".to_string(),
background: vec![],
foreground: vec![]
}
}
}
// #[derive(Serialize, Deserialize)]
// pub enum DataType {
// Image,
// Integer,
// Palette,
// Room,
// Script,
// String,
// Thing,
// Variable,
// }
//
// /// todo refactor, this is stupid
// #[derive(Serialize, Deserialize)]
// pub struct Value {
// data_type: DataType,
// image: Option<String>,
// integer: Option<u64>,
// palette: Option<String>,
// room: Option<String>,
// script: Option<String>,
// string: Option<String>,
// thing: Option<String>,
// variable: Option<String>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Variable {
// name: String,
// data_type: DataType,
// default: Value,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Parameter {
// name: String,
// data_type: DataType,
// default: Value,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Script {
// name: Option<String>,
// params: Vec<Parameter>,
// script: String,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct ScriptInstance {
// script: String,
// params: HashMap<String, Value>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct ScriptCollection {
// scripts: Vec<ScriptInstance>,
// /// as well as many named scripts, a trigger can have one anonymous script
// anonymous: Option<String>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Version {
// major: u8,
// minor: u8,
// }
//
// impl Version {
// pub fn default() -> Version {
// Version { major: 0, minor: 1 }
// }
// }
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Config {
/// used in the window title bar
name: Option<String>,
width: u8,
height: u8,
/// animation rate in milliseconds
tick: u64,
/// if this is not specified, the game will pick the first room it finds
starting_room: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub struct Game {
config: Config,
// palettes: Vec<Palette>,
// variables: Vec<Variable>,
// triggers: HashMap<String, ScriptCollection>,
}
//
// #[derive(Debug)]
// pub struct GameParseError;
//
// impl Game {
// pub fn from(s: &str) -> Result<Game, GameParseError> {
// let result = toml::from_str(s);
// if result.is_ok() {
// Ok(result.unwrap())
// } else {
// Err(GameParseError)
// }
// }
// }
//
mod mock {
pub(crate) mod image {
use crate::Image;
pub fn bg() -> Image {
Image {
name: "bg".to_string(),
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
]
}
}
pub fn block() -> Image {
Image {
name: "block".to_string(),
pixels: vec![
1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,1,
1,0,0,1,1,0,0,1,
1,0,0,1,1,0,0,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,
]
}
}
pub fn avatar() -> Image {
Image {
name: "avatar".to_string(),
pixels: vec![
0,0,0,2,2,0,0,0,
0,0,0,2,2,0,0,0,
0,0,0,2,2,0,0,0,
0,0,2,2,2,2,0,0,
0,2,2,2,2,2,2,0,
2,0,2,2,2,2,0,2,
0,0,2,0,0,2,0,0,
0,0,2,0,0,2,0,0,
]
}
}
pub fn cat() -> Image {
Image {
name: "cat".to_string(),
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,2,0,2,0,0,0,2,
0,2,2,2,0,0,0,2,
0,2,2,2,0,0,2,0,
0,2,2,2,2,2,0,0,
0,0,2,2,2,2,0,0,
0,0,2,0,0,2,0,0,
]
}
}
}
pub(crate) mod palette {
use crate::{Palette, Colour, IntermediatePalette};
pub(crate) fn intermediate() -> IntermediatePalette {
IntermediatePalette {
colours: vec![
vec![0,0,0,0],
vec![0,81,104,255],
vec![118,159,155,255],
vec![155,155,155,255],
]
}
}
pub(crate) fn default() -> Palette {
Palette {
name: "blueprint".to_string(),
colours: vec![
Colour { red: 0, green: 0, blue: 0, alpha: 0 },
Colour { red: 0, green: 81, blue: 104, alpha: 255 },
Colour { red: 118, green: 159, blue: 155, alpha: 255 },
Colour { red: 155, green: 155, blue: 155, alpha: 255 },
],
}
}
}
}
#[cfg(test)]
mod test {
use crate::{Game, Config, Palette, Colour, Image, IntermediatePalettes, IntermediateImage, IntermediateImages};
#[test]
fn test_config_from_toml() {
let output: Config = toml::from_str(include_str!("test-resources/basic/game.toml")).unwrap();
let expected = Config {
name: Some("Write your game's title here".to_string()),
width: 16,
height: 9,
tick: 400,
starting_room: Some("example room".to_string())
};
assert_eq!(output, expected);
}
#[test]
fn test_config_to_toml() {
let output = toml::to_string(&Config {
name: Some("Write your game's title here".to_string()),
width: 16,
height: 9,
tick: 400,
starting_room: Some("example room".to_string())
}).unwrap();
let expected = include_str!("test-resources/basic/game.toml");
assert_eq!(&output, expected);
}
#[test]
fn test_palette_from_toml() {
let output = Palette::from(
"blueprint",
include_str!("test-resources/basic/palettes/blueprint.toml")
);
let expected = crate::mock::palette::default();
assert_eq!(output, expected);
}
#[test]
fn test_palette_to_toml() {
let intermediate = crate::mock::palette::intermediate();
let output = toml::to_string(&intermediate).unwrap();
let expected = include_str!("test-resources/basic/palettes/blueprint.toml");
assert_eq!(&output, expected);
}
// #[test]
// fn test_image_from_toml() {
// let str = include_str!("test-resources/basic/images.toml");
// let output: Image = toml::from_str(str).unwrap();
// let expected = crate::mock::image::avatar();
// assert_eq!(output, expected);
// }
#[test]
fn test_colour_from_intermediate() {
let output = Colour::from(vec![64, 128, 192, 255]);
let expected = Colour { red: 64, green: 128, blue: 192, alpha: 255 };
assert_eq!(output, expected);
}
#[test]
fn test_colour_to_intermediate() {
let output = Colour { red: 64, green: 128, blue: 192, alpha: 255 }.to_vec();
let expected = vec![64, 128, 192, 255];
assert_eq!(output, expected);
}
// #[test]
// fn test_images_from_intermediate() {
// let str = include_str!("test-resources/basic/images.toml");
// let output: Vec<IntermediateImage> = toml::from_str(str).unwrap();
// print!("{}", output.len());
// }
// #[test]
// fn test_images_to_toml() {
// let images = IntermediateImages {
// image: vec![
// IntermediateImage::from(crate::mock::image::bg()),
// IntermediateImage::from(crate::mock::image::block()),
// IntermediateImage::from(crate::mock::image::avatar()),
// IntermediateImage::from(crate::mock::image::cat()),
// ]
// };
//
// let output = toml::to_string(&images).unwrap();
// let expected = include_str!("test-resources/basic/images.toml");
//
// // I think this is failing because one has escaped quotation marks and one has normal ones(??)
// assert_eq!(output, expected);
// }
// #[test]
// fn test_images_from_toml() {
// let str = include_str!("test-resources/basic/images.toml");
// let output: IntermediateImages = toml::from_str(str).unwrap();
// let output = output.to_images();
// let expected = vec![
// crate::mock::image::bg(),
// crate::mock::image::block(),
// crate::mock::image::avatar(),
// crate::mock::image::cat(),
// ];
// assert_eq!(output, expected);
// }
}