-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcmatrix.c
222 lines (170 loc) · 5.53 KB
/
cmatrix.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#include <sys/ioctl.h>
#include <sys/select.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
//Escape character's value
#define ESC 27
//Max height and width allowed for cmatrix
#define MAX_WIDTH 300
#define MAX_HEIGHT 200
//Speed at which the characters fall
#define FALL_SPEED 6
//Console codes
#define TXT_RST "\x1B[0m"
#define HIDE_CURSOR "\e[?25l"
#define SHOW_CURSOR "\e[?25h"
#define CLEAR_SCRN "\033[H\033[J"
//List from which characters are randomly generated
#define CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()+=[]{};:/?.>,<|\\'\"`~"
#define CHAR_LIST_LENGTH 82
//Returns the min of two ints
#define MIN(a, b) ((a) > (b)) ? (b) : (a)
//Moves the cursor to specified position in the terminal
#define GO_TO_POS(row, col) printf("\033[%d;%dH", (row), (col))
//Array of color fade values, from darkest to brightest
char* GREENS[5] = {"\x1B[38;5;22m", "\x1B[38;5;28m", "\x1B[38;5;34m", "\x1B[38;5;40m", "\x1B[38;5;46m"};
struct matrixChar {
char c;
int isWhite;
int runLength;
};
struct matrixChar matrix[MAX_HEIGHT][MAX_WIDTH];
static struct termios oldt;
//Restores terminal settings to the original settings
void restore_terminal_settings();
//Disables the terminal's default behavior of waiting
// for enter press to get input
void disable_waiting_for_enter();
//Shifts the matrix down one row and determines a new row
void updateMatrix();
//Determine the updated state of the space
void determineState(int row, int col);
//Determine the updated state of the top row in a column
void determineTopState(int col);
//Prints the entire matrix to the screen
void displayMatrix(int currWidth, int currHeight);
//Used to determine if the user pressed enter
int kbhit();
int main(int argc, char* argv[]) {
int i, j;
//The height and width used for printing to the screen
int currWidth, currHeight;
//Used to acquire terminal window size
struct winsize w;
disable_waiting_for_enter();
printf(HIDE_CURSOR);
//Creates empty space on terminal we can write to and initializes values in matrix
for (i = 0; i < MAX_HEIGHT; i++) {
//printf("\n");
for (j = 0; j < MAX_WIDTH; j++) {
matrix[i][j].c = ' ';
matrix[i][j].isWhite = 0;
matrix[i][j].runLength = 0;
}
}
//Seed the random number generator
srand(time(NULL));
//Loop until the key pressed is ESC
do {
//Loop until the user presses a key
do {
//Retrieve current window size
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
//Number of columns/rows used is the number in the window, capped at the max
currWidth = MIN(w.ws_col, MAX_WIDTH);
currHeight = MIN(w.ws_row+1, MAX_HEIGHT);
updateMatrix();
displayMatrix(currWidth, currHeight);
//Sleep for a fraction of a second
usleep(625000 / FALL_SPEED);
} while (!kbhit());
} while (getchar() != ESC);
printf(SHOW_CURSOR TXT_RST CLEAR_SCRN);
return 0;
}
void updateMatrix() {
int row, col;
//Loop through all the columns
for (col = MAX_WIDTH - 1; col >= 0; col--) {
//Loop through all the rows, except the top row
for (row = MAX_HEIGHT - 1; row > 0; row--) {
//Determine the state of current space
determineState(row, col);
}
//Determine the character on the top row
determineTopState(col);
}
}
void determineState(int row, int col) {
//A run is occurring, so continue
if (matrix[row][col].runLength > 0) {
matrix[row][col].isWhite = 0;
matrix[row][col].runLength--;
}
//A space "falls" into the current space
else if (matrix[row-1][col].c == ' ') {
matrix[row][col].c = ' ';
}
//A character "falls" into the current space
else {
matrix[row][col].c = CHARACTERS[rand() % CHAR_LIST_LENGTH];
matrix[row][col].isWhite = matrix[row-1][col].isWhite;
matrix[row][col].runLength = matrix[row-1][col].runLength;
}
}
void determineTopState(int col) {
//Continue a run
if (matrix[0][col].runLength > 0) {
matrix[0][col].runLength--;
matrix[0][col].isWhite = 0;
}
//1 in 40 chance of starting a new character run
else if (rand() % 40 < 1) {
matrix[0][col].c = CHARACTERS[rand() % CHAR_LIST_LENGTH];
//1 in 2 chance of starting character being white
matrix[0][col].isWhite = (rand() % 2 < 1);
//Run length is between 2 and 25, inclusive
matrix[0][col].runLength = (rand() % 24) + 2;
}
//No run
else {
matrix[0][col].c = ' ';
matrix[0][col].isWhite = 1;
}
}
void displayMatrix(int currWidth, int currHeight) {
int row, col;
for (row = 0; row < currHeight; row++) {
for (col = 0; col < currWidth; col++) {
GO_TO_POS(row, col+1);
if (matrix[row][col].isWhite) printf(TXT_RST);
else printf(GREENS[MIN(matrix[row][col].runLength + 1, 4)]);
printf("%c", matrix[row][col].c);
}
}
}
int kbhit() {
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
void restore_terminal_settings() {
tcsetattr(0, TCSANOW, &oldt); /* Apply saved settings */
}
void disable_waiting_for_enter() {
struct termios newt;
/* Make terminal read 1 char at a time */
tcgetattr(0, &oldt); /* Save terminal settings */
newt = oldt; /* Init new settings */
newt.c_lflag &= ~(ICANON | ECHO); /* Change settings */
tcsetattr(0, TCSANOW, &newt); /* Apply settings */
atexit(restore_terminal_settings); /* Make sure settings will be restored when program ends */
}