Compare commits
2 commits
48419b4674
...
5a6be3194e
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a6be3194e | |||
| c572fcb0e2 |
6 changed files with 312 additions and 50 deletions
|
|
@ -1,4 +1,8 @@
|
||||||
use factorio_blueprint::layout::Layout;
|
use factorio_blueprint::{
|
||||||
|
belt_finding::{conflict_avoidance::ConflictAvoidance, Problem},
|
||||||
|
common::visualize::Visualize,
|
||||||
|
layout::Layout,
|
||||||
|
};
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -15,14 +19,29 @@ fn main() {
|
||||||
|
|
||||||
let p = serde_yaml::from_reader(file).unwrap();
|
let p = serde_yaml::from_reader(file).unwrap();
|
||||||
|
|
||||||
dbg!(&p);
|
|
||||||
|
|
||||||
for i in 0..1 {
|
for i in 0..1 {
|
||||||
let mut rng = rand::rngs::SmallRng::seed_from_u64(i);
|
let mut rng = rand::rngs::SmallRng::seed_from_u64(5);
|
||||||
|
|
||||||
let l = Layout::new(&p, &mut rng);
|
let l = Layout::new(&p, &mut rng);
|
||||||
|
|
||||||
println!("Seed: {i}, Score {}", l.score());
|
// let s = l.score();
|
||||||
l.print();
|
l.print_visualization();
|
||||||
|
|
||||||
|
let mut p = Problem::from_layout(&l);
|
||||||
|
p.print();
|
||||||
|
p.find_path();
|
||||||
|
p.print();
|
||||||
|
let mut c = ConflictAvoidance::new(p);
|
||||||
|
|
||||||
|
c.remove_all_conflicts();
|
||||||
|
|
||||||
|
c.print();
|
||||||
|
// println!("Seed: {i}, Score {}", s);
|
||||||
|
|
||||||
|
// l.print_visualization();
|
||||||
|
// if s < min {
|
||||||
|
// min = s;
|
||||||
|
// min_l = Some(l);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
layout.yml
12
layout.yml
|
|
@ -1,6 +1,6 @@
|
||||||
size:
|
size:
|
||||||
x: 10
|
x: 15
|
||||||
y: 10
|
y: 15
|
||||||
blocks:
|
blocks:
|
||||||
- size:
|
- size:
|
||||||
x: 3
|
x: 3
|
||||||
|
|
@ -9,7 +9,7 @@ blocks:
|
||||||
- offset:
|
- offset:
|
||||||
x: 1
|
x: 1
|
||||||
y: 1
|
y: 1
|
||||||
dir: Down
|
dir: Up
|
||||||
output:
|
output:
|
||||||
- offset:
|
- offset:
|
||||||
x: 1
|
x: 1
|
||||||
|
|
@ -31,10 +31,14 @@ blocks:
|
||||||
- offset:
|
- offset:
|
||||||
x: 0
|
x: 0
|
||||||
y: 1
|
y: 1
|
||||||
dir: Left
|
dir: Right
|
||||||
output:
|
output:
|
||||||
connections:
|
connections:
|
||||||
- startblock: 1
|
- startblock: 1
|
||||||
startpoint: 0
|
startpoint: 0
|
||||||
endblock: 0
|
endblock: 0
|
||||||
endpoint: 0
|
endpoint: 0
|
||||||
|
- startblock: 0
|
||||||
|
startpoint: 0
|
||||||
|
endblock: 2
|
||||||
|
endpoint: 0
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::common::color::COLORS;
|
use crate::common::color::COLORS;
|
||||||
use crate::graph::wheighted_graph::WheightedGraph;
|
use crate::graph::wheighted_graph::WheightedGraph;
|
||||||
|
use crate::layout::Layout;
|
||||||
use crate::misc::Map;
|
use crate::misc::Map;
|
||||||
use crate::{
|
use crate::{
|
||||||
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
|
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
|
||||||
|
|
@ -36,6 +37,49 @@ impl Problem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_layout(l: &Layout) -> Self {
|
||||||
|
let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
|
||||||
|
|
||||||
|
for ((pos, dir), b) in l.blocks.iter().zip(l.problem.blocks.iter()) {
|
||||||
|
let (npos, nsize) = Layout::normalize_pos((b, *pos, *dir));
|
||||||
|
|
||||||
|
let nend = npos + nsize - Position::new(1, 1);
|
||||||
|
|
||||||
|
p.set_blocked_range(
|
||||||
|
npos.x as usize,
|
||||||
|
npos.y as usize,
|
||||||
|
nend.x as usize,
|
||||||
|
nend.y as usize,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in &l.problem.connections {
|
||||||
|
let startpos = Layout::transform(
|
||||||
|
l.blocks[c.startblock].0,
|
||||||
|
l.blocks[c.startblock].1,
|
||||||
|
l.problem.blocks[c.startblock].output[c.startpoint].offset,
|
||||||
|
);
|
||||||
|
let startdir = Layout::rotate(
|
||||||
|
l.problem.blocks[c.startblock].output[c.startpoint].dir,
|
||||||
|
l.blocks[c.startblock].1,
|
||||||
|
);
|
||||||
|
let enddir = Layout::rotate(
|
||||||
|
l.problem.blocks[c.endblock].input[c.endpoint].dir,
|
||||||
|
l.blocks[c.endblock].1,
|
||||||
|
);
|
||||||
|
let endpos = Layout::transform(
|
||||||
|
l.blocks[c.endblock].0,
|
||||||
|
l.blocks[c.endblock].1,
|
||||||
|
l.problem.blocks[c.endblock].input[c.endpoint].offset,
|
||||||
|
)
|
||||||
|
.in_direction(&enddir, -1);
|
||||||
|
p.add_connection((startpos, startdir), (endpos, enddir));
|
||||||
|
}
|
||||||
|
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
|
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
|
||||||
self.start.push(start);
|
self.start.push(start);
|
||||||
self.end.push(end);
|
self.end.push(end);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod direction;
|
pub mod direction;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
pub mod visualize;
|
||||||
|
|
|
||||||
181
src/common/visualize.rs
Normal file
181
src/common/visualize.rs
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
use termcolor::{ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub trait Visualize {
|
||||||
|
fn visualize(&self) -> Visualization;
|
||||||
|
|
||||||
|
fn print_visualization(&self) {
|
||||||
|
let v = self.visualize();
|
||||||
|
|
||||||
|
let stdout = &mut StandardStream::stdout(termcolor::ColorChoice::Always);
|
||||||
|
|
||||||
|
let width_digits = (v.size.x - 1).ilog10() + 1;
|
||||||
|
let height_digits = (v.size.y - 1).ilog10() + 1;
|
||||||
|
|
||||||
|
// print header
|
||||||
|
for i in 0..width_digits {
|
||||||
|
let d = width_digits - i - 1;
|
||||||
|
|
||||||
|
//padding
|
||||||
|
for _ in 0..height_digits {
|
||||||
|
write!(stdout, " ").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in 0..v.size.x {
|
||||||
|
let digits = x / (i32::pow(10, d));
|
||||||
|
if digits == 0 && d > 0 {
|
||||||
|
write!(stdout, " ").unwrap();
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}",
|
||||||
|
char::from_u32((digits % 10) as u32 + 48).unwrap()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(stdout).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in 0..v.size.y {
|
||||||
|
write!(stdout, "{:1$}", y, height_digits as usize).unwrap();
|
||||||
|
|
||||||
|
for x in 0..v.size.x {
|
||||||
|
if let Some((s, fg, bg)) = v.symbols.get(&Position::new(x, y)) {
|
||||||
|
let mut c = ColorSpec::new();
|
||||||
|
c.set_fg(fg.as_ref().map(|c| termcolor::Color::Rgb(c.r, c.g, c.b)));
|
||||||
|
c.set_bg(bg.as_ref().map(|c| termcolor::Color::Rgb(c.r, c.g, c.b)));
|
||||||
|
stdout.set_color(&c).unwrap();
|
||||||
|
write!(stdout, "{:1}", s.get_str()).unwrap();
|
||||||
|
stdout.reset().unwrap();
|
||||||
|
} else {
|
||||||
|
write!(stdout, " ").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(stdout, "{:1$}", y, height_digits as usize).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..width_digits {
|
||||||
|
let d = width_digits - i - 1;
|
||||||
|
|
||||||
|
//padding
|
||||||
|
for _ in 0..height_digits {
|
||||||
|
write!(stdout, " ").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in 0..v.size.x {
|
||||||
|
let digits = x / (i32::pow(10, d));
|
||||||
|
if digits == 0 && d > 0 {
|
||||||
|
write!(stdout, " ").unwrap();
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}",
|
||||||
|
char::from_u32((digits % 10) as u32 + 48).unwrap()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(stdout).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Symbol {
|
||||||
|
Arrow(Direction),
|
||||||
|
ArrowEnter(Direction),
|
||||||
|
ArrowExit(Direction),
|
||||||
|
Char(&'static str),
|
||||||
|
Block,
|
||||||
|
Space,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
fn get_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Symbol::Arrow(dir) => match dir {
|
||||||
|
Direction::Up => "↑",
|
||||||
|
Direction::Right => "→",
|
||||||
|
Direction::Down => "↓",
|
||||||
|
Direction::Left => "←",
|
||||||
|
},
|
||||||
|
Symbol::ArrowEnter(dir) => match dir {
|
||||||
|
Direction::Up => "↟",
|
||||||
|
Direction::Right => "↠",
|
||||||
|
Direction::Down => "↡",
|
||||||
|
Direction::Left => "↞",
|
||||||
|
},
|
||||||
|
Symbol::ArrowExit(dir) => match dir {
|
||||||
|
Direction::Up => "↥",
|
||||||
|
Direction::Right => "↦",
|
||||||
|
Direction::Down => "↧",
|
||||||
|
Direction::Left => "↤",
|
||||||
|
},
|
||||||
|
Symbol::Char(c) => c.split_at(1).0,
|
||||||
|
Symbol::Block => "#",
|
||||||
|
Symbol::Space => " ",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_char(&self) -> char {
|
||||||
|
self.get_str().chars().next().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Visualization {
|
||||||
|
size: Position,
|
||||||
|
symbols: HashMap<Position, (Symbol, Option<Color>, Option<Color>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Color {
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Self { r, g, b }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(i: usize) -> Self {
|
||||||
|
let c = [
|
||||||
|
Color::new(0xe6, 0x00, 0x49),
|
||||||
|
Color::new(0x0b, 0xb4, 0xff),
|
||||||
|
Color::new(0x50, 0xe9, 0x91),
|
||||||
|
Color::new(0xe6, 0xd8, 0x00),
|
||||||
|
Color::new(0x9b, 0x19, 0xf5),
|
||||||
|
Color::new(0xff, 0xa3, 0x00),
|
||||||
|
Color::new(0xdc, 0x0a, 0xb4),
|
||||||
|
Color::new(0xb3, 0xd4, 0xff),
|
||||||
|
Color::new(0x00, 0xbf, 0xa0),
|
||||||
|
];
|
||||||
|
|
||||||
|
c[i % c.len()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visualization {
|
||||||
|
pub fn new(size: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
size,
|
||||||
|
symbols: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_symbol(
|
||||||
|
&mut self,
|
||||||
|
pos: Position,
|
||||||
|
symbol: Symbol,
|
||||||
|
fg: Option<Color>,
|
||||||
|
bg: Option<Color>,
|
||||||
|
) {
|
||||||
|
self.symbols.insert(pos, (symbol, fg, bg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,45 +1,43 @@
|
||||||
|
use crate::common::visualize::{Color, Symbol, Visualization, Visualize};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{belt_finding::common::print_map, misc::Map};
|
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use termcolor::ColorSpec;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct Block {
|
pub(crate) struct Block {
|
||||||
size: Position,
|
pub(crate) size: Position,
|
||||||
input: Vec<Interface>,
|
pub(crate) input: Vec<Interface>,
|
||||||
output: Vec<Interface>,
|
pub(crate) output: Vec<Interface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct Interface {
|
pub(crate) struct Interface {
|
||||||
offset: Position,
|
pub(crate) offset: Position,
|
||||||
dir: Direction,
|
pub(crate) dir: Direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct Connection {
|
pub(crate) struct Connection {
|
||||||
startblock: usize,
|
pub(crate) startblock: usize,
|
||||||
startpoint: usize,
|
pub(crate) startpoint: usize,
|
||||||
endblock: usize,
|
pub(crate) endblock: usize,
|
||||||
endpoint: usize,
|
pub(crate) endpoint: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Problem {
|
pub struct Problem {
|
||||||
size: Position,
|
pub(crate) size: Position,
|
||||||
blocks: Vec<Block>,
|
pub(crate) blocks: Vec<Block>,
|
||||||
connections: Vec<Connection>,
|
pub(crate) connections: Vec<Connection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct BlockHandle(usize);
|
pub struct BlockHandle(usize);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Layout<'a> {
|
pub struct Layout<'a> {
|
||||||
problem: &'a Problem,
|
pub(crate) problem: &'a Problem,
|
||||||
blocks: Vec<(Position, Direction)>,
|
pub(crate) blocks: Vec<(Position, Direction)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Problem {
|
impl Problem {
|
||||||
|
|
@ -145,7 +143,9 @@ impl Layout<'_> {
|
||||||
|
|
||||||
/// Mutate existing layout, creating a valid layout
|
/// Mutate existing layout, creating a valid layout
|
||||||
pub fn mutate<R: Rng + ?Sized>(&self, rng: &mut R) -> Self {
|
pub fn mutate<R: Rng + ?Sized>(&self, rng: &mut R) -> Self {
|
||||||
todo!()
|
let s = self.clone();
|
||||||
|
|
||||||
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collision(
|
fn collision(
|
||||||
|
|
@ -161,7 +161,7 @@ impl Layout<'_> {
|
||||||
&& npos1.y + nsize1.y > npos2.y
|
&& npos1.y + nsize1.y > npos2.y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_pos(block: (&Block, Position, Direction)) -> (Position, Position) {
|
pub(crate) fn normalize_pos(block: (&Block, Position, Direction)) -> (Position, Position) {
|
||||||
let npos = match block.2 {
|
let npos = match block.2 {
|
||||||
Direction::Up => block.1,
|
Direction::Up => block.1,
|
||||||
Direction::Right => block.1.in_direction(&Direction::Left, block.0.size.y - 1),
|
Direction::Right => block.1.in_direction(&Direction::Left, block.0.size.y - 1),
|
||||||
|
|
@ -200,7 +200,7 @@ impl Layout<'_> {
|
||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform(pos: Position, dir: Direction, offset: Position) -> Position {
|
pub(crate) fn transform(pos: Position, dir: Direction, offset: Position) -> Position {
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up => pos + offset,
|
Direction::Up => pos + offset,
|
||||||
Direction::Right => pos + Position::new(-offset.y, offset.x),
|
Direction::Right => pos + Position::new(-offset.y, offset.x),
|
||||||
|
|
@ -209,9 +209,28 @@ impl Layout<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(&self) {
|
pub(crate) fn rotate(dir: Direction, rot: Direction) -> Direction {
|
||||||
let mut m: Map<Option<(usize, &str)>> =
|
match (rot, dir) {
|
||||||
Map::new(self.problem.size.x as usize, self.problem.size.y as usize);
|
(Direction::Up, _) => dir,
|
||||||
|
(Direction::Right, Direction::Up) => Direction::Right,
|
||||||
|
(Direction::Right, Direction::Right) => Direction::Down,
|
||||||
|
(Direction::Right, Direction::Down) => Direction::Left,
|
||||||
|
(Direction::Right, Direction::Left) => Direction::Up,
|
||||||
|
(Direction::Down, Direction::Up) => Direction::Down,
|
||||||
|
(Direction::Down, Direction::Right) => Direction::Left,
|
||||||
|
(Direction::Down, Direction::Down) => Direction::Up,
|
||||||
|
(Direction::Down, Direction::Left) => Direction::Right,
|
||||||
|
(Direction::Left, Direction::Up) => Direction::Left,
|
||||||
|
(Direction::Left, Direction::Right) => Direction::Up,
|
||||||
|
(Direction::Left, Direction::Down) => Direction::Right,
|
||||||
|
(Direction::Left, Direction::Left) => Direction::Down,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Visualize for Layout<'a> {
|
||||||
|
fn visualize(&self) -> Visualization {
|
||||||
|
let mut v = Visualization::new(self.problem.size);
|
||||||
|
|
||||||
for (i, ((p, d), b)) in self
|
for (i, ((p, d), b)) in self
|
||||||
.blocks
|
.blocks
|
||||||
|
|
@ -219,39 +238,33 @@ impl Layout<'_> {
|
||||||
.zip(self.problem.blocks.iter())
|
.zip(self.problem.blocks.iter())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
|
let c = Color::index(i);
|
||||||
|
|
||||||
let (npos, nsize) = Self::normalize_pos((b, *p, *d));
|
let (npos, nsize) = Self::normalize_pos((b, *p, *d));
|
||||||
|
|
||||||
for x in npos.x..(npos.x + nsize.x) {
|
for x in npos.x..(npos.x + nsize.x) {
|
||||||
for y in npos.y..(npos.y + nsize.y) {
|
for y in npos.y..(npos.y + nsize.y) {
|
||||||
m.set(x as usize, y as usize, Some((i, "#")));
|
v.add_symbol(Position::new(x, y), Symbol::Block, Some(c), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = Self::transform(*p, *d, Position::new(0, 0));
|
let pos = Self::transform(*p, *d, Position::new(0, 0));
|
||||||
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "X")));
|
v.add_symbol(pos, Symbol::Char("X"), Some(c), None);
|
||||||
|
|
||||||
for input in &b.input {
|
for input in &b.input {
|
||||||
let pos = Self::transform(*p, *d, input.offset);
|
let pos = Self::transform(*p, *d, input.offset);
|
||||||
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "i")));
|
v.add_symbol(pos, Symbol::Char("i"), Some(c), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
for output in &b.output {
|
for output in &b.output {
|
||||||
let pos = Self::transform(*p, *d, output.offset);
|
let pos = Self::transform(*p, *d, output.offset);
|
||||||
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "o")));
|
v.add_symbol(pos, Symbol::Char("o"), Some(c), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = print_map(self.problem.size.x, self.problem.size.y, |x, y| {
|
v
|
||||||
if let Some(i) = m.get(x as usize, y as usize) {
|
|
||||||
let mut color = ColorSpec::new();
|
|
||||||
color.set_fg(Some(crate::common::color::COLORS[i.0]));
|
|
||||||
(color, i.1)
|
|
||||||
} else {
|
|
||||||
(ColorSpec::new(), " ")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue