I am attempting to make my own matrix writing algorith that writes a matrix to the C console using a Run Length Encoding. My idea is that instead of printing every single value in a matrix we could clump up the matrix values in a row that are the same into one line and print that line, then do the same for the next group of values that are the same and continue doing this till we reach the end of the row, this would allow me do use theSetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE))
for coloured ASCII graphics as I could just colour each group. As an example if we had 01110000
as a row in our matrix we would use three print commands only: one for the initial zero, another one for the 3 ones and a finall one for the 4 zeroes. We could do this to avoid wasting proccesing time printing all the values to the console individually, the problem is that there is a lot of undefined behaviour in my code and this causes the console output to be very different to the expected one.
code:
#include <stdio.h>
#include <time.h>
#include <windows.h>
const int sizeX = 20;
const int sizeY = 20;
char line[20];
int grid[20][20] = {{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
void clearScreen(){
COORD cursorPosition; cursorPosition.X = 0; cursorPosition.Y = 0; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPosition);
}
void draw_screen(){
clearScreen();
int y, x;
for(y=0;y<sizeY;y ){
for(x=0;x<sizeX;x ){
if(grid[y][x] == 1){
line[x] = '1';
if(grid[y][x 1] != 1){
fputs(line, stdout);
if(grid[y][x 1] > sizeX){
putc('\n', stdout);
}
}
}
else if(grid[y][x] == 2){
line[x] = '2';
if(grid[y][x 1] != 2){
fputs(line, stdout);
if(grid[y][x 1] > sizeX){
putc('\n', stdout);
}
}
}
else if(grid[y][x] == 0){
line[x] = '0';
if(grid[y][x 1] != 0){
fputs(line, stdout);
if(grid[y][x 1] > sizeX){
putc('\n', stdout);
}
}
}
}
putc('\n', stdout);
}
}
int main(void) {
int x, y;
float frameTime, FPS;
while (1) {
clock_t start = clock();
draw_screen();
clock_t stop = clock();
frameTime = (float)(stop - start) / CLOCKS_PER_SEC;
FPS = 1.0 / frameTime;
printf("FPS: %f\n", FPS);
}
}
output:
100000000000000000001000000000000000000010000000000000001110
0000000000000000000000000000010000000000
00000000000000000000000100000000000000000001000000000000000000010000010000000000
0000000000000000000000000000000200000000
00000000000000000000
expected output:
10000000000000001110
00000000000000000000
00000000000000000000
00000000000000000000
00000000010000000000
00000000000000000000
00000000000000000000
00000000000000000000
00010000010000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000200000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
expected FPS: 100-500
CodePudding user response:
Your question has been misunderstood. My complaint is that the code is hard to read (and repetitious).
puts()
will unavoidably append a '\n' to each string it outputs.
You could try to "buffer up" a series of repeating characters, only outputting that 'block' when there is a change in the data (or end of grid row reached), but that makes the code messier. imho, it's more important that, for learning, the code be as clean as possible. Work on the algorithm and leave optimisations (like speed) until you have solved the bigger issues.
You have a 20x20 'grid' of int
s and want to output that as a grid of characters, but injecting an operation to change the font colour for the next series of characters.
The following example 'injects' an extra character indicating the location where you might change the font colour for subsequent output.
Keep things simple, and avoid the temptation to copy/paste/adapt. Use less code.
#include <stdio.h>
int grid[][20] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};
void draw_screen() {
int r, c; // I prefer 'r'ow and 'c'ol
int prev = -1; // force code to select 1st colour
for( r = 0; r < 20; r ) {
for( c = 0; c < 20; c ) {
if( grid[r][c] != prev ) {
// pick a colour (or character) for subsequent output
char cc = grid[r][c] == 0 ? '*' : grid[r][c] == 1 ? ' ' : '=';
putchar( cc ); // demonstrate "colour change" happening
}
putchar( grid[r][c] '0' ); // int to char conversion
prev = grid[r][c];
}
putchar( '\n' );
}
}
int main() {
draw_screen();
return 0;
}
Output
1*000000000000000 111*0
00000000000000000000
00000000000000000000
00000000000000000000
000000000 1*0000000000
00000000000000000000
00000000000000000000
00000000000000000000
000 1*00000 1*0000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000=2*00000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
EDIT: Trying to point this OP toward a compact solution only seems to generate frustration for all involved.
Here is an (obvious) extension of the above code that works. I don't want to "change colors", but by inserting "special characters" in the output stream, this shows how the program detects and responds to transitions in the data.
(How much are we being paid to write free code for others? Please remind me.)
const char c_red = '*', c_green = ' ', c_blue = '=';
void setFontColor( char color ) {
// do whatever you need to do here.
// This version outputs a "special" character
// indicating the color to be used
fwrite( &color, sizeof color, 1, stdout );
}
void out( char buf[], int n ) {
char color;
switch( buf[0] ) {
case '0': color = c_red; break;
case '1': color = c_green; break;
case '2': color = c_blue; break;
default:
fprintf( stderr, "Unknown character '%c'\n", buf[0] );
exit( 1 );
}
setFontColor( color );
fwrite( buf, sizeof buf[0], n, stdout );
}
void draw_screen() {
char prev = '#', obuf[ 20 ];
for( int bInd = 0, r = 0; r < 20; r ) {
for( int c = 0; c < 20; c ) {
char ch = (char)(grid[r][c] '0');
if( ( c || r ) && ch != prev )
out( obuf, bInd ), bInd = 0;
prev = obuf[ bInd ] = ch;
}
out( obuf, bInd ), bInd = 0; // End of row
putchar( '\n' ); // or, tack LF onto end of obuf[]...
}
}
int main() {
draw_screen();
return 0;
}
In the above, each buffered row is discrete (max 20 chars). Buffering LF's and not starting each row with its own colour is left as an exercise for the reader.