1
1
mod block;
2
2
use crate :: block:: * ;
3
3
4
+ extern crate arrayvec;
4
5
extern crate pancurses;
5
6
extern crate rand;
6
7
8
+ use arrayvec:: ArrayVec ;
7
9
use pancurses:: { endwin, initscr, Window } ;
8
10
use rand:: { thread_rng, Rng } ;
9
11
use std:: { thread, time} ;
@@ -12,30 +14,73 @@ fn in_bounds(window: &Window, row: i32, col: i32) -> bool {
12
14
row >= 0 && row < window. get_max_y ( ) && col >= 0 && col < window. get_max_x ( )
13
15
}
14
16
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) ;
21
23
}
22
24
}
23
25
}
24
26
25
27
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
+
26
34
let window = initscr ( ) ;
27
35
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
+ //
29
74
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) ) ;
34
75
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] ) ;
37
79
}
80
+
81
+ window. refresh ( ) ;
82
+ thread:: sleep ( RENDER_REFRESH_PERIOD ) ;
38
83
}
39
- window . getch ( ) ;
84
+
40
85
endwin ( ) ;
41
86
}
0 commit comments