{"id":6595,"date":"2024-10-05T00:01:15","date_gmt":"2024-10-05T07:01:15","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=6595"},"modified":"2024-10-12T09:32:48","modified_gmt":"2024-10-12T16:32:48","slug":"bouncing-an-asterisk","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=6595","title":{"rendered":"Bouncing an Asterisk"},"content":{"rendered":"<p>For <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6579\">last week&#8217;s Lesson<\/a>, I gathered various techniques to show how the terminal screen can be manipulated directly in C without using a library like Ncurses. I have a few more tricks to show.<br \/>\n<!--more--><br \/>\nThe next item I&#8217;d like to pull from old code is the <em>kbhit()<\/em> function, once popular in C programming for older (non-multitasking) operating systems. I wrote about emulating this function in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6305\">another post<\/a>. As with various terminal manipulation magic, recreating the <em>kbhit()<\/em> function involves a call to the <em>ioctl()<\/em> function to peek into the terminal&#8217;s guts. You can read the details in the original post.<\/p>\n<p>My purpose for adding the <em>kbhit()<\/em> function is to recreate the old bouncing asterisk program, which was popular with budding programmers way back when. The effect is seen as a character that traverses the screen, changing directions when it bumps into the screen&#8217;s edge.<\/p>\n<p>The <em>kbhit()<\/em> function is necessary to poll the keyboard to check for a press of the Enter key, which terminates the program. I also updated the code presented in last week&#8217;s Lesson, modifying the <em>locate()<\/em> function to not only move the cursor but to place a character at the given position. The new function is called <em>putat()<\/em>, and it&#8217;s shown in this update to the source code file:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2024_10_05-Lesson.c\" rel=\"noopener\" target=\"_blank\">2024_10_05-Lesson.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;time.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;sys\/ioctl.h&gt;\r\n\r\n#define home() printf(\"\\e[H\")\r\n#define clear() printf(\"\\e[H\\e[2J\")\r\n\r\n<span class=\"comments\">\/* check for a key waiting *\/<\/span>\r\nint kbhit(void)\r\n{\r\n    int k;\r\n\r\n    ioctl(STDIN_FILENO,FIONREAD,&amp;k);\r\n\r\n    return(k);\r\n}\r\n\r\n<span class=\"comments\">\/* set the cursor to position x (columns)\r\n   and y (rows ) and set character c *\/<\/span>\r\nvoid putat(x,y,c)\r\n{\r\n    printf(\"\\e[%d;%dH%c\",y,x,c);\r\n}\r\n\r\n<span class=\"comments\">\/* pause for m milliseconds *\/<\/span>\r\nvoid delay(int m)\r\n{\r\n    long pause;\r\n    clock_t now,then;\r\n\r\n    pause = m*(CLOCKS_PER_SEC\/1000);\r\n    now = then = clock();\r\n    while( (now-then) &lt; pause )\r\n        now = clock();\r\n}\r\n\r\n<span class=\"comments\">\/* set an asterisk in the center of the screen *\/<\/span>\r\nint main()\r\n{\r\n    int rows,columns,posx,posy,vert,horz;\r\n    struct winsize w;\r\n    char buffer[BUFSIZ];\r\n\r\n    <span class=\"comments\">\/* obtain the window size *\/<\/span>\r\n    ioctl(STDOUT_FILENO, TIOCGWINSZ, &amp;w);\r\n    rows = w.ws_row;\r\n    columns = w.ws_col;\r\n\r\n    <span class=\"comments\">\/* remove line buffering *\/<\/span>\r\n    setvbuf(stdout,buffer,_IONBF,BUFSIZ);\r\n\r\n    <span class=\"comments\">\/* initialize *\/<\/span>\r\n    clear();\r\n    puts(\"Press Enter to end\");\r\n    posx=columns\/2;\r\n    posy=rows\/2;\r\n    vert=1;\r\n    horz=1;\r\n\r\n    <span class=\"comments\">\/* bounce the asterisk *\/<\/span>\r\n    while(1)\r\n    {\r\n        <span class=\"comments\">\/* end the loop on key press *\/<\/span>\r\n        if( kbhit() )\r\n        {\r\n            getchar();\r\n            break;\r\n        }\r\n        <span class=\"comments\">\/* position the cursor *\/<\/span>\r\n        putat(posx,posy,'*');\r\n        delay(125);                <span class=\"comments\">\/* 1\/8 sec. delay *\/<\/span>\r\n        putat(posx,posy,' ');    <span class=\"comments\">\/* erase *\/<\/span>\r\n        <span class=\"comments\">\/* check bounds *\/<\/span>\r\n        if( posx==columns-1 || posx==1 )\r\n            horz=-horz;            <span class=\"comments\">\/* switch directions *\/<\/span>\r\n        posx += horz;\r\n        if( posy==rows-1 || posy==2 )\r\n            vert=-vert;            <span class=\"comments\">\/* switch directions *\/<\/span>\r\n        posy += vert;\r\n    }\r\n    <span class=\"comments\">\/* set the cursor and say goodbye *\/<\/span>\r\n    putat(1,rows-1,'B');\r\n    puts(\"ye!\");\r\n\r\n    return 0;\r\n}<\/pre>\n<p>This code adds four new <em>int<\/em> variables to track the bouncing asterisk: <code>posx<\/code>, <code>posy<\/code>, <code>vert<\/code>, and <code>horz<\/code>. The <code>posx<\/code> and <code>posy<\/code> variables contain the asterisk&#8217;s column and row positions. The <code>vert<\/code> and <code>horz<\/code> variables hold 1 or -1 to set the direction.<\/p>\n<p>The bouncing action takes place in the endless <em>while<\/em> loop. The <em>kbhit()<\/em> function terminates the loop when the user presses the Enter key. (It&#8217;s not a perfect substitute for the original <em>kbhit()<\/em> as other characters entered appear in the output.)<\/p>\n<p>Within the loop, the asterisk is positioned, execution delays for 125 milliseconds, then the asterisk is erased. An <em>if<\/em> test checks for the edges of the terminal window. When encountered, the <code>horz<\/code> or <code>vert<\/code> variables are inverted, changing the asterisk&#8217;s direction. This action repeats until the user presses Enter.<\/p>\n<p>Figure 1 shows a sample run.<\/p>\n<div id=\"attachment_6596\" style=\"width: 650px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-6596\" src=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2024\/09\/bouncing-asterisk_1.gif\" alt=\"\" width=\"640\" height=\"380\" class=\"size-full wp-image-6596\" \/><p id=\"caption-attachment-6596\" class=\"wp-caption-text\">Figure 1. The program&#8217;s sample run.<\/p><\/div>\n<p>I continue messing with these features in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6607\">next week&#8217;s Lesson<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How to manipulate the screen and the keyboard without using a library like Ncurses. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6595\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-6595","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6595","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6595"}],"version-history":[{"count":5,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6595\/revisions"}],"predecessor-version":[{"id":6628,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6595\/revisions\/6628"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6595"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6595"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}