C - Creating animation in terminal - auto-updating 2D array - c

I'm trying to make an animation which will make a basic circle from dots. I got stuck, because i do not know how to make an array to auto-update herself to make an animation. My program has an issue, because it shows only the last point on circle and other, previous points has vanished due to system("clear") command, but i do not know how to make it the proper way.
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void){
char tab[43][132];
int a, b, t;
double x_kropki, y_kropki;
for (t=0 ; t<360 ; t++) {
x_kropki=floor(10*cos((t*pi)/180))+60;
y_kropki=floor(10*sin((t*pi)/180))+20;
for (a=0 ; a<43 ; a++, printf("\n")) for (b=0 ; b<132 ; b++) {
if ((int)y_kropki==a && (int)x_kropki==b){
tab[a][b]='.';
printf("%c", tab[a][b]);
}else {
tab[a][b]=' ';
printf("%c", tab[a][b]);
}
}
system("clear");
}
return 0;
}

What is the animation supposed to look like? Do you want the circle to grow slowly? Then you need to add a delay (sleep or similar) or else it will finish the whole process too quickly for the screen to draw and for your eyes to notice.
Also you should not clear the progress after every new dot (of the 360 dots in total, it seems). To achieve that, you will need to change your approach a bit. Here's what the loop could look like:
Draw nothing
Draw dot 1
Clear
Draw dot 1 and 2
Clear
Draw dot 1 and 2 and 3
You see that after clearing, you need to repeat printing the progress so far. At loop iteration 180, you need to print the last 179 dots again plus the 180th. Wait a few milliseconds, then clear, then the same for 181.
How you do that? You repeat the for loop:
int dot, maxDots;
for (maxDots = 0; maxDots < 360; maxDots++) {
for (dot = 0; dot < maxDots; dot++) {
// your location calculations and printing for each dot
}
system("clear");
}
This should at least give you some kind of growing circle. But you will notice that the printing approach is hard to get right, because once a line has been finished, you cannot go back. If you start at the top and go your way around 180 degrees, down line by line, you will then need to go up line by line until you reach the top again. That won't work easily. Instead of printing directly, as #Weather Vane suggested, store the to-be-printed result of each animation stage in a buffer. That is an abstraction of on-screen coordinates. A very simple approach would be a two-dimensional array that you can manipulate freely, then print the whole array en bloc.

Related

Vertical line using Bresenham Line Algorithm printing a point, not a line

I am trying to do vertical lines using Bresenham's Line Algorithm. But when I put coordinate for a vertical line, it is printing a point only, not showing a vertical line.
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int main( )
{
int x1,y1,x2,y2,dx,dy,ds,dt,d,x,y;
/* request auto detection */
int gdriver = DETECT, gmode, errorcode;
/* initialize graphics and local variables */
initgraph(&gdriver, &gmode, "c:\\tc\\bgi");
x1=200;
x2=200;
y1=200;
y2=300;
x=x1;
y=y1;
dx=x2-x1;
dy=y2-y1;
dt=2*(dy-dx);
ds=2*dy;
d=2*dy-dx;
printf("Using Bresenham's Line Algorithm");
putpixel(x,y,7);
while(x<=x2)
{
x=x+1;
if(d<0)
d=d+ds;
else
{
y=y+1;
d=d+dt;
}
putpixel(x,y,7);
}
getch();
closegraph();
return 0;
}
When I put x1=200 x2=200 it gives me an error.
Why am I getting the error?
But in normal line function, I am getting the right result,
but when putting in Bresenham, I am getting the wrong result.
Bresenham like you implemented can only draw lines with a slope between 0° and 45° since every loop increases x by one and conditionally increases y by one.
What you have to do is first check if the line goes left to right. If not you have to switch the endpoints.
Next if the line slopes down instead of up you have to decrement y instead of incrementing it. You can store 1 or -1 in a temp variable depending on whether the lines slopes up or down and add that to y when needed.
And if the change in y is greater than the change in x you have to swap the coordinates around in the algorithm incrementing y every loop and x conditionally. For this you actually have to duplicate the whole loop.

ignoring "collision" in a pacman game

i am almost done with my pixel pacman
and im trying to figure out how the monsters should avoid the collision with the power up and the energizer pills
if you run the game you will see dots which represents
yellow is the pacman
red are the ghosts
purple are simple pills
green are energizer pills(if you eat them you can eat the ghosts).
my problem here is that the im having hard time that the monsters will not "eat" the red or green dots. here is my main struct
struct info {
int curX;
int curY;
char color;
int alive;
};
also every monster move is represented like this
if ( rand1 == 1){ //random up
if(infos[i].curY > 50){
for (j = 0 ;j < 18 ; j++){
set_board(infos[i].curX,infos[i].curY,0);
set_board(infos[i].curX,--infos[i].curY,4);
if the monster is the same location as the pixel it will override it( a thing that i dont want to happen)
It seems that your issue is a display one, not a game logic one. From what I understand, when the ghost goes over the pellets, they get erased. It seems that the answer here is simply to redraw the pellets after the ghost goes over them. You call this pixel pacman: does that mean that every entity is a displayed as a one pixel ? If so, the solution is simply to turn the pixel back to its original colour instead of black (I guess that is the colour you chose when there is nothing to display) when the ghost has moved to the next location.

Selectively ignoring parts of a randomly generated sequence of numbers (in C)

I have a question that may be hard to understand -- but I will try my best to explain.
I'm programming the Simon Game in C. This implementation specifically read/writes to a hardware DAQ module that has a 4 LED display, and 4 corresponding toggle switches.
As per the rules of the Game, I've seeded and generated a random sequence of numbers between 0 and 3 (sequence length is arbitrarily 5). In the Game, if the player presses the wrong switch (i.e. blue is shown but you press green), the game ends and restarts.
The way I've set up the Game looks like this:
(I haven't included the code for function "blinkLED" here -- it turns the actual LED on/off.)
void runSimon(void){
int sequence[MAX_SEQ_LEN];
int i;
int count = 0;
// Seeds the random number generator.
srand((unsigned)time(NULL));
// Generate the random LED sequence & store it as an array.
for (i = 0; i < MAX_SEQ_LEN; i++){
sequence[i] = (rand() % NUM_LEDS);
}
// The game begins!
while (continueSuperLoop() == TRUE){
// Loop the game while the sequence length is less than the pre-defined maximum (currently it's 5).
while (count < MAX_SEQ_LEN){
for (i = 0; i <= count; i++){
// Blink the first 'count' LEDs in the sequence, one at a time.
blinkLED(sequence[i], 1, ONE_SEC);
//
//
//THE ISSUE SHOULD BE HERE (!)
//
// Monitors whether or not the player has made a mistake...if so, blink the red LED thrice, then restart the game.
if (digitalRead(sequence[ !i ] == SWITCH_ON)){
blinkLED(LED_1_R, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
continue;
}
// Monitors whether or not the correct switch is being pressed -- waits for it to be released
while (digitalRead(sequence[i]) == SWITCH_ON){}
}
count++;
}
// If 'count' is equal to 'MAX_SEQ_LEN', the green LED blinks 3x to indicate the player has won .
if (count == MAX_SEQ_LEN){
blinkLED(LED_0_G, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
}
}
}
Where I indicated an issue, I'm not sure how the "digitalRead(sequence[ ! i ]" behaves; I need this line to read every switch that's not supposed to be pressed.
I don't think the compiler understands what I'm trying to do here, though -- for example, if the first number in the sequence is 3 (representing the 4th LED), I need to specify that every other number (0, 1, 2) and its corresponding switch should not be pressed.
Would a solution be to store the current number in the sequence, having a set of four TRUE/FALSE flags for each LED, and monitoring the three non-current numbers and their corresp. switches to see if they are pressed?
I'm getting quite frustrated with writing this program. I'm pretty new to programming. Any help is appreciated.
I'm not sure I understand the rules of this game correctly but one thing that jumps out instantly is
digitalRead(sequence[ !i ]
I think you want
!digitalRead(sequence[ i ]
Also, you need to fix your game flow. Right now it's:
1. Light LED.
2. Check if user pressed the right button.
You need to wait for some time before checking a switch or wait for ANY switch to be pressed and see if it's the correct one. So something like this:
1. Light LED.
2. Wait for timeout or ANY switch to be pressed.
3. If timeout: error
4. else: check if switch that was pressed is correct.
In C, ! operator is a unary NOT. When applied to an integer i, it is equivalent to if (i == 0) return 1; else return 0;. Then you are using !i as an index for sequence array, so it will be either sequence[0] or sequence[1], and clearly this is not what you want. Also your == is inside of digitalRead call :)
I would suggest explicitly checking for every other button not to be pressed. Like this:
int isOtherPressed = 0;
for (ledId = 0; ledId < NUM_LEDS; ledId++) {
if (ledId != sequence[i] && digitalRead(ledId) == SWITCH_ON) {
isOtherPressed = 1;
}
}
if (isOtherPressed) {
// restart the game
}
However, I'm suspicious about the whole gameplay you have, but maybe it's just because I don't know how digitalRead works. For example, the way you use continue doesn't seem to stop the game. Maybe you meant break?

How do I create a "twirly" in a C program task?

Hey guys I have created a program in C that tests all numbers between 1 and 10000 to check if they are perfect using a function that determines whether a number is perfect. Once it finds these it prints them to the user, they are 6, 28, 496 and 8128. After this the program then prints out all the factors of each perfect number to the user. This is all fine. Here is my problem.
The final part of my task asks me to:
"Use a "twirly" to indicate that your program is happily working away. A "twirly" is the following characters printed over the top of each other in the following order: '|' '/' '-' '\'. This has the effect of producing a spinning wheel - ie a "twirly". Hint: to do this you can use \r (instead of \n) in printf to give a carriage return only (instead of a carriage return linefeed). (Note: this may not work on some systems - you do not have to do it this way.)"
I have no idea what a twirly is or how to implement one. My tutor said it has something to do with the sleep and delay functions which I also don't know how to use. Can anyone help me with this last stage, it sucks that all my coding is complete but I can't get this "twirly" thing to work.
if you want to simultaneously perform the task of
Testing the numbers and
Display the twirly on screen
while the process goes on then you better look into using threads. using POSIX threads you can initiate the task on a thread and the other thread will display the twirly to the user on terminal.
#include<stdlib.h>
#include<pthread.h>
int Test();
void Display();
int main(){
// create threads each for both tasks test and Display
//call threads
//wait for Test thread to finish
//terminate display thread after Test thread completes
//exit code
}
Refer chapter 12 for threads
beginning linux programming ebook
Given the program upon which the user is "waiting", I believe the problem as stated and the solutions using sleep() or threads are misguided.
To produce all the perfect numbers below 10,000 using C on a modern personal computer takes about 1/10 of a second. So any device to show the computer is "happily working away" would either never be seen or would significanly intefere with the time it takes to get the job done.
But let's make a working twirly for perfect number search anyway. I've left off printing the factors to keep this simple. Since 10,000 is too low to see the twirly in action, I've upped the limit to 100,000:
#include <stdio.h>
#include <string.h>
int main()
{
const char *twirly = "|/-\\";
for (unsigned x = 1; x <= 100000; x++)
{
unsigned sum = 0;
for (unsigned i = 1; i <= x / 2; i++)
{
if (x % i == 0)
{
sum += i;
}
}
if (sum == x)
{
printf("%d\n", x);
}
printf("%c\r", twirly[x / 2500 % strlen(twirly)]);
}
return 0;
}
No need for sleep() or threads, just key it into the complexity of the problem itself and have it update at reasonable intervals.
Now here's the catch, although the above works, the user will never see a fifth perfect number pop out with a 100,000 limit and even with a 100,000,000 limit, which should produce one more, they'll likely give up as this is a bad (slow) algorithm for finding them. But they'll have a twirly to watch.
i as integer
loop i: 1 to 10000
loop j: 1 to i/2
sum as integer
set sum = 0
if i%j == 0
sum+=j
return sum==i
if i%100 == 0
str as character pointer
set *str = "|/-\\"
set length = 4
print str[p] using "%c\r" as format specifier
Increment p and assign its modulo by len to p

gotoxy() function using printf() 's position

Hello there
i am working a project which need the gotoxy() function
i have read gotoxy() implementation for Linux using printf
i wonder why the
void gotoxy(int x,int y)
{
printf("%c[%d;%df",0x1B,y,x);
}
need to change the x y order in printf, is that just to fit the coordinate system?
in my way, i change it to printf("%c[%d;%df",0x1B,x,y) to meet my needs
stil, during my using this gotoxy() in for loop like this:
for( int i = 0; i < 12; i++ ) {
for( int j = 0; j < 12; j++ ) {
gotoxy( i , j );
usleep(500000);
}
}
when i = 0 and i = 0, the cursor are on the first row
i wonder why cursor does't go to second row when i = 1?
OP: "why the need to change the x y order".
The cursor position command's format is
Force Cursor Position <ESC>[{ROW};{COLUMN}f
The need arises because to match that format and have your y variable as the ROW, y comes first. (You could rotate your screen 90 degrees instead).
OP: why cursor does't go to second row when i = 1?
The home position, at the upper left of the screen is the Origin being line 1, column 1
Note: You can put the escape character in the format,
printf("\x1B[%d;%df", y, x);
fflush(stdout); // #jxh
The order of x and y matters because the names of the variables have no meaning to the operation of the gotoxy() function.
That function is outputing a terminal command sequence that moves to the specified coordinates. When the terminal sees that command sequence and processes it, y is expected first.
By the way, be careful with this solution as this is highly dependent on the type of terminal within which the program is run. In order to get wide terminal support with random movement and "drawing" on a terminal screen, ncurses or curses are your best bet. They are challenging to learn at first though.
The column and row positions do not start at 0 when using the terminal escape sequences. They start at 1.
You need to flush stdout to see the cursor move.
void gotoxy(int x,int y)
{
printf("%c[%d;%df",0x1B,y,x);
fflush(stdout);
}
GotoXY is a function or procedure that positions the cursor at (X,Y), X in horizontal, Y in vertical direction relative to the origin of the current window. The origin is located at (1,1), the upper-left corner of the window.
The above C code worked after I converted to Android script (I think I'm using Korn Shell).
function gotoxy()
{
printf "\033[$1;$2f"
}
I've beenn using "\033[r;cH" all this time and it was working.

Resources