diff --git a/src/app.rs b/src/app.rs index 91b8f94..db6e6f2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -27,6 +27,8 @@ impl Game for App { } fn load(&mut self, _asset_store: &mut AssetStore) { + self.board.generate_tile(); + self.board.generate_tile(); } fn key_press( @@ -35,10 +37,10 @@ impl Game for App { _asset_store: &mut AssetStore ) { if key == keyboard::Left { - self.board.test_tile.start_moving(settings::TILE_MOVE_TIME, 0, 0); + self.board.merge_from_right_to_left(); } if key == keyboard::Right { - self.board.test_tile.start_moving(settings::TILE_MOVE_TIME, 3, 0); + self.board.merge_from_left_to_right(); } } diff --git a/src/board.rs b/src/board.rs index a881deb..eca8bf9 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,37 +1,177 @@ +use std::iter::range_step; +use rand::random; use graphics::*; use piston::*; use settings; -use tile::Tile; +use tile::{ + Tile, + TileStatic, +}; pub struct Board { - center: [f64, ..2], - tiles: [[Option, ..settings::TILE_WIDTH], ..settings::TILE_HEIGHT], - pub test_tile: Tile, + tiles: Vec, } impl Board { pub fn new() -> Board { Board { - center: [0.0, 0.0], - tiles: [ - [None, None, None, None], - [None, None, None, None], - [None, None, None, None], - [None, None, None, None], - ], - test_tile: Tile::new(16, 0, 0), + tiles: Vec::::new(), + } + } + + pub fn generate_tile(&mut self) { + if self.tiles.len() == (settings::TILE_WIDTH * settings::TILE_HEIGHT) as uint { + return; + } + + 'generating: loop { + let x = (random::() % settings::TILE_WIDTH as uint) as int; + let y = (random::() % settings::TILE_HEIGHT as uint) as int; + if self.get_tile(x, y).is_none() { + self.tiles.push(Tile::new(2, x, y)); + break; + } } } pub fn update(&mut self, dt: f64) { - self.test_tile.update(dt); + for tile in self.tiles.mut_iter() { + tile.update(dt); + } } pub fn render(&self, c: &Context, gl: &mut Gl) { self.render_board(c, gl); self.render_tiles(c, gl); - self.test_tile.render(c, gl); + } + + pub fn can_merge(&self) -> bool { + for row in range(0, settings::TILE_HEIGHT) { + if !self.can_merge_row(row) { + return false; + } + } + true + } + + pub fn merge_from_left_to_right(&mut self) { + self.merge_row(settings::TILE_WIDTH - 1, -1, -1); + } + + pub fn merge_from_right_to_left(&mut self) { + self.merge_row(0, settings::TILE_WIDTH, 1); + } + + fn merge_row(&mut self, x_start: int, x_end: int, x_step: int) { + if self.is_locking() { + return; + } + + // move all tiles to right place + for row in range(0, settings::TILE_HEIGHT) { + for col in range_step(x_start, x_end, x_step) { + match self.get_mut_tile(col, row) { + None => { + match self.get_mut_next_tile(col, row, x_step, 0) { + Some(ref mut tile) => { + tile.start_moving(col, row); + }, + _ => {}, + } + }, + _ => {}, + } + } + } + + // merge + + self.generate_tile(); + } + + fn can_merge_row(&self, row: int) -> bool { + for col in range(0, settings::TILE_WIDTH) { + match self.get_tile(col, row) { + Some(ref tile) => { + match self.get_next_tile(tile.tile_x, tile.tile_y, 1, 0) { + Some(ref s_tile) => { + if tile.score == s_tile.score { + return true; + } + }, + _ => {}, + } + }, + None => {}, + } + } + false + } + + fn is_locking(&self) -> bool { + for tile in self.tiles.iter() { + if tile.status != TileStatic { + return true; + } + } + false + } + + /// Returns next tile right besides (x, y) + fn get_next_tile<'a>(&'a self, x: int, y: int, step_x: int, step_y: int) -> Option<&'a Tile> { + let mut x = x + step_x; + let mut y = y + step_y; + while x >= 0 && x < settings::TILE_WIDTH + && y >= 0 && y < settings::TILE_HEIGHT { + let tile = self.get_tile(x, y); + if tile.is_some() { + return tile; + } + x += step_x; + y += step_y; + } + None + } + + fn get_mut_next_tile<'a>(&'a mut self, x: int, y: int, step_x: int, step_y: int) -> Option<&'a mut Tile> { + let mut x = x + step_x; + let mut y = y + step_y; + let mut found = false; + while x >= 0 && x < settings::TILE_WIDTH + && y >= 0 && y < settings::TILE_HEIGHT { + let tile = self.get_tile(x, y); + if tile.is_some() { + found = true; + break; + } + x += step_x; + y += step_y; + } + + if found { + self.get_mut_tile(x, y) + } else { + None + } + } + + fn get_tile<'a>(&'a self, x: int, y: int) -> Option<&'a Tile> { + for tile in self.tiles.iter() { + if tile.tile_x == x && tile.tile_y == y { + return Some(tile); + } + } + None + } + + fn get_mut_tile<'a>(&'a mut self, x: int, y: int) -> Option<&'a mut Tile> { + for tile in self.tiles.mut_iter() { + if tile.tile_x == x && tile.tile_y == y { + return Some(tile); + } + } + None } fn render_board(&self, c: &Context, gl: &mut Gl) { @@ -70,7 +210,7 @@ impl Board { fn render_tiles(&self, c: &Context, gl: &mut Gl) { for row in range(0, settings::TILE_HEIGHT) { for col in range(0, settings::TILE_WIDTH) { - match self.tiles[row][col] { + match self.get_tile(col, row) { Some(ref tile) => { tile.render(c, gl); }, diff --git a/src/main.rs b/src/main.rs index 25cba57..8ee46ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(globs)] +extern crate collections; extern crate rand; extern crate graphics; diff --git a/src/settings.rs b/src/settings.rs index 355b7e6..24336cd 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -14,8 +14,8 @@ pub static BOARD_SIZE: [f64, ..2] = [ ]; pub static BOARD_OFFSET_Y: f64 = 128.0; -pub static TILE_WIDTH: uint = 4; -pub static TILE_HEIGHT: uint = 4; +pub static TILE_WIDTH: int = 4; +pub static TILE_HEIGHT: int = 4; pub static TILE_SIZE: f64 = 96.0; pub static TILE_PADDING: f64 = 16.0; pub static TILE_BACKGROUND_COLOR: [f32, ..4] = [187.0 / 255.0, 173.0 / 255.0, 160.0 / 255.0, 1.0]; diff --git a/src/tile.rs b/src/tile.rs index 45c3915..4def4c5 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -3,17 +3,18 @@ use graphics::*; use piston::*; use settings; -enum TileState { +#[deriving(Eq)] +pub enum TileState { TileStatic, - /// (t, x, y, destination_tile_x, destination_tile_y) - TileMoving(f64, f64, f64, int, int), + /// (t, x, y) + TileMoving(f64, f64, f64), } pub struct Tile { - score: int, - tile_x: int, - tile_y: int, - status: TileState, + pub score: int, + pub tile_x: int, + pub tile_y: int, + pub status: TileState, } impl Tile { @@ -32,27 +33,22 @@ impl Tile { (x, y) } - pub fn start_moving(&mut self, t: f64, destination_tile_x: int, destination_tile_y: int) { - match self.status { - TileStatic => { - let (x, y) = Tile::tile_to_pos(self.tile_x, self.tile_y); - self.status = TileMoving(t, x, y, destination_tile_x, destination_tile_y); - }, - _ => {}, - } + pub fn start_moving(&mut self, destination_tile_x: int, destination_tile_y: int) { + let (x, y) = Tile::tile_to_pos(self.tile_x, self.tile_y); + self.status = TileMoving(settings::TILE_MOVE_TIME, x, y); + self.tile_x = destination_tile_x; + self.tile_y = destination_tile_y; } pub fn update(&mut self, dt: f64) { match self.status { - TileMoving(t, x, y, dtx, dty) => { + TileMoving(t, x, y) => { if dt >= t { - self.tile_x = dtx; - self.tile_y = dty; self.status = TileStatic; } else { - let (dx, dy) = Tile::tile_to_pos(dtx, dty); + let (dx, dy) = Tile::tile_to_pos(self.tile_x, self.tile_y); let factor = dt / t; - self.status = TileMoving(t - dt, x + factor * (dx - x), y + factor * (dy - y), dtx, dty); + self.status = TileMoving(t - dt, x + factor * (dx - x), y + factor * (dy - y)); } }, TileStatic => {}, @@ -62,12 +58,12 @@ impl Tile { pub fn render(&self, c: &Context, gl: &mut Gl) { let mut pos = (0.0, 0.0); match self.status { + TileMoving(_, x, y) => { + pos = (x, y); + }, TileStatic => { pos = Tile::tile_to_pos(self.tile_x, self.tile_y); }, - TileMoving(_, x, y, _, _) => { - pos = (x, y); - } } let (x, y) = pos; let color = self.get_color();