rust_sc2/
pixel_map.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Data structures, used to store map data.
#![allow(missing_docs)]

use crate::{geometry::Point2, FromProto};
use ndarray::Array2;
use num_traits::FromPrimitive;
use sc2_proto::common::ImageData;
use std::{
	fmt,
	ops::{Index, IndexMut},
};

/// 2-Dimensional Array of pixels, where each pixel is `Set` or is `Empty`.
pub type PixelMap = Array2<Pixel>;
/// 2-Dimensional Array of bytes.
pub type ByteMap = Array2<u8>;
/// 2-Dimensional Array that represents visibility.
pub type VisibilityMap = Array2<Visibility>;

impl<T> Index<Point2> for Array2<T> {
	type Output = T;

	#[inline]
	fn index(&self, pos: Point2) -> &Self::Output {
		&self[<(usize, usize)>::from(pos)]
	}
}
impl<T> IndexMut<Point2> for Array2<T> {
	#[inline]
	fn index_mut(&mut self, pos: Point2) -> &mut Self::Output {
		&mut self[<(usize, usize)>::from(pos)]
	}
}

fn to_binary(n: u8) -> Vec<Pixel> {
	match n {
		0 => vec![Pixel::Set; 8],
		255 => vec![Pixel::Empty; 8],
		_ => (0..8)
			.rev()
			.map(|x| Pixel::from_u8((n >> x) & 1).unwrap())
			.collect(),
	}
}

impl FromProto<&ImageData> for PixelMap {
	fn from_proto(grid: &ImageData) -> Self {
		let size = grid.get_size();
		Array2::from_shape_vec(
			(size.get_y() as usize, size.get_x() as usize),
			grid.get_data().iter().flat_map(|n| to_binary(*n)).collect(),
		)
		.expect("Can't create PixelMap")
		.reversed_axes()
	}
}
impl FromProto<&ImageData> for ByteMap {
	fn from_proto(grid: &ImageData) -> Self {
		let size = grid.get_size();
		Array2::from_shape_vec(
			(size.get_y() as usize, size.get_x() as usize),
			grid.get_data().iter().copied().collect(),
		)
		.expect("Can't create ByteMap")
		.reversed_axes()
	}
}
impl FromProto<&ImageData> for VisibilityMap {
	fn from_proto(grid: &ImageData) -> Self {
		let size = grid.get_size();
		Array2::from_shape_vec(
			(size.get_y() as usize, size.get_x() as usize),
			grid.get_data()
				.iter()
				.map(|n| {
					Visibility::from_u8(*n)
						.unwrap_or_else(|| panic!("enum Visibility has no variant with value: {}", n))
				})
				.collect(),
		)
		.expect("Can't create VisibilityMap")
		.reversed_axes()
	}
}

/// Base for the most 2d maps.
#[variant_checkers]
#[derive(FromPrimitive, ToPrimitive, Copy, Clone, PartialEq, Eq)]
pub enum Pixel {
	/// When pixel is set, this tile is obstacle (e.g. not pathable | not placeable)
	/// or has something on it (e.g. has creep).
	Set,
	/// When pixel is empty, this tile is free (e.g. pathable | placeable | no creep).
	Empty,
}
impl Default for Pixel {
	fn default() -> Self {
		Pixel::Empty
	}
}
impl fmt::Debug for Pixel {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		match self {
			Pixel::Empty => 0.fmt(f),
			Pixel::Set => 1.fmt(f),
		}
	}
}

/// Base for visibility maps.
#[variant_checkers]
#[derive(Debug, FromPrimitive, ToPrimitive, Copy, Clone, PartialEq, Eq)]
pub enum Visibility {
	/// Position is hidden (i.e. weren't explored before)
	Hidden,
	/// Position is in fog of war (i.e. was explored before, but not visible now)
	Fogged,
	/// Position is visible now.
	Visible,
	/// Position is fully hidden (i.e. terrain isn't visible, only darkness; only in campain and custom maps).
	FullHidden,
}
impl Visibility {
	pub fn is_explored(self) -> bool {
		!matches!(self, Visibility::Hidden)
	}
}
impl Default for Visibility {
	fn default() -> Self {
		Visibility::Hidden
	}
}