changed standard to hard tabulations
This commit is contained in:
parent
0b7e0f847c
commit
5fde51e81b
6 changed files with 411 additions and 410 deletions
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hard_tabs = true
|
|
@ -2,63 +2,63 @@ use termion::{event::Key, input::TermRead, raw::IntoRawMode};
|
||||||
|
|
||||||
use super::grid::Grid;
|
use super::grid::Grid;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
io::{stdin, stdout},
|
io::{stdin, stdout},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum Move {
|
pub enum Move {
|
||||||
LEFT,
|
LEFT,
|
||||||
RIGHT,
|
RIGHT,
|
||||||
UP,
|
UP,
|
||||||
DOWN,
|
DOWN,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ControllerError {
|
pub enum ControllerError {
|
||||||
ExitSignal,
|
ExitSignal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ControllerError {
|
impl Display for ControllerError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let msg = match self {
|
let msg = match self {
|
||||||
ControllerError::ExitSignal => "received exit signal",
|
ControllerError::ExitSignal => "received exit signal",
|
||||||
};
|
};
|
||||||
f.write_str(msg)
|
f.write_str(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for ControllerError {}
|
impl Error for ControllerError {}
|
||||||
|
|
||||||
pub trait Controller {
|
pub trait Controller {
|
||||||
fn next_move(&mut self, grid: &Grid) -> Result<Move, ControllerError>;
|
fn next_move(&mut self, grid: &Grid) -> Result<Move, ControllerError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PlayerController {
|
pub struct PlayerController {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerController {
|
impl PlayerController {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller for PlayerController {
|
impl Controller for PlayerController {
|
||||||
fn next_move(&mut self, _grid: &Grid) -> Result<Move, ControllerError> {
|
fn next_move(&mut self, _grid: &Grid) -> Result<Move, ControllerError> {
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
let mut _stdout = stdout().into_raw_mode().unwrap();
|
let mut _stdout = stdout().into_raw_mode().unwrap();
|
||||||
for c in stdin.keys() {
|
for c in stdin.keys() {
|
||||||
let movement = match c.unwrap() {
|
let movement = match c.unwrap() {
|
||||||
Key::Char('q') => return Err(ControllerError::ExitSignal),
|
Key::Char('q') => return Err(ControllerError::ExitSignal),
|
||||||
Key::Left => Move::LEFT,
|
Key::Left => Move::LEFT,
|
||||||
Key::Right => Move::RIGHT,
|
Key::Right => Move::RIGHT,
|
||||||
Key::Up => Move::UP,
|
Key::Up => Move::UP,
|
||||||
Key::Down => Move::DOWN,
|
Key::Down => Move::DOWN,
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
return Ok(movement);
|
return Ok(movement);
|
||||||
}
|
}
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
356
src/lib/game.rs
356
src/lib/game.rs
|
@ -1,226 +1,226 @@
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
controller::{Controller, Move, PlayerController},
|
controller::{Controller, Move, PlayerController},
|
||||||
grid::Grid,
|
grid::Grid,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Rules {
|
pub struct Rules {
|
||||||
size: usize,
|
size: usize,
|
||||||
spawn_per_turn: usize,
|
spawn_per_turn: usize,
|
||||||
controller: Box<dyn Controller>,
|
controller: Box<dyn Controller>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rules {
|
impl Rules {
|
||||||
pub fn size(mut self, size: usize) -> Self {
|
pub fn size(mut self, size: usize) -> Self {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_per_turn(mut self, spawn_per_turn: usize) -> Self {
|
pub fn spawn_per_turn(mut self, spawn_per_turn: usize) -> Self {
|
||||||
self.spawn_per_turn = spawn_per_turn;
|
self.spawn_per_turn = spawn_per_turn;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Rules {
|
impl Default for Rules {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
size: 4,
|
size: 4,
|
||||||
spawn_per_turn: 1,
|
spawn_per_turn: 1,
|
||||||
controller: Box::new(PlayerController::new()),
|
controller: Box::new(PlayerController::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Err2048 {
|
pub enum Err2048 {
|
||||||
GridIsFull,
|
GridIsFull,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Err2048 {
|
impl Display for Err2048 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let msg = match self {
|
let msg = match self {
|
||||||
&Self::GridIsFull => "grid is full",
|
&Self::GridIsFull => "grid is full",
|
||||||
};
|
};
|
||||||
f.write_str(msg)
|
f.write_str(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for Err2048 {}
|
impl Error for Err2048 {}
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
board: Grid,
|
board: Grid,
|
||||||
controller: Box<dyn Controller>,
|
controller: Box<dyn Controller>,
|
||||||
spawn_per_turn: usize,
|
spawn_per_turn: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new(rules: Rules) -> Self {
|
pub fn new(rules: Rules) -> Self {
|
||||||
let Rules {
|
let Rules {
|
||||||
controller,
|
controller,
|
||||||
size,
|
size,
|
||||||
spawn_per_turn,
|
spawn_per_turn,
|
||||||
} = rules;
|
} = rules;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
board: Grid::new(size),
|
board: Grid::new(size),
|
||||||
controller,
|
controller,
|
||||||
spawn_per_turn,
|
spawn_per_turn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn turn(&mut self) -> Result<(), Box<dyn Error>> {
|
pub fn turn(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
for _ in 0..self.spawn_per_turn {
|
for _ in 0..self.spawn_per_turn {
|
||||||
self.spawn_random()?;
|
self.spawn_random()?;
|
||||||
}
|
}
|
||||||
self.refresh_display();
|
self.refresh_display();
|
||||||
let movement = self.controller.next_move(&self.board)?;
|
let movement = self.controller.next_move(&self.board)?;
|
||||||
self.perform_move(movement);
|
self.perform_move(movement);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_random(&mut self) -> Result<(), Box<dyn Error>> {
|
pub fn spawn_random(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let mut potentials = vec![];
|
let mut potentials = vec![];
|
||||||
for x in 0..self.board.size() {
|
for x in 0..self.board.size() {
|
||||||
for y in 0..self.board.size() {
|
for y in 0..self.board.size() {
|
||||||
if self.board.get((x, y)).unwrap().is_empty() {
|
if self.board.get((x, y)).unwrap().is_empty() {
|
||||||
potentials.push((x, y));
|
potentials.push((x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let potential_count = potentials.len() as f32;
|
let potential_count = potentials.len() as f32;
|
||||||
if potential_count == 0. {
|
if potential_count == 0. {
|
||||||
return Err(Err2048::GridIsFull.into());
|
return Err(Err2048::GridIsFull.into());
|
||||||
}
|
}
|
||||||
let random = rand::random::<f32>() * potential_count;
|
let random = rand::random::<f32>() * potential_count;
|
||||||
let index = random.floor() as usize;
|
let index = random.floor() as usize;
|
||||||
let (x, y) = potentials[index];
|
let (x, y) = potentials[index];
|
||||||
self.board.set((x, y), Some(1));
|
self.board.set((x, y), Some(1));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_display(&self) {
|
pub fn refresh_display(&self) {
|
||||||
super::clear_term();
|
super::clear_term();
|
||||||
let text = self.board.display();
|
let text = self.board.display();
|
||||||
println!("{text}");
|
println!("{text}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: macro peut être ?
|
// TODO: macro peut être ?
|
||||||
pub fn perform_move(&mut self, movement: Move) {
|
pub fn perform_move(&mut self, movement: Move) {
|
||||||
match movement {
|
match movement {
|
||||||
Move::LEFT => {
|
Move::LEFT => {
|
||||||
for y in 0..self.board.size() {
|
for y in 0..self.board.size() {
|
||||||
for x in 0..self.board.size() {
|
for x in 0..self.board.size() {
|
||||||
if !self.board.get((x, y)).unwrap().is_empty() {
|
if !self.board.get((x, y)).unwrap().is_empty() {
|
||||||
self.perform_linear_move((-1, 0), (x, y));
|
self.perform_linear_move((-1, 0), (x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Move::RIGHT => {
|
Move::RIGHT => {
|
||||||
for y in 0..self.board.size() {
|
for y in 0..self.board.size() {
|
||||||
for x in (0..self.board.size()).rev() {
|
for x in (0..self.board.size()).rev() {
|
||||||
if !self.board.get((x, y)).unwrap().is_empty() {
|
if !self.board.get((x, y)).unwrap().is_empty() {
|
||||||
self.perform_linear_move((1, 0), (x, y));
|
self.perform_linear_move((1, 0), (x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Move::UP => {
|
Move::UP => {
|
||||||
for x in 0..self.board.size() {
|
for x in 0..self.board.size() {
|
||||||
for y in 0..self.board.size() {
|
for y in 0..self.board.size() {
|
||||||
if !self.board.get((x, y)).unwrap().is_empty() {
|
if !self.board.get((x, y)).unwrap().is_empty() {
|
||||||
self.perform_linear_move((0, -1), (x, y));
|
self.perform_linear_move((0, -1), (x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Move::DOWN => {
|
Move::DOWN => {
|
||||||
for x in 0..self.board.size() {
|
for x in 0..self.board.size() {
|
||||||
for y in (0..self.board.size()).rev() {
|
for y in (0..self.board.size()).rev() {
|
||||||
if !self.board.get((x, y)).unwrap().is_empty() {
|
if !self.board.get((x, y)).unwrap().is_empty() {
|
||||||
self.perform_linear_move((0, 1), (x, y));
|
self.perform_linear_move((0, 1), (x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_linear_move(&mut self, direction: (isize, isize), tile_pos: (usize, usize)) {
|
fn perform_linear_move(&mut self, direction: (isize, isize), tile_pos: (usize, usize)) {
|
||||||
let mut displacement = Displacement::new(&mut self.board, tile_pos, direction);
|
let mut displacement = Displacement::new(&mut self.board, tile_pos, direction);
|
||||||
displacement.move_all();
|
displacement.move_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Displacement<'g> {
|
pub struct Displacement<'g> {
|
||||||
grid: &'g mut Grid,
|
grid: &'g mut Grid,
|
||||||
position: (usize, usize),
|
position: (usize, usize),
|
||||||
direction: (isize, isize),
|
direction: (isize, isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'g> Displacement<'g> {
|
impl<'g> Displacement<'g> {
|
||||||
pub fn new(grid: &'g mut Grid, position: (usize, usize), direction: (isize, isize)) -> Self {
|
pub fn new(grid: &'g mut Grid, position: (usize, usize), direction: (isize, isize)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
grid,
|
grid,
|
||||||
position,
|
position,
|
||||||
direction,
|
direction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_all(&mut self) {
|
pub fn move_all(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
let can_continue = self.move_once();
|
let can_continue = self.move_once();
|
||||||
if !can_continue {
|
if !can_continue {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_once(&mut self) -> bool {
|
fn move_once(&mut self) -> bool {
|
||||||
let current_pos = self.position.clone();
|
let current_pos = self.position.clone();
|
||||||
let current_value = self.grid.get_val(current_pos).unwrap();
|
let current_value = self.grid.get_val(current_pos).unwrap();
|
||||||
if let Some(next_pos) = self.get_next_pos() {
|
if let Some(next_pos) = self.get_next_pos() {
|
||||||
match self.grid.get_val(next_pos) {
|
match self.grid.get_val(next_pos) {
|
||||||
None => {
|
None => {
|
||||||
self.grid.move_tile(current_pos, next_pos);
|
self.grid.move_tile(current_pos, next_pos);
|
||||||
self.set_pos(next_pos);
|
self.set_pos(next_pos);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Some(value) if value == current_value => {
|
Some(value) if value == current_value => {
|
||||||
self.grid.move_tile(current_pos, next_pos);
|
self.grid.move_tile(current_pos, next_pos);
|
||||||
self.grid.set(next_pos, Some(value * 2));
|
self.grid.set(next_pos, Some(value * 2));
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Some(_) => false,
|
Some(_) => false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_pos(&self) -> Option<(usize, usize)> {
|
fn get_next_pos(&self) -> Option<(usize, usize)> {
|
||||||
let (current_x, current_y) = self.position.clone();
|
let (current_x, current_y) = self.position.clone();
|
||||||
let (dx, dy) = self.direction.clone();
|
let (dx, dy) = self.direction.clone();
|
||||||
if would_overflow(current_x, dx, self.grid.size() - 1)
|
if would_overflow(current_x, dx, self.grid.size() - 1)
|
||||||
|| would_overflow(current_y, dy, self.grid.size() - 1)
|
|| would_overflow(current_y, dy, self.grid.size() - 1)
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let next_x = (current_x as isize) + dx;
|
let next_x = (current_x as isize) + dx;
|
||||||
let next_y = (current_y as isize) + dy;
|
let next_y = (current_y as isize) + dy;
|
||||||
Some((next_x as usize, next_y as usize))
|
Some((next_x as usize, next_y as usize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pos(&mut self, (x, y): (usize, usize)) {
|
fn set_pos(&mut self, (x, y): (usize, usize)) {
|
||||||
self.position = (x, y);
|
self.position = (x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn would_overflow(n: usize, d: isize, max: usize) -> bool {
|
fn would_overflow(n: usize, d: isize, max: usize) -> bool {
|
||||||
let too_little = n == 0 && d == -1;
|
let too_little = n == 0 && d == -1;
|
||||||
let too_big = n == max && d == 1;
|
let too_big = n == max && d == 1;
|
||||||
too_little || too_big
|
too_little || too_big
|
||||||
}
|
}
|
||||||
|
|
382
src/lib/grid.rs
382
src/lib/grid.rs
|
@ -1,231 +1,231 @@
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
value: Option<usize>,
|
value: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tile {
|
impl Tile {
|
||||||
pub fn new_with_value(value: usize) -> Self {
|
pub fn new_with_value(value: usize) -> Self {
|
||||||
Self { value: Some(value) }
|
Self { value: Some(value) }
|
||||||
}
|
}
|
||||||
pub fn new_empty() -> Self {
|
pub fn new_empty() -> Self {
|
||||||
Self { value: None }
|
Self { value: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> Option<usize> {
|
pub fn value(&self) -> Option<usize> {
|
||||||
self.value.clone()
|
self.value.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
if let Some(_) = self.value {
|
if let Some(_) = self.value {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// displayability
|
/// displayability
|
||||||
///
|
///
|
||||||
impl Tile {
|
impl Tile {
|
||||||
const TILE_LENGTH: usize = 7;
|
const TILE_LENGTH: usize = 7;
|
||||||
const TILE_HEIGHT: usize = 3;
|
const TILE_HEIGHT: usize = 3;
|
||||||
|
|
||||||
pub fn display(&self) -> String {
|
pub fn display(&self) -> String {
|
||||||
match self.value {
|
match self.value {
|
||||||
Some(value) => Self::display_number(value),
|
Some(value) => Self::display_number(value),
|
||||||
None => [
|
None => [
|
||||||
// empty tile
|
// empty tile
|
||||||
" ", " ", " ",
|
" ", " ", " ",
|
||||||
]
|
]
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_number(value: usize) -> String {
|
pub fn display_number(value: usize) -> String {
|
||||||
let result = [
|
let result = [
|
||||||
// number tile
|
// number tile
|
||||||
"┌─────┐",
|
"┌─────┐",
|
||||||
&Self::pad_both(value.to_string(), Self::TILE_LENGTH),
|
&Self::pad_both(value.to_string(), Self::TILE_LENGTH),
|
||||||
"└─────┘",
|
"└─────┘",
|
||||||
]
|
]
|
||||||
.join("\n");
|
.join("\n");
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pad_both(text: String, length: usize) -> String {
|
fn pad_both(text: String, length: usize) -> String {
|
||||||
let mut text = text;
|
let mut text = text;
|
||||||
while text.len() < length {
|
while text.len() < length {
|
||||||
text = format!(" {text} ");
|
text = format!(" {text} ");
|
||||||
}
|
}
|
||||||
if text.len() > length {
|
if text.len() > length {
|
||||||
(&text)[..length].to_string()
|
(&text)[..length].to_string()
|
||||||
} else {
|
} else {
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
size: usize,
|
size: usize,
|
||||||
tiles: Vec<Vec<Tile>>,
|
tiles: Vec<Vec<Tile>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Grid {
|
impl Grid {
|
||||||
///
|
///
|
||||||
/// constructor
|
/// constructor
|
||||||
///
|
///
|
||||||
pub fn new(size: usize) -> Self {
|
pub fn new(size: usize) -> Self {
|
||||||
let tiles = (0..size)
|
let tiles = (0..size)
|
||||||
.map(|_| (0..size).map(|_| Tile::new_empty()).collect())
|
.map(|_| (0..size).map(|_| Tile::new_empty()).collect())
|
||||||
.collect();
|
.collect();
|
||||||
Self { size, tiles }
|
Self { size, tiles }
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// set the value of the tile at the selected position
|
/// set the value of the tile at the selected position
|
||||||
///
|
///
|
||||||
pub fn set(&mut self, (x, y): (usize, usize), value: Option<usize>) {
|
pub fn set(&mut self, (x, y): (usize, usize), value: Option<usize>) {
|
||||||
self.tiles[y][x] = if let Some(value) = value {
|
self.tiles[y][x] = if let Some(value) = value {
|
||||||
Tile::new_with_value(value)
|
Tile::new_with_value(value)
|
||||||
} else {
|
} else {
|
||||||
Tile::new_empty()
|
Tile::new_empty()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// get a tile if the position is in the grid
|
/// get a tile if the position is in the grid
|
||||||
///
|
///
|
||||||
pub fn get(&self, (x, y): (usize, usize)) -> Option<&Tile> {
|
pub fn get(&self, (x, y): (usize, usize)) -> Option<&Tile> {
|
||||||
match self.tiles.get(y).map(|row| row.get(x)) {
|
match self.tiles.get(y).map(|row| row.get(x)) {
|
||||||
Some(Some(tile)) => Some(tile),
|
Some(Some(tile)) => Some(tile),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// get the value of a tile if the position is in the grid and the tile has a value
|
/// get the value of a tile if the position is in the grid and the tile has a value
|
||||||
///
|
///
|
||||||
pub fn get_val(&self, (x, y): (usize, usize)) -> Option<usize> {
|
pub fn get_val(&self, (x, y): (usize, usize)) -> Option<usize> {
|
||||||
match self.get((x, y)).map(|tile| tile.value()) {
|
match self.get((x, y)).map(|tile| tile.value()) {
|
||||||
Some(Some(value)) => Some(value),
|
Some(Some(value)) => Some(value),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// get the size of the grid
|
/// get the size of the grid
|
||||||
///
|
///
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// move a tile over another one, replace the previously occupied place by an empty tile and overrides the destination
|
/// move a tile over another one, replace the previously occupied place by an empty tile and overrides the destination
|
||||||
///
|
///
|
||||||
pub fn move_tile(&mut self, (src_x, src_y): (usize, usize), (dst_x, dst_y): (usize, usize)) {
|
pub fn move_tile(&mut self, (src_x, src_y): (usize, usize), (dst_x, dst_y): (usize, usize)) {
|
||||||
let src = self.tiles[src_y][src_x].clone();
|
let src = self.tiles[src_y][src_x].clone();
|
||||||
self.tiles[dst_y][dst_x] = src;
|
self.tiles[dst_y][dst_x] = src;
|
||||||
self.tiles[src_y][src_x] = Tile::new_empty();
|
self.tiles[src_y][src_x] = Tile::new_empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// displayability
|
/// displayability
|
||||||
///
|
///
|
||||||
impl Grid {
|
impl Grid {
|
||||||
/// 0: '┘'
|
/// 0: '┘'
|
||||||
///
|
///
|
||||||
/// 1: '┐'
|
/// 1: '┐'
|
||||||
///
|
///
|
||||||
/// 2: '┌'
|
/// 2: '┌'
|
||||||
///
|
///
|
||||||
/// 3: '└'
|
/// 3: '└'
|
||||||
///
|
///
|
||||||
/// 4: '┼'
|
/// 4: '┼'
|
||||||
///
|
///
|
||||||
/// 5: '─'
|
/// 5: '─'
|
||||||
///
|
///
|
||||||
/// 6: '├'
|
/// 6: '├'
|
||||||
///
|
///
|
||||||
/// 7: '┤'
|
/// 7: '┤'
|
||||||
///
|
///
|
||||||
/// 8: '┴'
|
/// 8: '┴'
|
||||||
///
|
///
|
||||||
/// 9: '┬'
|
/// 9: '┬'
|
||||||
///
|
///
|
||||||
/// 10: '│'
|
/// 10: '│'
|
||||||
const DISPLAY_CHAR: [&'static str; 11] =
|
const DISPLAY_CHAR: [&'static str; 11] =
|
||||||
["┘", "┐", "┌", "└", "┼", "─", "├", "┤", "┴", "┬", "│"];
|
["┘", "┐", "┌", "└", "┼", "─", "├", "┤", "┴", "┬", "│"];
|
||||||
|
|
||||||
///
|
///
|
||||||
/// returns a string of multiple lines representing the grid
|
/// returns a string of multiple lines representing the grid
|
||||||
///
|
///
|
||||||
pub fn display(&self) -> String {
|
pub fn display(&self) -> String {
|
||||||
let tiles: Vec<Vec<_>> = self
|
let tiles: Vec<Vec<_>> = self
|
||||||
.tiles
|
.tiles
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| row.iter().map(|tile| tile.display()).collect())
|
.map(|row| row.iter().map(|tile| tile.display()).collect())
|
||||||
.collect();
|
.collect();
|
||||||
let row_representations: Vec<_> = tiles
|
let row_representations: Vec<_> = tiles
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row_representation| {
|
.map(|row_representation| {
|
||||||
let mut row_lines = (0..Tile::TILE_HEIGHT).map(|_| vec![]).collect::<Vec<_>>();
|
let mut row_lines = (0..Tile::TILE_HEIGHT).map(|_| vec![]).collect::<Vec<_>>();
|
||||||
// push every item lines in [`row_lines`]
|
// push every item lines in [`row_lines`]
|
||||||
for item_representation in row_representation {
|
for item_representation in row_representation {
|
||||||
item_representation
|
item_representation
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(row_lines.iter_mut())
|
.zip(row_lines.iter_mut())
|
||||||
.for_each(|(item_line, row_line)| row_line.push(item_line.to_string()));
|
.for_each(|(item_line, row_line)| row_line.push(item_line.to_string()));
|
||||||
}
|
}
|
||||||
// join lines of [`row_lines`]
|
// join lines of [`row_lines`]
|
||||||
let row_lines = row_lines
|
let row_lines = row_lines
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|line_parts| line_parts.join(Self::DISPLAY_CHAR[10]).to_string())
|
.map(|line_parts| line_parts.join(Self::DISPLAY_CHAR[10]).to_string())
|
||||||
.map(|line| [Self::DISPLAY_CHAR[10], &line, Self::DISPLAY_CHAR[10]].join(""))
|
.map(|line| [Self::DISPLAY_CHAR[10], &line, Self::DISPLAY_CHAR[10]].join(""))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
row_lines.join("\n")
|
row_lines.join("\n")
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
[
|
[
|
||||||
self.first_grid_display_line(),
|
self.first_grid_display_line(),
|
||||||
row_representations.join(&self.between_grid_display_line()),
|
row_representations.join(&self.between_grid_display_line()),
|
||||||
self.last_grid_display_line(),
|
self.last_grid_display_line(),
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_grid_display_line(&self) -> String {
|
fn first_grid_display_line(&self) -> String {
|
||||||
let middle = (0..self.size)
|
let middle = (0..self.size)
|
||||||
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(Self::DISPLAY_CHAR[9]);
|
.join(Self::DISPLAY_CHAR[9]);
|
||||||
[Self::DISPLAY_CHAR[2], &middle, Self::DISPLAY_CHAR[1]].join("")
|
[Self::DISPLAY_CHAR[2], &middle, Self::DISPLAY_CHAR[1]].join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn between_grid_display_line(&self) -> String {
|
fn between_grid_display_line(&self) -> String {
|
||||||
let middle = (0..self.size)
|
let middle = (0..self.size)
|
||||||
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(Self::DISPLAY_CHAR[4]);
|
.join(Self::DISPLAY_CHAR[4]);
|
||||||
[
|
[
|
||||||
"\n",
|
"\n",
|
||||||
Self::DISPLAY_CHAR[6],
|
Self::DISPLAY_CHAR[6],
|
||||||
&middle,
|
&middle,
|
||||||
Self::DISPLAY_CHAR[7],
|
Self::DISPLAY_CHAR[7],
|
||||||
"\n",
|
"\n",
|
||||||
]
|
]
|
||||||
.join("")
|
.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_grid_display_line(&self) -> String {
|
fn last_grid_display_line(&self) -> String {
|
||||||
let middle = (0..self.size)
|
let middle = (0..self.size)
|
||||||
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
.map(|_| Self::DISPLAY_CHAR[5].repeat(Tile::TILE_LENGTH))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(Self::DISPLAY_CHAR[8]);
|
.join(Self::DISPLAY_CHAR[8]);
|
||||||
[Self::DISPLAY_CHAR[3], &middle, Self::DISPLAY_CHAR[0], "\n"].join("")
|
[Self::DISPLAY_CHAR[3], &middle, Self::DISPLAY_CHAR[0], "\n"].join("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,5 @@ pub mod game;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
|
||||||
pub fn clear_term() {
|
pub fn clear_term() {
|
||||||
print!("\x1B[2J\x1B[1;1H");
|
print!("\x1B[2J\x1B[1;1H");
|
||||||
}
|
}
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -3,9 +3,9 @@ use lib::game::{Game, Rules};
|
||||||
pub mod lib;
|
pub mod lib;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let rules = Rules::default().size(4).spawn_per_turn(1);
|
let rules = Rules::default().size(4).spawn_per_turn(1);
|
||||||
let mut game = Game::new(rules);
|
let mut game = Game::new(rules);
|
||||||
loop {
|
loop {
|
||||||
game.turn().unwrap();
|
game.turn().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue