RosettaCodeData/Task/Matrix-digital-rain/C/matrix-digital-rain-2.c
2023-07-01 13:44:08 -04:00

185 lines
4.6 KiB
C

/*******************************************************************************
*
* Digital ASCII rain - the single thread variant.
* 2012 (C) by Author, 2020 GPL licensed for RossetaCode
*
*******************************************************************************/
#include <assert.h> /* assertions */
#include <conio.h> /* console operations */
#include <locale.h> /* l10n and i18n */
#include <string.h> /* operations on strings and memory blocks */
#include <process.h> /* Microsoft Windows API for threads etc. */
#include <stdio.h> /* standard i/o library */
#include <stdlib.h> /* standard library with rand() function */
#include <time.h> /* time(NULL) used as srand(time(NULL)) */
#include <windows.h> /* just the Microsoft Windows main header for C */
/*
* Global variables - you could use local variables instead...
* but then e.g. the memory for the buffer variable would be unnecessarily
* allocated and released manifold, which would lead to a worse performance.
*/
HANDLE hStdOut; /* the handle to console "out" */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* numbers of rows, columns etc. */
PCHAR_INFO buffer = NULL; /* an enough big buffer */
COORD bufferSize, bufferCoord; /* the size of buffer etc. */
/*
* A structure that holds data that is distinct for each column.
*/
struct Data
{
DWORD armed; /* time in ms to synchronize */
int delay; /* armed = current_time + delay */
BOOL show; /* TRUE - draw, FALSE - erase */
COORD ncp; /* position for drawing new characters */
SMALL_RECT s, d; /* source/destination regions for copy */
};
/*
* A function to generate random numbers from the range (a, b).
* NOTE: POSIX rand () is not thread safe,
* but we use secure rand() from MS runtime libraries.
*/
int rnd(int a, int b)
{
return a + rand() % (b + 1 - a);
}
BOOL randomShow(void)
{
return rnd(0, 99) < 65;
}
int randomDelay(void)
{
return rnd(0, 150) + rnd(0, 150) + rnd(0, 150);
}
BOOL randomRegenerate(void)
{
return rnd(0, 99) < 2;
}
void column_init(struct Data* data, int k)
{
data->armed = 0;
data->show = randomShow();
data->delay = randomDelay();
data->s.Left = k;
data->s.Top = 0;
data->s.Bottom = bufferSize.Y - 2;
data->s.Right = k;
data->d.Left = data->s.Left;
data->d.Top = data->s.Top + 1;
data->d.Right = data->s.Right;
data->d.Bottom = data->s.Bottom + 1;
data->ncp.X = k;
data->ncp.Y = 0;
}
void column_run(struct Data* data)
{
char c;
WORD a;
DWORD result;
/*
* Shift down a column.
*/
ReadConsoleOutput (hStdOut, buffer, bufferSize, bufferCoord, &data->s);
WriteConsoleOutput(hStdOut, buffer, bufferSize, bufferCoord, &data->d);
/*
* If show == TRUE then generate a new character.
* If show == FALSE write the space to erase.
*/
if(data->show)
{
c = (rnd(1,100) <= 15) ? ' ' : rnd( 'a', 'z' );
a = FOREGROUND_GREEN | ((rnd(1,100) > 10) ? 0 : FOREGROUND_INTENSITY);
}
else
{
c = ' ';
a = FOREGROUND_GREEN;
}
WriteConsoleOutputCharacter(hStdOut, &c, 1, data->ncp, &result);
WriteConsoleOutputAttribute(hStdOut, &a, 1, data->ncp, &result);
/*
* Randomly regenerate the delay and the visibility state of the column.
*/
if(randomRegenerate()) data->show = randomShow();
if(randomRegenerate()) data->delay = randomDelay();
data->armed = GetTickCount() + data->delay;
}
int main(int argc, char* argv[])
{
int j;
struct Data* table;
srand((unsigned int)time(NULL));
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
SetConsoleTitle("Digital ASCII rain");
/*
* An attempt to run in the full-screen mode.
*/
if(argc == 1)
{
COORD coord;
CONSOLE_CURSOR_INFO cci;
cci.bVisible = FALSE;
cci.dwSize = 0;
SetConsoleDisplayMode(hStdOut, CONSOLE_FULLSCREEN_MODE, &coord);
SetConsoleCursorInfo(hStdOut, &cci);
}
GetConsoleScreenBufferInfo(hStdOut, &csbi );
//SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN);
bufferSize.X = 1;
bufferSize.Y = csbi.dwSize.Y - 1;
bufferCoord.X = 0;
bufferCoord.Y = 0;
buffer = (PCHAR_INFO)calloc(bufferSize.Y, sizeof(CHAR_INFO));
assert(buffer != NULL);
table = (struct Data*)calloc(csbi.dwSize.X, sizeof(struct Data));
assert(table != NULL);
for(j = 0; j < csbi.dwSize.X; j++) column_init(&table[j], j);
/*
* Main loop. Sleep(1) significally decreases the CPU load.
*/
while(!_kbhit())
{
DWORD t = GetTickCount();
for(j = 0; j < csbi.dwSize.X; j++)
if(table[j].armed < t) column_run(&table[j]);
Sleep(1);
}
free(table);
free(buffer);
return 0;
}