diff --git a/src/main.rs b/src/main.rs index 72d63a6..fe2df0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -624,28 +624,30 @@ fn test_colour_to_string() { ); } -fn palette_from_string(palette: String) -> Palette { - let lines: Vec<&str> = palette.split('\n').collect(); +impl From for Palette { + fn from(string: String) -> Palette { + let lines: Vec<&str> = string.lines().collect(); - let id = lines[0].replace("PAL ", ""); + 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 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 colour_start_index = if name.is_some() { 2 } else { 1 }; - let colours = lines[colour_start_index..].iter().map(|&line| { - Colour::from(line.to_string()) - }).collect(); + let colours = lines[colour_start_index..].iter().map(|&line| { + Colour::from(line.to_string()) + }).collect(); - Palette { id, name, colours } + Palette { id, name, colours } + } } #[test] fn test_palette_from_string() { - let output = palette_from_string( + let output = Palette::from( "PAL 1\nNAME lamplight\n45,45,59\n66,60,39\n140,94,1".to_string() ); @@ -664,7 +666,7 @@ fn test_palette_from_string() { #[test] fn test_palette_from_string_no_name() { - let output = palette_from_string( + let output = Palette::from( "PAL 9\n45,45,59\n66,60,39\n140,94,1".to_string() ); @@ -715,21 +717,20 @@ fn test_palette_to_string() { assert_eq!(output, expected); } -fn position_from_string(string: String) -> Position { - // e.g. "2,5" - let xy: Vec<&str> = string.split(',').collect(); - let x = xy[0].parse().unwrap(); - let y = xy[1].parse().unwrap(); +impl From for Position { + fn from(string: String) -> Position { + // e.g. "2,5" + let xy: Vec<&str> = string.split(',').collect(); + let x = xy[0].parse().unwrap(); + let y = xy[1].parse().unwrap(); - Position {x, y} + Position { x, y } + } } #[test] fn test_position_from_string() { - assert_eq!( - position_from_string("4,12".to_string()), - Position { x: 4, y: 12 } - ) + assert_eq!(Position::from("4,12".to_string()), Position { x: 4, y: 12 }); } impl ToString for Position { @@ -744,27 +745,30 @@ fn test_position_to_string() { assert_eq!(Position { x: 4, y: 12 }.to_string(), "4,12".to_string()) } -fn avatar_from_string(string: String) -> Avatar { - let string = string.replace("SPR A\n", ""); - let mut lines: Vec<&str> = string.lines().collect(); - let room_pos = lines.pop().unwrap().replace("POS ", ""); - let room_pos: Vec<&str> = room_pos.split_whitespace().collect(); - let room = room_pos[0].to_string(); - let position = position_from_string(room_pos[1].to_string()); - let animation_frames: String = lines.join("\n"); - let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); - let animation_frames: Vec = animation_frames.iter().map(|&frame| { - Image::from(frame.to_string()) - }).collect(); +impl From for Avatar { + fn from(string: String) -> Avatar { + let string = string.replace("SPR A\n", ""); + let mut lines: Vec<&str> = string.lines().collect(); + let room_pos = lines.pop().unwrap().replace("POS ", ""); + let room_pos: Vec<&str> = room_pos.split_whitespace().collect(); + let room = room_pos[0].to_string(); + let position = Position::from(room_pos[1].to_string()); + let animation_frames: String = lines.join("\n"); + let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); + let animation_frames: Vec = animation_frames.iter().map(|&frame| { + Image::from(frame.to_string()) + }).collect(); - Avatar { animation_frames, room, position } + Avatar { animation_frames, room, position } + } } #[test] fn test_avatar_from_string() { - let output = avatar_from_string( + let output = Avatar::from( include_str!("../test/resources/avatar").to_string() ); + let expected = example_avatar(); assert_eq!(output, expected); } @@ -786,48 +790,51 @@ fn test_avatar_to_string() { assert_eq!(example_avatar().to_string(), include_str!("../test/resources/avatar")); } -fn sprite_from_string(string: String) -> Sprite { - let mut lines: Vec<&str> = string.lines().collect(); +impl From for Sprite { + fn from(string: String) -> Sprite { + let mut lines: Vec<&str> = string.lines().collect(); - let id = lines[0].replace("SPR ", ""); - let mut name = None; - let mut dialogue = None; - let mut room: Option = None; - let mut position: Option = None; + let id = lines[0].replace("SPR ", ""); + let mut name = None; + let mut dialogue = None; + let mut room: Option = None; + let mut position: Option = None; - for _ in 0..3 { - let last_line = lines.pop().unwrap(); + for _ in 0..3 { + let last_line = lines.pop().unwrap(); - if last_line.starts_with("NAME") { - name = Some(last_line.replace("NAME ", "").to_string()); - } else if last_line.starts_with("DLG") { - dialogue = Some(last_line.replace("DLG ", "").to_string()); - } else if last_line.starts_with("POS") { - let last_line = last_line.replace("POS ", ""); - let room_position: Vec<&str> = last_line.split(' ').collect(); - room = Some(room_position[0].to_string()); - position = Some(position_from_string(room_position[1].to_string())); - } else { - lines.push(last_line); break; + if last_line.starts_with("NAME") { + name = Some(last_line.replace("NAME ", "").to_string()); + } else if last_line.starts_with("DLG") { + dialogue = Some(last_line.replace("DLG ", "").to_string()); + } else if last_line.starts_with("POS") { + let last_line = last_line.replace("POS ", ""); + let room_position: Vec<&str> = last_line.split(' ').collect(); + room = Some(room_position[0].to_string()); + position = Some(Position::from(room_position[1].to_string())); + } else { + lines.push(last_line); + break; + } } + + let room = room.unwrap(); + let position = position.unwrap(); + + // todo dedupe + let animation_frames = lines[1..].join(""); + let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); + let animation_frames: Vec = animation_frames.iter().map(|&frame| { + Image::from(frame.to_string()) + }).collect(); + + Sprite { id, name, animation_frames, dialogue, room, position } } - - let room = room.unwrap(); - let position = position.unwrap(); - - // todo dedupe - let animation_frames = lines[1..].join(""); - let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); - let animation_frames: Vec = animation_frames.iter().map(|&frame| { - Image::from(frame.to_string()) - }).collect(); - - Sprite { id, name, animation_frames, dialogue, room, position } } #[test] fn test_sprite_from_string() { - let output = sprite_from_string( + let output = Sprite::from( include_str!("../test/resources/sprite").to_string() ); @@ -856,43 +863,42 @@ fn test_sprite_to_string() { assert_eq!(example_sprite().to_string(), include_str!("../test/resources/sprite").to_string()); } -fn item_from_string(string: String) -> Item { - let mut lines: Vec<&str> = string.lines().collect(); +impl From for Item { + fn from(string: String) -> Item { + let mut lines: Vec<&str> = string.lines().collect(); - let id = lines[0].replace("ITM ", ""); - let mut name = None; - let mut dialogue = None; + let id = lines[0].replace("ITM ", ""); + let mut name = None; + let mut dialogue = None; - for _ in 0..2 { - let last_line = lines.pop().unwrap(); + for _ in 0..2 { + let last_line = lines.pop().unwrap(); - if last_line.starts_with("NAME") { - name = Some(last_line.replace("NAME ", "").to_string()); - } else if last_line.starts_with("DLG") { - dialogue = Some(last_line.replace("DLG ", "").to_string()); - } else { - lines.push(last_line); break; + if last_line.starts_with("NAME") { + name = Some(last_line.replace("NAME ", "").to_string()); + } else if last_line.starts_with("DLG") { + dialogue = Some(last_line.replace("DLG ", "").to_string()); + } else { + lines.push(last_line); + break; + } } + + // todo dedupe + let animation_frames = lines[1..].join(""); + let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); + let animation_frames: Vec = animation_frames.iter().map(|&frame| { + Image::from(frame.to_string()) + }).collect(); + + Item { id, name, animation_frames, dialogue } } - - // todo dedupe - let animation_frames = lines[1..].join(""); - let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect(); - let animation_frames: Vec = animation_frames.iter().map(|&frame| { - Image::from(frame.to_string()) - }).collect(); - - Item { id, name, animation_frames, dialogue } } #[test] fn test_item_from_string() { - let output = item_from_string( - include_str!("../test/resources/item").to_string() - ); - + let output = Item::from(include_str!("../test/resources/item").to_string()); let expected = example_item(); - assert_eq!(output, expected); } @@ -916,19 +922,21 @@ fn test_item_to_string() { assert_eq!(output, expected); } -fn exit_from_string(string: String) -> Exit { - // e.g. "4 3,3" - let room_position: Vec<&str> = string.split(' ').collect(); - let room = room_position[0].to_string(); - let position = position_from_string(room_position[1].to_string()); +impl From for Exit { + fn from(string: String) -> Exit { + // e.g. "4 3,3" + let room_position: Vec<&str> = string.split(' ').collect(); + let room = room_position[0].to_string(); + let position = Position::from(room_position[1].to_string()); - Exit { room, position } + Exit { room, position } + } } #[test] fn test_exit_from_string() { assert_eq!( - exit_from_string("a 12,13".to_string()), + Exit::from("a 12,13".to_string()), Exit { room: "a".to_string(), position: Position { x: 12, y: 13 } } ); } @@ -947,19 +955,21 @@ fn test_exit_to_string() { ); } -fn ending_from_string(string: String) -> Ending { - let string = string.replace("END ", ""); - let id_dialogue: Vec<&str> = string.split('\n').collect(); - let id = id_dialogue[0].to_string(); - let dialogue = id_dialogue[1].to_string(); +impl From for Ending { + fn from(string: String) -> Ending { + let string = string.replace("END ", ""); + let id_dialogue: Vec<&str> = string.lines().collect(); + let id = id_dialogue[0].to_string(); + let dialogue = id_dialogue[1].to_string(); - Ending { id, dialogue } + Ending { id, dialogue } + } } #[test] fn test_ending_from_string() { assert_eq!( - ending_from_string(include_str!("../test/resources/ending").to_string()), + Ending::from(include_str!("../test/resources/ending").to_string()), Ending { id: "a".to_string(), dialogue: "This is a long line of dialogue. Blah blah blah".to_string() @@ -985,18 +995,20 @@ fn test_ending_to_string() { ); } -fn dialogue_from_string(string: String) -> Dialogue { - let lines: Vec<&str> = string.lines().collect(); - let id = lines[0].replace("DLG ", "").to_string(); - let contents = lines[1..].join("\n"); +impl From for Dialogue { + fn from(string: String) -> Dialogue { + let lines: Vec<&str> = string.lines().collect(); + let id = lines[0].replace("DLG ", "").to_string(); + let contents = lines[1..].join("\n"); - Dialogue { id, contents } + Dialogue { id, contents } + } } #[test] fn test_dialogue_from_string() { assert_eq!( - dialogue_from_string("DLG h\nhello\ngoodbye".to_string()), + Dialogue::from("DLG h\nhello\ngoodbye".to_string()), Dialogue { id: "h".to_string(), contents: "hello\ngoodbye".to_string()} ) } @@ -1019,18 +1031,20 @@ fn test_dialogue_to_string() { ); } -fn variable_from_string(string: String) -> Variable { - let id_value: Vec<&str> = string.split('\n').collect(); - let id = id_value[0].replace("VAR ", "").to_string(); - let initial_value = id_value[1].to_string(); +impl From for Variable { + fn from(string: String) -> Variable { + let id_value: Vec<&str> = string.split('\n').collect(); + let id = id_value[0].replace("VAR ", "").to_string(); + let initial_value = id_value[1].to_string(); - Variable { id, initial_value } + Variable { id, initial_value } + } } #[test] fn test_variable_from_string() { assert_eq!( - variable_from_string("VAR a\n42".to_string()), + Variable::from("VAR a\n42".to_string()), Variable { id: "a".to_string(), initial_value: "42".to_string()} ); } @@ -1049,72 +1063,72 @@ fn test_variable_to_string() { assert_eq!(output, expected); } -fn room_from_string(string: String) -> Room { - // todo handle room_format? - let mut lines: Vec<&str> = string.lines().collect(); - let id = lines[0].replace("ROOM ", ""); - let mut name = None; - let mut palette = "0".to_string(); - let mut items: Vec = Vec::new(); - let mut exits: Vec = Vec::new(); - let mut endings: Vec = Vec::new(); +impl From for Room { + fn from(string: String) -> Room { + // todo handle room_format? + let mut lines: Vec<&str> = string.lines().collect(); + let id = lines[0].replace("ROOM ", ""); + let mut name = None; + let mut palette = "0".to_string(); + let mut items: Vec = Vec::new(); + let mut exits: Vec = Vec::new(); + let mut endings: Vec = Vec::new(); - loop { - let last_line = lines.pop().unwrap(); + loop { + let last_line = lines.pop().unwrap(); - if last_line.starts_with("NAME") { - name = Some(last_line.replace("NAME ", "").to_string()); - } else if last_line.starts_with("PAL") { - palette = last_line.replace("PAL ", "").to_string(); - } else if last_line.starts_with("ITM") { - let last_line = last_line.replace("ITM ", ""); - let item_position: Vec<&str> = last_line.split(' ').collect(); - let item_id = item_position[0]; - let position = item_position[1]; - let position = position_from_string(position.to_string()); + if last_line.starts_with("NAME") { + name = Some(last_line.replace("NAME ", "").to_string()); + } else if last_line.starts_with("PAL") { + palette = last_line.replace("PAL ", "").to_string(); + } else if last_line.starts_with("ITM") { + let last_line = last_line.replace("ITM ", ""); + let item_position: Vec<&str> = last_line.split(' ').collect(); + let item_id = item_position[0]; + let position = item_position[1]; + let position = Position::from(position.to_string()); - items.push(Instance { position, id: item_id.to_string() }); - } else if last_line.starts_with("EXT") { - let last_line = last_line.replace("EXT ", ""); - let parts: Vec<&str> = last_line.split(' ').collect(); - let position = position_from_string(parts[0].to_string()); - let exit = exit_from_string(format!("{} {}", parts[1], parts[2])); + items.push(Instance { position, id: item_id.to_string() }); + } else if last_line.starts_with("EXT") { + let last_line = last_line.replace("EXT ", ""); + let parts: Vec<&str> = last_line.split(' ').collect(); + let position = Position::from(parts[0].to_string()); + let exit = Exit::from(format!("{} {}", parts[1], parts[2])); - exits.push(ExitInstance { position, exit }); - } else if last_line.starts_with("END") { - let last_line = last_line.replace("END ", ""); - let ending_position: Vec<&str> = last_line.split(' ').collect(); - let ending= ending_position[0].to_string(); - let position = ending_position[1].to_string(); - let position = position_from_string(position); + exits.push(ExitInstance { position, exit }); + } else if last_line.starts_with("END") { + let last_line = last_line.replace("END ", ""); + let ending_position: Vec<&str> = last_line.split(' ').collect(); + let ending = ending_position[0].to_string(); + let position = ending_position[1].to_string(); + let position = Position::from(position); - endings.push(Instance { position, id: ending }); - } else { - lines.push(last_line); break; + endings.push(Instance { position, id: ending }); + } else { + lines.push(last_line); + break; + } } - } - let lines= &lines[1..]; + let lines = &lines[1..]; - let mut tiles : Vec = Vec::new(); + let mut tiles: Vec = Vec::new(); - for line in lines.into_iter() { - let line: Vec<&str> = line.split(",").collect(); + for line in lines.into_iter() { + let line: Vec<&str> = line.split(",").collect(); - for tile_id in line { - tiles.push(tile_id.to_string()); + for tile_id in line { + tiles.push(tile_id.to_string()); + } } - } - Room { id, palette, name, tiles, items, exits, endings } + Room { id, palette, name, tiles, items, exits, endings } + } } #[test] fn test_room_from_string() { - let output = room_from_string(example_room_string()); - let expected = example_room(); - - assert_eq!(output, expected); + assert_eq!(Room::from(example_room_string()), example_room()); } impl ToString for Room { @@ -1174,105 +1188,108 @@ fn test_room_to_string() { assert_eq!(example_room().to_string(), example_room_string()); } -fn game_from_string(string: String ) -> Game { - // dialogues and endings can have 2+ line breaks inside, so deal with these separately - // otherwise, everything can be split on a double line break (\n\n) - let mut dialogues: Vec = Vec::new(); - let mut endings: Vec = Vec::new(); - let mut variables: Vec = Vec::new(); - let main_split: Vec<&str> = string.split("\n\nDLG").collect(); - let main = main_split[0].to_string(); - let mut dialogues_endings_variables: String = main_split[1..].join("\n\nDLG"); +impl From for Game { + fn from(string: String) -> Game { + // dialogues and endings can have 2+ line breaks inside, so deal with these separately + // otherwise, everything can be split on a double line break (\n\n) + let mut dialogues: Vec = Vec::new(); + let mut endings: Vec = Vec::new(); + let mut variables: Vec = Vec::new(); + let main_split: Vec<&str> = string.split("\n\nDLG").collect(); + let main = main_split[0].to_string(); + let mut dialogues_endings_variables: String = main_split[1..].join("\n\nDLG"); - let variable_segments = dialogues_endings_variables.clone(); - let variable_segments: Vec<&str> = variable_segments.split("\n\nVAR").collect(); - if variable_segments.len() > 0 { - dialogues_endings_variables = variable_segments[0].to_string(); - let variable_segments = variable_segments[1..].to_owned(); + let variable_segments = dialogues_endings_variables.clone(); + let variable_segments: Vec<&str> = variable_segments.split("\n\nVAR").collect(); + if variable_segments.len() > 0 { + dialogues_endings_variables = variable_segments[0].to_string(); + let variable_segments = variable_segments[1..].to_owned(); - for segment in variable_segments { - let segment = format!("VAR{}", segment); - variables.push(variable_from_string(segment)); + for segment in variable_segments { + let segment = format!("VAR{}", segment); + variables.push(Variable::from(segment)); + } } - } - let ending_segments = dialogues_endings_variables.clone(); - let ending_segments: Vec<&str> = ending_segments.split("\n\nEND").collect(); - if ending_segments.len() > 0 { - dialogues_endings_variables = ending_segments[0].to_string(); - let ending_segments = ending_segments[1..].to_owned(); + let ending_segments = dialogues_endings_variables.clone(); + let ending_segments: Vec<&str> = ending_segments.split("\n\nEND").collect(); + if ending_segments.len() > 0 { + dialogues_endings_variables = ending_segments[0].to_string(); + let ending_segments = ending_segments[1..].to_owned(); - for segment in ending_segments { - let segment = format!("END{}", segment); - endings.push(ending_from_string(segment)); + for segment in ending_segments { + let segment = format!("END{}", segment); + endings.push(Ending::from(segment)); + } } - } - let dialogue_segments = format!("\n\nDLG {}", dialogues_endings_variables.trim()); - let dialogue_segments: Vec<&str> = dialogue_segments.split("\n\nDLG").collect(); - for segment in dialogue_segments[1..].to_owned() { - let segment = format!("DLG{}", segment); - dialogues.push(dialogue_from_string(segment)); - } - - let segments: Vec<&str> = main.split("\n\n").collect(); - - let name = segments[0].to_string(); - let mut version: f64 = 1.0; - let mut room_format: u8 = 1; - let mut palettes: Vec = Vec::new(); - let mut rooms: Vec = Vec::new(); - let mut tiles: Vec = Vec::new(); - let mut avatar : Option = None; // unwrap this later - let mut sprites: Vec = Vec::new(); - let mut items: Vec = Vec::new(); - - for segment in segments[1..].to_owned() { - let segment = segment.to_string(); - - if segment.starts_with("# BITSY VERSION") { - version = segment.replace("# BITSY VERSION ", "").parse().unwrap(); - } else if segment.starts_with("! ROOM_FORMAT") { - room_format = segment.replace("! ROOM_FORMAT ", "").parse().unwrap(); - } else if segment.starts_with("PAL") { - palettes.push(palette_from_string(segment)); - } else if segment.starts_with("ROOM") { - rooms.push(room_from_string(segment)); - } else if segment.starts_with("TIL") { - tiles.push(Tile::from(segment)); - } else if segment.starts_with("SPR A") { - avatar = Some(avatar_from_string(segment)); - } else if segment.starts_with("SPR") { - sprites.push(sprite_from_string(segment)); - } else if segment.starts_with("ITM") { - items.push(item_from_string(segment)); + let dialogue_segments = format!("\n\nDLG {}", dialogues_endings_variables.trim()); + let dialogue_segments: Vec<&str> = dialogue_segments.split("\n\nDLG").collect(); + for segment in dialogue_segments[1..].to_owned() { + let segment = format!("DLG{}", segment); + dialogues.push(Dialogue::from(segment)); } - } - assert!(avatar.is_some()); - let avatar = avatar.unwrap(); - - Game { - name, - version, - room_format, - palettes, - rooms, - tiles, - avatar, - sprites, - items, - dialogues, - endings, - variables, + let segments: Vec<&str> = main.split("\n\n").collect(); + + let name = segments[0].to_string(); + let mut version: f64 = 1.0; + let mut room_format: u8 = 1; + let mut palettes: Vec = Vec::new(); + let mut rooms: Vec = Vec::new(); + let mut tiles: Vec = Vec::new(); + let mut avatar: Option = None; // unwrap this later + let mut sprites: Vec = Vec::new(); + let mut items: Vec = Vec::new(); + + for segment in segments[1..].to_owned() { + let segment = segment.to_string(); + + if segment.starts_with("# BITSY VERSION") { + version = segment.replace("# BITSY VERSION ", "").parse().unwrap(); + } else if segment.starts_with("! ROOM_FORMAT") { + room_format = segment.replace("! ROOM_FORMAT ", "").parse().unwrap(); + } else if segment.starts_with("PAL") { + palettes.push(Palette::from(segment)); + } else if segment.starts_with("ROOM") { + rooms.push(Room::from(segment)); + } else if segment.starts_with("TIL") { + tiles.push(Tile::from(segment)); + } else if segment.starts_with("SPR A") { + avatar = Some(Avatar::from(segment)); + } else if segment.starts_with("SPR") { + sprites.push(Sprite::from(segment)); + } else if segment.starts_with("ITM") { + items.push(Item::from(segment)); + } + } + + assert!(avatar.is_some()); + let avatar = avatar.unwrap(); + + Game { + name, + version, + room_format, + palettes, + rooms, + tiles, + avatar, + sprites, + items, + dialogues, + endings, + variables, + } } } #[test] fn test_game_from_string() { - let output = game_from_string( + let output = Game::from( include_str!["../test/resources/default.bitsy"].to_string() ); + let expected = example_game_default(); assert_eq!(output, expected);