store grid as flat vec for faster access

This commit is contained in:
Crispy 2024-12-17 16:47:55 +01:00
parent 73a1c62f52
commit e6437ae9cf
2 changed files with 32 additions and 92 deletions

View file

@ -350,8 +350,7 @@ impl Editor {
}
fn save_blueprint(&mut self, selection: (Pos, Pos)) {
let mut board = self.get_selected_as_board(selection);
board.trim_size(0);
let board = self.get_selected_as_board(selection);
let id = get_free_id(&self.blueprints, Blueprint::id);
let mut blueprint = Blueprint::new(&board, id);
if !self.new_blueprint_name.is_empty() {
@ -1086,7 +1085,6 @@ impl Editor {
Tool::Mirror => self.set_tile(pos, Tile::Mirror(self.tool_mirror)),
Tool::Digits(_pos) => {
self.active_tool = Tool::Digits(Some(pos));
let tile = self.source_board.get_or_blank(pos);
if !matches!(tile, Tile::Open(OpenTile::Digit(_), _)) {
self.set_tile(pos, Tile::Open(OpenTile::Digit(0), Claim::Free));

View file

@ -8,7 +8,7 @@ use raylib::prelude::*;
#[derive(Debug, Clone, PartialEq)]
pub struct Board {
rows: Vec<Vec<Tile>>,
tiles: Vec<Tile>,
width: usize,
height: usize,
}
@ -26,7 +26,9 @@ impl Board {
let mut rows = Vec::new();
let mut width = 0;
let mut height = 0;
for line in source.lines() {
height += 1;
width = width.max(line.len());
let mut tiles = Vec::new();
for char in line.chars() {
@ -37,14 +39,20 @@ impl Board {
for line in &mut rows {
line.resize(width, Tile::BLANK);
}
let tiles = rows.into_iter().flatten().collect();
Board::new(rows)
Self {
tiles,
width,
height,
}
}
pub fn to_string(&self) -> String {
let mut out = String::new();
for row in &self.rows {
for tile in row {
for y in 0..self.height {
for x in 0..self.width {
let tile = self.get((x, y).into()).unwrap();
out.push(tile.to_char());
}
out.push('\n');
@ -53,9 +61,9 @@ impl Board {
}
pub fn new_empty(width: usize, height: usize) -> Self {
let rows = vec![vec![Tile::BLANK; width]; height];
let tiles = vec![Tile::BLANK; width * height];
Self {
rows,
tiles,
width,
height,
}
@ -63,28 +71,17 @@ impl Board {
pub fn new_single(tile: Tile) -> Self {
Self {
rows: vec![vec![tile]],
tiles: vec![tile],
width: 1,
height: 1,
}
}
pub fn new(rows: Vec<Vec<Tile>>) -> Self {
Self {
width: rows[0].len(),
height: rows.len(),
rows,
}
}
pub fn count_tiles(&self) -> usize {
let mut sum = 0;
for row in &self.rows {
for tile in row {
match tile {
Tile::Open(OpenTile::Blank, _) | Tile::Block => (),
_ => sum += 1,
}
for tile in &self.tiles {
if !matches!(tile, Tile::Open(OpenTile::Blank, _) | Tile::Block) {
sum += 1
}
}
sum
@ -94,9 +91,13 @@ impl Board {
p.x >= 0 && p.y >= 0 && p.x < self.width as PosInt && p.y < self.height as PosInt
}
fn get_unchecked(&self, p: Pos) -> Tile {
self.tiles[p.y as usize * self.width + p.x as usize]
}
pub fn get(&self, p: Pos) -> Option<Tile> {
if self.in_bounds(p) {
Some(self.rows[p.y as usize][p.x as usize])
Some(self.get_unchecked(p))
} else {
None
}
@ -104,7 +105,7 @@ impl Board {
pub fn get_or_blank(&self, p: Pos) -> Tile {
if self.in_bounds(p) {
self.rows[p.y as usize][p.x as usize]
self.get_unchecked(p)
} else {
Tile::BLANK
}
@ -112,7 +113,7 @@ impl Board {
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])
Some(&mut self.tiles[p.y as usize * self.width + p.x as usize])
} else {
None
}
@ -120,7 +121,7 @@ impl Board {
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;
self.tiles[p.y as usize * self.width + p.x as usize] = tile;
}
}
@ -148,73 +149,14 @@ impl Board {
out
}
pub fn trim_size(&mut self, margin: usize) -> (usize, usize) {
let (offset_x, offset_y);
// top
{
let mut n = 0;
while n < self.height && self.rows[n].iter().all(|t| t.is_blank()) {
n += 1;
}
let trim_top = n.saturating_sub(margin);
for _ in 0..trim_top {
self.rows.remove(0);
}
offset_y = trim_top;
self.height -= trim_top;
}
// bottom
{
let mut n = 0;
while n < self.height && self.rows[self.height - n - 1].iter().all(|t| t.is_blank()) {
n += 1;
}
let trim_bottom = n.saturating_sub(margin);
for _ in 0..trim_bottom {
self.rows.pop();
}
self.height -= trim_bottom;
}
// left
{
let mut n = 0;
while n < self.width && self.rows.iter().all(|row| row[n].is_blank()) {
n += 1;
}
let trim_left = n.saturating_sub(margin);
for row in &mut self.rows {
for _ in 0..trim_left {
row.remove(0);
}
}
offset_x = trim_left;
self.width -= trim_left;
}
// right
{
let mut n = 0;
while n < self.width && self.rows.iter().all(|r| r[self.width - n - 1].is_blank()) {
n += 1;
}
let trim_right = n.saturating_sub(margin);
for row in &mut self.rows {
for _ in 0..trim_right {
row.pop();
}
}
self.width -= trim_right;
}
(offset_x, offset_y)
}
pub fn grow(&mut self, deltas: &ResizeDeltas) {
let new_width = self.width + deltas.x_neg + deltas.x_pos;
let new_height = self.height + deltas.y_neg + deltas.y_pos;
let mut new_board = Board::new_empty(new_width, new_height);
for x in 0..self.width {
for y in 0..self.height {
let tile = self.rows[y][x];
new_board.rows[y + deltas.y_neg][x + deltas.x_neg] = tile;
let tile = self.get_unchecked((x, y).into());
new_board.set((x + deltas.x_neg, y + deltas.y_neg).into(), tile);
}
}
*self = new_board;
@ -226,8 +168,8 @@ impl Board {
let mut new_board = Board::new_empty(new_width, new_height);
for x in 0..new_width {
for y in 0..new_height {
let tile = self.rows[y + deltas.y_neg][x + deltas.x_neg];
new_board.rows[y][x] = tile;
let tile = self.get_unchecked((x + deltas.x_neg, y + deltas.y_neg).into());
new_board.set((x, y).into(), tile);
}
}
*self = new_board;
@ -245,7 +187,7 @@ impl Board {
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] {
if let Tile::Marble { value: _, dir: _ } = self.get_unchecked((x, y).into()) {
out.push((x, y).into());
}
}