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.
Related
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.
I need to make a game using ncurses in C.
The game needs to be 80(char)x24(char).
I need an status bar on the bottom (5 char) so I hardcoded it.
I made this loop to keep things centralized, but I can't figure out how to keep the aspect ratio when the terminal screen is resized.
Is there any way to do it using ncurses?
I need the screen to always stay at least 80x24, perhaps using fullscreen mode always, I don't really need screen resizing.
Here's the loop to keep things in their places (status bar poorly hardcoded, the aspect ratio is a mess)
/* LOOP TO CENTRALIZE FOR ANY RESIZING */
while (1){
getmaxyx(stdscr, yMax, xMax);
clear();
mvprintw(yMax/24, xMax/80, "BEG");
mvprintw(yMax/2, xMax/2, "CENTER %d %d", yMax, xMax);
attron(COLOR_PAIR(1)); /* bottom status bar (5 lines) */
int i, j;
for ( j=(yMax-5) ; j <= yMax ; j++){
for ( i=0 ; i <= xMax ; i++ ){
mvprintw(j, i, " ");
}
}
attroff(COLOR_PAIR(1));
refresh();
}
Unless your program reads input, e.g., calls getch, ncurses will continue using the original screen-size (and look confused). When you call getch after ncurses receives a SIGWINCH, it returns KEY_RESIZE, and at that point ncurses updates its screen-size.
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.
I have the following code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define dimensions 5
int RandomNumInRange(int M, int N)
{
return M + rand() / (RAND_MAX / (N - M + 1) + 1);
}
char ** CreateWorld(int dim)
{
int i,j;
char **world = malloc(dim *sizeof(char*));
for(i=0;i<dim;i++)
world[i]=malloc(dim*sizeof(char));
for(i=0;i<dim;i++)
for(j=0;j<dim;j++)
world[i][j]=42;
return world;
}
void CreateCastle(char **world)
{
//assuming world is big enough
//to hold a match of 2
int randRow,randCol;
//1 to dimension -2 so we can spawn a 3x3 castle
randRow = RandomNumInRange(1,dimensions-2);
randCol = RandomNumInRange(1,dimensions-2);
printf("position: %d %d\n", randRow, randCol);
world[randRow][randCol]='c';
//fill the rest so castle is 3x3
//assuming there is enough space for that
world[randRow-1][randCol-1]=35;
world[randRow-1][randCol]=35;
world[randRow-1][randCol+1]=35;
world[randRow][randCol-1]=35;
world[randRow][randCol+1]=35;
world[randRow+1][randCol-1]=35;
world[randRow+1][randCol]=35;
world[randRow+1][randCol+1]=35;
}
void DisplayWorld(char** world)
{
int i,j;
for(i=0;i<dimensions;i++)
{
for(j=0;j<dimensions;j++)
{
printf("%c",world[i][j]);
}
printf("\n");
}
}
int main(void){
system("clear");
int i,j;
srand (time(NULL));
char **world = CreateWorld(dimensions);
DisplayWorld(world);
CreateCastle(world);
printf("Castle Positions:\n");
DisplayWorld(world);
//free allocated memory
free(world);
//3 star strats
char ***world1 = malloc(3 *sizeof(char**));
for(i=0;i<3;i++)
world1[i]=malloc(3*sizeof(char*));
for(i=0;i<3;i++)
for(j=0;j<3;j++)
world1[i][j]="\u254B";
for(i=0;i<3;i++){
for(j=0;j<3;j++)
printf("%s",world1[i][j]);
puts("");
}
free(world1);
//end
return 0 ;
}
If I use the system("clear") command, I get a line consisting of "[3;J"
followed by an expected output. If I run the program again, I get the same gibberish, then many blank newlines, then the expected output. If I put the system("clear") command in comments then both the "[3;J" and the blank newlines don't show and the output is expected.
Edit: it seems the error is not in the code, but rather in the way the terminal on my system is (not) set. Thank you all for your input, I definitely have a lot of interesting stuff to read and learn now.
The codes being sent by your clear command from don't seem to be compatible with the Gnome terminal emulator, which I believe is what you would be using.
The normal control codes to clear a console are CSI H CSI J. (CSI is the Control Sequence Initializer: an escape character \033 followed by a [). CSI H sends the cursor to the home position, and CSI J clears from the cursor position to the end of the screen. You could also use CSI 2 J which clears the entire screen.
On Linux consoles and some terminal emulators, you can use CSI 3 J to clear both the entire screen and the scrollback. I would consider it unfriendly to do this (and the clear command installed on my system doesn't.)
CSI sequences can typically contain semicolons to separate numeric arguments. However, the J command doesn't accept more than one numeric argument and the semicolon seems to cause Gnome terminal to fail to recognize the control sequence. In any event, I don't believe Gnome terminal supports CSI 3 J.
The clear command normally uses the terminfo database to find the correct control sequences for the terminal. It identifies the terminal by using the value of the TERM environment variable, which suggests that you have to wrong value for that variable. Try setting export TERM=xterm and see if you get different results. If that works, you'll have to figure out where Linux Mint configures environment variables and fix it.
On the whole, you shouldn't need to use system("clear") to clear your screen; it's entirely too much overhead for such a simple task. You would be better off using tputs from the ncurses package. However, that also uses the terminfo database, so you will have to fix your TERM setting in any case.
We all know how to draw a line in Processing.
But when we draw a line, the line is shown immediately.
What if i want to witness the drawing process, namely, to see the line moving forward, gradually completes a whole line.
Here's what i want to realize: to DRAW several lines and curves which finally turn into some pattern.
So how to make that happen? Using array?
Many thanks.
In processing all of the drawing happens in a loop. An easy way to create animated sequences like you describe is to use frameCount to drive it and using the modulus function % is a good way to create a loop. For example, to animate along the x axis:
void draw() {
float x = 50;
float y = 50;
float lineLength = 50;
int framesToAnimate = 60;
line(x,y,x+float(frameCount % framesToAnimate)/framesToAnimate*lineLength, y);
}
Note: strange things will happen if you don't cast / convert to a float
I use this pretty often to animate other features such as the color.
fill(color(127 + sin(float(frameCount)/90)*127, 0, 0, 127));
If you want to get more advanced, setting vectors and coordinates with PVector. There is a pretty good tutorial on Daniel Shiffman's site.
If you want to set your animation independent of frame rate, you can use mills() instead. That will return current time since the sketch started so you can set something to happen in a given time in seconds.
like for example:
long initialTime;
void setup(){
size(400,200);
initialTime = millis();
}
void draw() {
float x = 50;
float y = 50; //set the multiplier to adjust speed
line(x,y,x+(millis()-initialTime)*0.01, y); //10 px/sec
line(x,y+50,x+(millis()-initialTime)*0.05, y+50); //50 px/sec
line(x,y+100,x+(millis()-initialTime)*0.001, y+100); // 1 px/sec
}
There is also some animation libraries, i've seen some impressive results with some, but i never used them. Here a list.