2024-10-07 01:16:52 +02:00
|
|
|
use crate::{draw_scaled_texture, Textures};
|
2024-10-04 22:10:00 +02:00
|
|
|
|
2024-10-03 22:59:49 +02:00
|
|
|
use super::tile::*;
|
2024-10-04 22:35:15 +02:00
|
|
|
use raylib::prelude::*;
|
2024-10-03 22:59:49 +02:00
|
|
|
|
|
|
|
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
|
|
|
pub struct Pos {
|
|
|
|
pub x: isize,
|
|
|
|
pub y: isize,
|
|
|
|
}
|
|
|
|
|
2024-10-05 20:22:18 +02:00
|
|
|
impl Pos {
|
2024-10-06 12:39:36 +02:00
|
|
|
pub const fn to_vec(self) -> Vector2 {
|
2024-10-05 20:22:18 +02:00
|
|
|
Vector2 {
|
|
|
|
x: self.x as f32,
|
|
|
|
y: self.y as f32,
|
|
|
|
}
|
|
|
|
}
|
2024-10-07 15:11:53 +02:00
|
|
|
|
|
|
|
pub fn min(self, other: Self) -> Self {
|
|
|
|
Self {
|
|
|
|
x: self.x.min(other.x),
|
|
|
|
y: self.y.min(other.y),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn max(self, other: Self) -> Self {
|
|
|
|
Self {
|
|
|
|
x: self.x.max(other.x),
|
|
|
|
y: self.y.max(other.y),
|
|
|
|
}
|
|
|
|
}
|
2024-10-05 20:22:18 +02:00
|
|
|
}
|
|
|
|
|
2024-10-03 22:59:49 +02:00
|
|
|
impl From<(usize, usize)> for Pos {
|
|
|
|
fn from(value: (usize, usize)) -> Self {
|
|
|
|
Self {
|
|
|
|
x: value.0 as isize,
|
|
|
|
y: value.1 as isize,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-05 15:34:58 +02:00
|
|
|
impl From<Vector2> for Pos {
|
|
|
|
fn from(vec: Vector2) -> Self {
|
|
|
|
Self {
|
|
|
|
x: vec.x as isize,
|
|
|
|
y: vec.y as isize,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-04 22:10:00 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2024-10-03 22:59:49 +02:00
|
|
|
pub struct Board {
|
|
|
|
rows: Vec<Vec<Tile>>,
|
|
|
|
width: usize,
|
|
|
|
height: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Board {
|
2024-10-05 19:45:25 +02:00
|
|
|
pub fn parse(source: &str) -> Self {
|
|
|
|
let mut rows = Vec::new();
|
|
|
|
|
|
|
|
let mut width = 0;
|
|
|
|
for line in source.lines() {
|
|
|
|
width = width.max(line.len());
|
|
|
|
let mut tiles = Vec::new();
|
|
|
|
for char in line.chars() {
|
|
|
|
tiles.push(Tile::from_char(char));
|
|
|
|
}
|
|
|
|
rows.push(tiles);
|
|
|
|
}
|
|
|
|
for line in &mut rows {
|
|
|
|
line.resize(width, Tile::Blank);
|
|
|
|
}
|
|
|
|
|
|
|
|
Board::new(rows)
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:24:37 +02:00
|
|
|
pub fn to_string(&self) -> String {
|
2024-10-06 16:00:12 +02:00
|
|
|
let mut out = String::new();
|
2024-10-06 22:24:37 +02:00
|
|
|
for row in &self.rows {
|
|
|
|
for tile in row {
|
2024-10-06 16:00:12 +02:00
|
|
|
out.push(tile.to_char())
|
|
|
|
}
|
|
|
|
out.push('\n');
|
|
|
|
}
|
|
|
|
out
|
|
|
|
}
|
|
|
|
|
2024-10-03 22:59:49 +02:00
|
|
|
pub fn new_empty(width: usize, height: usize) -> Self {
|
|
|
|
let rows = vec![vec![Tile::Blank; width]; height];
|
|
|
|
Self {
|
|
|
|
rows,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new(rows: Vec<Vec<Tile>>) -> Self {
|
|
|
|
Self {
|
|
|
|
width: rows[0].len(),
|
|
|
|
height: rows.len(),
|
|
|
|
rows,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:24:37 +02:00
|
|
|
pub fn count_tiles(&self) -> usize {
|
|
|
|
let mut sum = 0;
|
|
|
|
for row in &self.rows {
|
|
|
|
for tile in row {
|
|
|
|
match tile {
|
|
|
|
Tile::Blank | Tile::Block => (),
|
|
|
|
_ => sum += 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sum
|
|
|
|
}
|
|
|
|
|
2024-10-06 23:30:59 +02:00
|
|
|
fn in_bounds(&self, p: Pos) -> bool {
|
2024-10-03 22:59:49 +02:00
|
|
|
p.x >= 0 && p.y >= 0 && p.x < self.width as isize && p.y < self.height as isize
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get(&self, p: Pos) -> Option<Tile> {
|
|
|
|
if self.in_bounds(p) {
|
|
|
|
Some(self.rows[p.y as usize][p.x as usize])
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_or_blank(&self, p: Pos) -> Tile {
|
|
|
|
if self.in_bounds(p) {
|
|
|
|
self.rows[p.y as usize][p.x as usize]
|
|
|
|
} else {
|
|
|
|
Tile::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-05 20:22:18 +02:00
|
|
|
pub fn get_mut(&mut self, p: Pos) -> Option<&mut Tile> {
|
|
|
|
if self.in_bounds(p) {
|
|
|
|
Some(&mut self.rows[p.y as usize][p.x as usize])
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-05 23:16:24 +02:00
|
|
|
pub fn get_blank_mut(&mut self, p: Pos) -> Option<&mut Tile> {
|
2024-10-03 22:59:49 +02:00
|
|
|
if self.in_bounds(p) {
|
2024-10-05 23:16:24 +02:00
|
|
|
let tile = &mut self.rows[p.y as usize][p.x as usize];
|
|
|
|
if tile == &Tile::Blank {
|
|
|
|
return Some(tile);
|
|
|
|
}
|
2024-10-03 22:59:49 +02:00
|
|
|
}
|
2024-10-05 23:16:24 +02:00
|
|
|
None
|
2024-10-03 22:59:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&mut self, p: Pos, tile: Tile) {
|
|
|
|
if self.in_bounds(p) {
|
|
|
|
self.rows[p.y as usize][p.x as usize] = tile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-07 20:01:00 +02:00
|
|
|
pub fn grow_to_include(&mut self, p: Pos) -> (isize, isize) {
|
|
|
|
let mut offset_x = 0;
|
|
|
|
let mut offset_y = 0;
|
2024-10-06 23:30:59 +02:00
|
|
|
if p.x < 0 {
|
2024-10-07 20:01:00 +02:00
|
|
|
let len = p.x.unsigned_abs() + 2;
|
2024-10-06 23:30:59 +02:00
|
|
|
for row in &mut self.rows {
|
|
|
|
let mut new_row = vec![Tile::Blank; len];
|
|
|
|
new_row.append(row);
|
|
|
|
*row = new_row;
|
|
|
|
}
|
2024-10-07 20:01:00 +02:00
|
|
|
offset_x = len;
|
2024-10-06 23:30:59 +02:00
|
|
|
self.width += len;
|
|
|
|
} else if p.x as usize >= self.width {
|
2024-10-07 20:01:00 +02:00
|
|
|
let new_width = p.x as usize + 3;
|
2024-10-06 23:30:59 +02:00
|
|
|
for row in &mut self.rows {
|
|
|
|
row.resize(new_width, Tile::Blank);
|
|
|
|
}
|
|
|
|
self.width = new_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.y < 0 {
|
2024-10-07 20:01:00 +02:00
|
|
|
let len = p.y.unsigned_abs() + 2;
|
2024-10-06 23:30:59 +02:00
|
|
|
let mut new_rows = vec![vec![Tile::Blank; self.width]; len];
|
|
|
|
new_rows.append(&mut self.rows);
|
|
|
|
self.rows = new_rows;
|
2024-10-07 20:01:00 +02:00
|
|
|
offset_y = len;
|
2024-10-06 23:30:59 +02:00
|
|
|
self.height += len;
|
2024-10-07 12:21:57 +02:00
|
|
|
} else if p.y as usize >= self.height {
|
2024-10-07 20:01:00 +02:00
|
|
|
let new_height = p.y as usize + 3;
|
2024-10-06 23:30:59 +02:00
|
|
|
self.rows.resize(new_height, vec![Tile::Blank; self.width]);
|
|
|
|
self.height = new_height;
|
|
|
|
}
|
2024-10-07 20:01:00 +02:00
|
|
|
(offset_x as isize, offset_y as isize)
|
2024-10-06 23:30:59 +02:00
|
|
|
}
|
|
|
|
|
2024-10-07 20:01:00 +02:00
|
|
|
pub fn trim_size(&mut self) -> (usize, usize) {
|
|
|
|
let (offset_x, offset_y);
|
2024-10-07 16:51:56 +02:00
|
|
|
// top
|
2024-10-07 12:44:15 +02:00
|
|
|
{
|
2024-10-07 16:51:56 +02:00
|
|
|
let mut n = 0;
|
|
|
|
while n < self.height && self.rows[n].iter().all(Tile::is_blank) {
|
|
|
|
n += 1;
|
2024-10-07 12:44:15 +02:00
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
let trim_top = n.saturating_sub(2);
|
2024-10-07 12:44:15 +02:00
|
|
|
for _ in 0..trim_top {
|
|
|
|
self.rows.remove(0);
|
|
|
|
}
|
2024-10-07 20:01:00 +02:00
|
|
|
offset_y = trim_top;
|
2024-10-07 12:44:15 +02:00
|
|
|
self.height -= trim_top;
|
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
// bottom
|
2024-10-07 12:44:15 +02:00
|
|
|
{
|
2024-10-07 16:51:56 +02:00
|
|
|
let mut n = 0;
|
|
|
|
while n < self.height && self.rows[self.height - n - 1].iter().all(Tile::is_blank) {
|
|
|
|
n += 1;
|
2024-10-07 12:44:15 +02:00
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
let trim_bottom = n.saturating_sub(2);
|
2024-10-07 12:44:15 +02:00
|
|
|
for _ in 0..trim_bottom {
|
|
|
|
self.rows.pop();
|
|
|
|
}
|
|
|
|
self.height -= trim_bottom;
|
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
// left
|
2024-10-07 12:44:15 +02:00
|
|
|
{
|
2024-10-07 16:51:56 +02:00
|
|
|
let mut n = 0;
|
|
|
|
while n < self.width && self.rows.iter().all(|row| row[n].is_blank()) {
|
|
|
|
n += 1;
|
2024-10-07 12:44:15 +02:00
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
let trim_left = n.saturating_sub(2);
|
2024-10-07 12:44:15 +02:00
|
|
|
for row in &mut self.rows {
|
|
|
|
for _ in 0..trim_left {
|
|
|
|
row.remove(0);
|
|
|
|
}
|
|
|
|
}
|
2024-10-07 20:01:00 +02:00
|
|
|
offset_x = trim_left;
|
2024-10-07 12:44:15 +02:00
|
|
|
self.width -= trim_left;
|
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
// right
|
2024-10-07 12:44:15 +02:00
|
|
|
{
|
2024-10-07 16:51:56 +02:00
|
|
|
let mut n = 0;
|
|
|
|
while n < self.width && self.rows.iter().all(|r| r[self.width - n - 1].is_blank()) {
|
|
|
|
n += 1;
|
2024-10-07 12:44:15 +02:00
|
|
|
}
|
2024-10-07 16:51:56 +02:00
|
|
|
let trim_right = n.saturating_sub(2);
|
2024-10-07 12:44:15 +02:00
|
|
|
for row in &mut self.rows {
|
|
|
|
for _ in 0..trim_right {
|
|
|
|
row.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.width -= trim_right;
|
|
|
|
}
|
2024-10-07 20:01:00 +02:00
|
|
|
(offset_x, offset_y)
|
2024-10-07 12:44:15 +02:00
|
|
|
}
|
|
|
|
|
2024-10-03 22:59:49 +02:00
|
|
|
pub fn width(&self) -> usize {
|
|
|
|
self.width
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn height(&self) -> usize {
|
|
|
|
self.height
|
|
|
|
}
|
2024-10-07 17:57:07 +02:00
|
|
|
|
|
|
|
pub fn get_marbles(&self) -> Vec<Pos> {
|
|
|
|
let mut out = Vec::new();
|
|
|
|
for y in 0..self.height {
|
|
|
|
for x in 0..self.width {
|
|
|
|
if let Tile::Marble { value: _, dir: _ } = self.rows[y][x] {
|
2024-10-07 20:01:00 +02:00
|
|
|
out.push((x, y).into());
|
2024-10-07 17:57:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out
|
|
|
|
}
|
2024-10-04 22:10:00 +02:00
|
|
|
|
2024-10-05 17:53:23 +02:00
|
|
|
pub fn draw(&self, d: &mut RaylibDrawHandle, textures: &Textures, offset: Vector2, zoom: i32) {
|
2024-10-04 22:10:00 +02:00
|
|
|
let tile_size = 16 << zoom;
|
2024-10-07 00:01:02 +02:00
|
|
|
|
2024-10-07 00:08:06 +02:00
|
|
|
let start_x = (-offset.x as i32) / tile_size - 1;
|
2024-10-07 00:01:02 +02:00
|
|
|
let tile_width = d.get_screen_width() / tile_size + 2;
|
2024-10-07 00:08:06 +02:00
|
|
|
let start_y = (-offset.y as i32) / tile_size - 1;
|
2024-10-07 00:01:02 +02:00
|
|
|
let tile_height = d.get_screen_height() / tile_size + 2;
|
|
|
|
|
|
|
|
for x in start_x..(start_x + tile_width) {
|
|
|
|
for y in start_y..(start_y + tile_height) {
|
2024-10-07 20:01:00 +02:00
|
|
|
let tx = x as usize;
|
|
|
|
let ty = y as usize;
|
2024-10-07 12:08:30 +02:00
|
|
|
let px = x * tile_size + offset.x as i32;
|
|
|
|
let py = y * tile_size + offset.y as i32;
|
2024-10-07 00:08:06 +02:00
|
|
|
if self.in_bounds((tx, ty).into()) {
|
2024-10-07 00:01:02 +02:00
|
|
|
let tile = self.rows[ty][tx];
|
2024-10-07 00:08:06 +02:00
|
|
|
let texname = tile.texture();
|
2024-10-07 00:20:52 +02:00
|
|
|
if texname.is_empty() {
|
2024-10-07 00:08:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let texture = textures.get(&texname);
|
2024-10-07 01:16:52 +02:00
|
|
|
draw_scaled_texture(d, texture, px, py, (1 << zoom) as f32);
|
2024-10-07 12:08:30 +02:00
|
|
|
} else {
|
|
|
|
d.draw_rectangle(px, py, tile_size, tile_size, Color::new(0, 0, 0, 80));
|
2024-10-07 00:01:02 +02:00
|
|
|
}
|
2024-10-04 22:10:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-10-03 22:59:49 +02:00
|
|
|
}
|