use std::iter::range_step; use collections::hashmap::HashSet; use rand::random; use graphics::*; use piston::*; use settings; use tile::{ Tile, TileStatic, }; pub struct Board { tiles: Vec, } impl Board { pub fn new() -> Board { Board { tiles: Vec::::new(), } } pub fn generate_tile(&mut self) { if self.tiles.len() == (settings::TILE_WIDTH * settings::TILE_HEIGHT) as uint { return; } 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) { for tile in self.tiles.mut_iter() { tile.update(dt); } if self.is_locking() { return; } let mut tiles_need_removed = HashSet::::new(); let mut tiles_need_added = Vec::::new(); for i in range(0, self.tiles.len()) { let tile1 = self.tiles.get(i); if tile1.status != TileStatic { continue; } for j in range(i + 1, self.tiles.len()) { let tile2 = self.tiles.get(j); if tile2.status != TileStatic || tile1.tile_x != tile2.tile_x || tile1.tile_y != tile2.tile_y { continue; } tiles_need_removed.insert(i); tiles_need_removed.insert(j); tiles_need_added.push(Tile::new_combined(tile1.score + tile2.score, tile1.tile_x, tile1.tile_y)); break; } } if tiles_need_removed.len() > 0 { let mut tiles = Vec::::new(); for i in range(0, self.tiles.len()) { if !tiles_need_removed.contains(&i) { tiles.push(*self.tiles.get(i)); } } self.tiles = tiles.append(tiles_need_added.as_slice()); } } pub fn render(&self, c: &Context, gl: &mut Gl) { self.render_board(c, gl); self.render_tiles(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_bottom_to_top(&mut self) { self.merge_col(0, settings::TILE_HEIGHT, 1); } pub fn merge_from_top_to_bottom(&mut self) { self.merge_col(settings::TILE_HEIGHT - 1, -1, -1); } fn merge_col(&mut self, y_start: int, y_end: int, y_step: int) { if self.is_locking() { return; } let mut need_generate = false; loop { // move all tiles to right place for col in range(0, settings::TILE_WIDTH) { for row in range_step(y_start, y_end, y_step) { match self.get_mut_tile(col, row) { None => { match self.get_mut_next_tile(col, row, 0, y_step) { Some(ref mut tile) => { println!("move ({}, {}) to ({}, {})", tile.tile_x, tile.tile_y, col, row); tile.start_moving(col, row); }, _ => {}, } }, _ => {}, } } } let mut did_merged = false; for col in range(0, settings::TILE_WIDTH) { let mut found = false; let mut sx = 0; let mut sy = 0; let mut dx = 0; let mut dy = 0; for row in range_step(y_start, y_end, y_step) { match self.get_tile(col, row) { Some(ref d_tile) => { match self.get_next_tile(col, row, 0, y_step) { Some(ref s_tile) if d_tile.score == s_tile.score => { found = true; dx = d_tile.tile_x; dy = d_tile.tile_y; sx = s_tile.tile_x; sy = s_tile.tile_y; break; }, _ => {}, } }, None => { break; } } } if found { need_generate = true; did_merged = true; let mut tile = self.get_mut_tile(sx, sy); let tile = tile.get_mut_ref(); tile.start_moving(dx, dy); } } if !did_merged { break; } } if need_generate { self.generate_tile(); } } 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; } let mut need_generate = false; loop { // 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) => { println!("move ({}, {}) to ({}, {})", tile.tile_x, tile.tile_y, col, row); need_generate = true; tile.start_moving(col, row); }, _ => {}, } }, _ => {}, } } } // merge let mut did_merged = false; for row in range(0, settings::TILE_HEIGHT) { let mut found = false; let mut sx = 0; let mut sy = 0; let mut dx = 0; let mut dy = 0; for col in range_step(x_start, x_end, x_step) { match self.get_tile(col, row) { Some(ref d_tile) => { match self.get_next_tile(col, row, x_step, 0) { Some(ref s_tile) if d_tile.score == s_tile.score => { found = true; dx = d_tile.tile_x; dy = d_tile.tile_y; sx = s_tile.tile_x; sy = s_tile.tile_y; break; }, _ => {}, } }, None => { break; } } } if found { need_generate = true; did_merged = true; let mut tile = self.get_mut_tile(sx, sy); let tile = tile.get_mut_ref(); tile.start_moving(dx, dy); } } if !did_merged { break; } } if need_generate { 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) { let width = settings::TILE_SIZE * settings::TILE_WIDTH as f64 + settings::TILE_PADDING * (settings::TILE_WIDTH + 1) as f64; let height = settings::TILE_SIZE * settings::TILE_HEIGHT as f64 + settings::TILE_PADDING * (settings::TILE_HEIGHT + 1) as f64; c.view() .rect(settings::BOARD_PADDING, settings::BOARD_PADDING + settings::BOARD_OFFSET_Y, settings::BOARD_SIZE[0], settings::BOARD_SIZE[1]) .rgba(settings::TILE_BACKGROUND_COLOR[0], settings::TILE_BACKGROUND_COLOR[1], settings::TILE_BACKGROUND_COLOR[2], settings::TILE_BACKGROUND_COLOR[3]) .fill(gl); let mut x = settings::BOARD_PADDING + settings::TILE_PADDING; let mut y = settings::BOARD_PADDING + settings::BOARD_OFFSET_Y + settings::TILE_PADDING; for _ in range(0, settings::TILE_HEIGHT) { for _ in range(0, settings::TILE_WIDTH) { c.view() .rect(x, y, settings::TILE_SIZE, settings::TILE_SIZE) .rgba(settings::TILES_COLOR[0][0], settings::TILES_COLOR[0][1], settings::TILES_COLOR[0][2], settings::TILES_COLOR[0][3]) .fill(gl); x += settings::TILE_PADDING + settings::TILE_SIZE; } x = settings::BOARD_PADDING + settings::TILE_PADDING; y += settings::TILE_PADDING + settings::TILE_SIZE; } } fn render_tiles(&self, c: &Context, gl: &mut Gl) { for tile in self.tiles.iter() { tile.render(c, gl); } } }