Skip to content

Commit f3aca54

Browse files
committed
blocks fall now. Oh boyyyyyy
1 parent fc83459 commit f3aca54

File tree

6 files changed

+82
-19
lines changed

6 files changed

+82
-19
lines changed

Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ edition = "2018"
77
[dependencies]
88
pancurses = "0.16"
99
rand = "0.7.0"
10+
arrayvec = "0.4.10"

demo/2-fall.gif

87.9 KB
Loading

readme.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626

2727
### Steps
2828

29-
- [X] Get a tetromino to render
29+
- [X] Get a tetromino to render: 76babe55
3030
![Image of text-tetrominoes rendering](demo/1-render.gif)
31-
- [ ] Get a tetromino to fall
31+
- [X] Get a tetromino to fall: <insert hash here>
32+
![Image of text-tetrominoes falling](demo/2-fall.gif)
3233
- [ ] Get a tetromino to stick
3334
- [ ] Get two tetrominos to stack
3435
- [ ] Allow clearing lines

src/block.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl BlockType {
2727
BLOCKTYPES[rng.gen_range(0, BLOCKTYPES.len())]
2828
}
2929

30-
pub fn to_char(&self) -> char {
30+
pub fn block_char(&self) -> char {
3131
match *self {
3232
BlockType::I => 'O',
3333
BlockType::O => 'X',
@@ -39,8 +39,8 @@ impl BlockType {
3939
}
4040
}
4141

42-
#[rustfmt::skip]
43-
pub fn to_block_array(&self) -> [(i32, i32); 4] {
42+
#[rustfmt::skip] // skip rust formatting so that my block declarations can look pleasant
43+
pub fn block_cells(&self) -> [(i32, i32); 4] {
4444
match *self {
4545
BlockType::I =>
4646
[

src/main.rs

+59-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
mod block;
22
use crate::block::*;
33

4+
extern crate arrayvec;
45
extern crate pancurses;
56
extern crate rand;
67

8+
use arrayvec::ArrayVec;
79
use pancurses::{endwin, initscr, Window};
810
use rand::{thread_rng, Rng};
911
use std::{thread, time};
@@ -12,30 +14,73 @@ fn in_bounds(window: &Window, row: i32, col: i32) -> bool {
1214
row >= 0 && row < window.get_max_y() && col >= 0 && col < window.get_max_x()
1315
}
1416

15-
fn render_block(window: &Window, row: i32, col: i32, b: BlockType) {
16-
let block_char = b.to_char();
17-
let tetromino_pos = b.to_block_array();
18-
for block_pos in tetromino_pos.iter() {
19-
if in_bounds(window, block_pos.0, block_pos.1) {
20-
window.mvaddch(block_pos.0 + row, block_pos.1 + col, block_char);
17+
fn render_block(window: &Window, (row, col): (i32, i32), block_type: BlockType) {
18+
let block_char = block_type.block_char();
19+
let block_cells = block_type.block_cells();
20+
for cell in block_cells.iter() {
21+
if in_bounds(window, cell.0, cell.1) {
22+
window.mvaddch(cell.0 + row, cell.1 + col, block_char);
2123
}
2224
}
2325
}
2426

2527
fn main() {
28+
const BLOCK_GENERATION_PERIOD: time::Duration = time::Duration::from_millis(500); // generate a new block once a second
29+
const BLOCK_MOVE_PERIOD: time::Duration = time::Duration::from_millis(250);
30+
const MAX_BLOCKS: usize = 20;
31+
const RUN_TIME: time::Duration = time::Duration::from_secs(10); // run long enough to generate all blocks
32+
const RENDER_REFRESH_PERIOD: time::Duration = time::Duration::from_millis(16); // 60 fps
33+
2634
let window = initscr();
2735
let mut rng = thread_rng();
28-
for _dashgroup in 0..10 {
36+
37+
let start_time = time::Instant::now();
38+
let mut last_block_generation_timestamp = time::Instant::now();
39+
let mut last_move_timestamp = time::Instant::now();
40+
41+
let mut block_types = ArrayVec::<[BlockType; MAX_BLOCKS]>::new();
42+
let mut block_positions = ArrayVec::<[(i32, i32); MAX_BLOCKS]>::new();
43+
44+
while start_time.elapsed() < RUN_TIME {
45+
//
46+
// Game logic:
47+
// - generate a new block periodically
48+
// - move every block periodically
49+
//
50+
if last_block_generation_timestamp.elapsed() >= BLOCK_GENERATION_PERIOD {
51+
assert!(!block_types.is_full());
52+
assert!(!block_positions.is_full());
53+
54+
let new_block_type = BlockType::random(&mut rng);
55+
let start_row: i32 = rng.gen_range(0, window.get_max_y());
56+
let start_col: i32 = rng.gen_range(0, window.get_max_x());
57+
58+
block_types.push(new_block_type);
59+
block_positions.push((start_row, start_col));
60+
61+
last_block_generation_timestamp = time::Instant::now();
62+
}
63+
64+
if last_move_timestamp.elapsed() >= BLOCK_MOVE_PERIOD {
65+
for pos in &mut block_positions {
66+
pos.0 += 1;
67+
}
68+
last_move_timestamp = time::Instant::now();
69+
}
70+
71+
//
72+
// Render the frame
73+
//
2974
window.erase();
30-
for _dashiter in 0..5 {
31-
let x: i32 = rng.gen_range(0, window.get_max_x());
32-
let y: i32 = rng.gen_range(0, window.get_max_y());
33-
render_block(&window, y, x, BlockType::random(&mut rng));
3475

35-
thread::sleep(time::Duration::from_millis(200));
36-
window.refresh();
76+
assert_eq!(block_types.len(), block_positions.len());
77+
for block_id in 0..block_types.len() {
78+
render_block(&window, block_positions[block_id], block_types[block_id]);
3779
}
80+
81+
window.refresh();
82+
thread::sleep(RENDER_REFRESH_PERIOD);
3883
}
39-
window.getch();
84+
4085
endwin();
4186
}

0 commit comments

Comments
 (0)