town and world maps to unicode
This commit is contained in:
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "vrtue"
|
||||
version = "0.1.0"
|
||||
authors = ["Jared Roberts <jaredr@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
itertools = ">=0.4"
|
||||
memmap = "~0.2"
|
||||
49
src/main.rs
Normal file
49
src/main.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
extern crate itertools;
|
||||
extern crate memmap;
|
||||
|
||||
use std::mem::transmute;
|
||||
use std::env;
|
||||
|
||||
use itertools::Itertools;
|
||||
use memmap::{Mmap, Protection};
|
||||
|
||||
mod world;
|
||||
mod transpose;
|
||||
|
||||
use world::Map;
|
||||
|
||||
fn mmap_to_rows<'a, M: world::Map>(mmap: &memmap::Mmap) -> &'a world::Map
|
||||
where M: Copy + 'a
|
||||
{
|
||||
assert!(std::mem::size_of::<M>() <= mmap.len());
|
||||
unsafe { transmute::<*const u8, &M>(mmap.ptr()) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let filename;
|
||||
let conv;
|
||||
if args.len() > 1 {
|
||||
filename = &args[1] as &str;
|
||||
conv = mmap_to_rows::<world::Chunk>;
|
||||
} else {
|
||||
filename = "data/WORLD.MAP";
|
||||
conv = mmap_to_rows::<world::World>;
|
||||
}
|
||||
|
||||
let file_mmap = Mmap::open_path(filename, Protection::Read).unwrap();
|
||||
let world = conv(&file_mmap);
|
||||
|
||||
print_rows(world.rows());
|
||||
}
|
||||
|
||||
fn print_rows<'a, T: ?Sized, U: ?Sized>(rows: Box<T>)
|
||||
where T: Iterator<Item = Box<U>> + 'a,
|
||||
U: Iterator<Item = &'a world::Tile> + 'a
|
||||
{
|
||||
for row in rows {
|
||||
let s1: String = row.into_iter().map(|tile| tile.as_char()).collect();
|
||||
let s: String = s1.chars().intersperse(' ').collect();
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
89
src/transpose.rs
Normal file
89
src/transpose.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
pub trait TransposableIterator: Iterator {
|
||||
fn transpose<C, J, T>(self) -> Transpose<Self>
|
||||
where Self: Iterator<Item = C> + Clone + Sized,
|
||||
C: IntoIterator<Item = T, IntoIter = J>,
|
||||
J: ExactSizeIterator<Item = T>
|
||||
{
|
||||
Transpose::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TransposableIterator for I where I: Iterator
|
||||
{}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Transpose<I> {
|
||||
loc: ::std::ops::Range<usize>,
|
||||
iter: I,
|
||||
}
|
||||
|
||||
impl<I, C, J, T> Transpose<I>
|
||||
where I: Iterator<Item = C> + Clone,
|
||||
C: IntoIterator<Item = T, IntoIter = J>,
|
||||
J: ExactSizeIterator<Item = T>
|
||||
{
|
||||
fn new(base: I) -> Transpose<I> {
|
||||
let longest = base.clone()
|
||||
.fold(0, |len, row| ::std::cmp::max(len, row.into_iter().len()));
|
||||
|
||||
Transpose {
|
||||
loc: 0..longest,
|
||||
iter: base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for Transpose<I> where I: Clone
|
||||
{
|
||||
type Item = TransposeInner<I>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<TransposeInner<I>> {
|
||||
self.loc.next().map(|idx| {
|
||||
TransposeInner {
|
||||
iter: self.iter.clone(),
|
||||
col: idx,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.loc.end, Some(self.loc.end))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ExactSizeIterator for Transpose<I> where I: Clone
|
||||
{}
|
||||
|
||||
impl<I> DoubleEndedIterator for Transpose<I> where I: Clone
|
||||
{
|
||||
fn next_back(&mut self) -> Option<TransposeInner<I>> {
|
||||
self.loc.next_back().map(|idx| {
|
||||
TransposeInner {
|
||||
iter: self.iter.clone(),
|
||||
col: idx,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[derive(Clone)]
|
||||
pub struct TransposeInner<I> {
|
||||
iter: I,
|
||||
col: usize,
|
||||
}
|
||||
|
||||
impl<I, J, T> Iterator for TransposeInner<I>
|
||||
where I: Iterator<Item = J>,
|
||||
J: IntoIterator<Item = T>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
self.iter.next().and_then(|row| row.into_iter().nth(self.col))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ExactSizeIterator and DoubleEndedIterator for TransposeInner
|
||||
128
src/world.rs
Normal file
128
src/world.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
extern crate core;
|
||||
extern crate itertools;
|
||||
|
||||
use self::itertools::Itertools;
|
||||
|
||||
use transpose::TransposableIterator;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Tile {
|
||||
val: u8,
|
||||
}
|
||||
|
||||
impl Tile {
|
||||
pub fn as_char(&self) -> char {
|
||||
match self.val {
|
||||
0 => '~', // deep water '🌊'
|
||||
1 => '≈', // medium water
|
||||
2 => '≋', // shallow water
|
||||
3 => ',', // swamp
|
||||
4 => '⢊', // plain '░'
|
||||
5 => '🌿', // scrub 'წ'
|
||||
6 => '🌳', // forest
|
||||
7 => '⌓', // hill '∩'
|
||||
8 => '⨇', // mountain '△'
|
||||
9 => '☗', // dungeon
|
||||
10 => '⍟', // city
|
||||
11 | 13...15 => '⛫', // castle
|
||||
12 => '❖', // village
|
||||
22 => '⎔', // tile floor
|
||||
23 => '⟗', // bridge
|
||||
24 => '⧬', // balloon
|
||||
25 => '≃', // bridge top
|
||||
26 => '≂', // bridge bottom
|
||||
27 => '⍐', // ladder up
|
||||
28 => '⍗', // ladder down
|
||||
29 => 'v', // ruin
|
||||
30 => '◌', // shrine
|
||||
48 => '◯', // column
|
||||
49 => '◣', // SW
|
||||
50 => '◢', // SE
|
||||
51 => '◤', // NW
|
||||
52 => '◥', // NE
|
||||
54 => '⎈', // ship's wheel
|
||||
55 => 'ფ', // rocks '❍'
|
||||
56 => '/', // Lyin down
|
||||
57 => '⬛', // stone wall
|
||||
58 => '⧯', // '🔒', // locked door
|
||||
59 => '⧮', // '🔓', // unlocked door
|
||||
60 => '💰', // chest
|
||||
61 => '☥', // ankh
|
||||
62 => '⨳', // brick floor '⌗'
|
||||
63 => '▤', // wood planks '⧻'
|
||||
68 => '🌫', // poison field
|
||||
69 => '⚡', // energy field
|
||||
70 => '🔥', // fire field
|
||||
71 => '💤', // sleep field
|
||||
72 => '▣', // solid barrier
|
||||
73 => '▒', // hidden passage
|
||||
75 => '🍖', // spit (rotisserie) '🍳'
|
||||
76 => '⌘', // lava
|
||||
96...121 => ::std::char::from_u32((self.val - 31) as u32).unwrap(),
|
||||
122 => '=', // space
|
||||
123 => '⊐', // right ''
|
||||
124 => '⊏', // left '⊨'
|
||||
125 => '▢', // window
|
||||
126 => '✨', // space
|
||||
127 => '▓', // brick wall
|
||||
189 => '⚔', // phantom 2
|
||||
_ => '?', // panic!("{0}", self.val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Map {
|
||||
fn rows<'a>(&'a self) -> BoxedMapIterator;
|
||||
}
|
||||
|
||||
pub type BoxedMapIterator<'a> = Box<Iterator<Item = ChunkRowIterator<'a>> + 'a>;
|
||||
pub type ExactBoxedMapIterator<'a> = Box<ExactSizeIterator<Item = ChunkRowIterator<'a>> + 'a>;
|
||||
|
||||
const CHUNKDIM: usize = 32;
|
||||
pub type ChunkRow = [Tile; CHUNKDIM];
|
||||
pub type ChunkRect = [ChunkRow; CHUNKDIM];
|
||||
pub type ChunkRowIterator<'a> = Box<Iterator<Item = &'a Tile> + 'a>;
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Chunk {
|
||||
pub rect: ChunkRect,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
fn rows_exact<'a>(&'a self) -> ExactBoxedMapIterator {
|
||||
Box::new(self.rect
|
||||
.iter()
|
||||
.map(|row| Box::new(row.into_iter()) as ChunkRowIterator<'a>))
|
||||
}
|
||||
}
|
||||
|
||||
impl Map for Chunk {
|
||||
fn rows<'a>(&'a self) -> BoxedMapIterator {
|
||||
Box::new(self.rect
|
||||
.iter()
|
||||
.map(|row| Box::new(row.into_iter()) as ChunkRowIterator<'a>))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Chunk {
|
||||
type Item=ChunkRowIterator<'a>;
|
||||
type IntoIter=ExactBoxedMapIterator<'a>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.rows_exact()
|
||||
}
|
||||
}
|
||||
|
||||
const WORLDDIM: usize = 8;
|
||||
pub type WorldRow = [Chunk; WORLDDIM];
|
||||
pub type WorldRect = [WorldRow; WORLDDIM];
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct World {
|
||||
pub rect: WorldRect,
|
||||
}
|
||||
|
||||
impl Map for World {
|
||||
fn rows<'a>(&'a self) -> BoxedMapIterator {
|
||||
let flipped = self.rect.iter().map(|cr| cr.into_iter().transpose());
|
||||
Box::new(flipped.flatten()
|
||||
.map(|r| Box::new(r.flatten()) as ChunkRowIterator<'a>))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user