Advertisement
dmilicev

self_driven_rectangle_v1.c

Nov 11th, 2019
360
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 37.46 KB | None | 0 0
  1. /*
  2.  
  3.     self_driven_rectangle_v1.c      by      Dragan Milicev
  4.  
  5. The solid rectangle can be moved automatic or manualy in 8 directions:
  6.  
  7. UP          up arrow
  8. DOWN        down arrow
  9. LEFT        left arrow
  10. RIGHT       right arrow
  11.  
  12. UP_LEFT     Home        or  Q, q
  13. DOWN_LEFT   End         or  A, a
  14. UP_RIGHT    Page Up     or  W, w
  15. DOWN_RIGHT  Page Down   or  S, s
  16.  
  17. Key Escape ESC for quit program.
  18.  
  19. Also numeric keypad can be used (NumLock must be off).
  20.  
  21. Example of keyboard control.
  22.  
  23. Example of work with pointers.
  24. https://www.tutorialspoint.com/cprogramming/c_pointers.htm
  25.  
  26. Example of structure.
  27. https://www.tutorialspoint.com/cprogramming/c_structures.htm
  28.  
  29. Example of passing a variable to the function by reference,
  30. so the function can change the value of that variable because
  31. it has address (pointer) of variable in memory.
  32.  
  33.     The beginning of the coordinate system is in the upper left UL corner
  34.     of the window and there is a point ( x, y ) = ( xTL, yTL ) = ( 0, 0 )
  35.     x is row, y is column.
  36.     Columns increase to the right and rows increase downwards,
  37.     starting with TL top left point of the console window (0, 0).
  38.  
  39.     Characteristic points of console window and rectangle are:
  40.     TL top left     (x, y) = ( 0, 0) = ( 0          ,           0 )
  41.     TR top right    (x, y) = (80, 0) = ( MAX_COLUMNS,           0 )
  42.     BL bottom left  (x, y) = (0, 24) = ( 0          ,    MAX_ROWS )
  43.     BR bottom right (x, y) = (80,24) = ( MAX_COLUMNS,    MAX_ROWS )
  44.  
  45.     If MAX_COLUMNS 80 and MAX_ROWS 24 exceed the your console window box,
  46.     try reducing them a little by changing the lines of code
  47.  
  48.     #define MAX_COLUMNS 80
  49.     #define MAX_ROWS    24
  50.  
  51.     Rectangle is defined with 4 arguments,
  52.     by top left TL point ( xTL, yTL ) and width and height (from TL point)
  53.  
  54.     rectangle ( xTL , yTL, width , height )
  55.  
  56.     width  is from xTL to the right
  57.     height is from yTL to the down
  58.  
  59.  
  60.  
  61. Rectangle can be moved (controled) in eight directions,
  62. manualy by keyboard or
  63. automatic by program using random numbers generated by the rand() function.
  64. This Control mode (int control) can be changed with the key C.
  65. Default value is Control = AUTOMATIC and it can be
  66. MANUAL      0
  67. AUTOMATIC   1
  68.  
  69.  
  70. Directions of movement are:
  71.  
  72. U   UP          72
  73. D   DOWN        80
  74. L   LEFT        75
  75. R   RIGHT       77
  76. UL  UP_LEFT     71
  77. UR  UP_RIGHT    73
  78. DL  DOWN_LEFT   79
  79. DR  DOWN_RIGHT  81
  80.  
  81.  
  82. Use keys on numpad (NumLock must be off):
  83.  
  84. UL  U   UR
  85.  
  86. L        R
  87.  
  88. DL  D   DR
  89.  
  90.  
  91. Touch point (int tp) is the point of contact of the rectangle with the wall and may be:
  92.  
  93. tp NO        0  default value, there is no contact of the rectangle with the wall
  94.                 _
  95. tp UP       72  ^
  96.  
  97. tp DOWN     80  _
  98.  
  99. tp LEFT     75  |<
  100.  
  101. tp RIGHT    77  >|
  102.  
  103.  
  104. Key B switch Beep mode (sound of rectangle touching the wall) on/off.
  105.  
  106.  
  107. Mode of movement (int modeOfMovement) of rectangle can be:
  108.  
  109. NATURAL 0   bounce angles are equal to bump angles
  110.                  When rectangle hitting a wall,
  111.                  the bounce angle is equal to the bump angle,
  112.                  considering where the touch point is.
  113.                  This is default value modeOfMovement = NATURAL
  114. RANDOM  1   random bounce angles
  115.                  after contact of the rectangle with the wall,
  116.                  a new direction of movement of the rectangle is accidental.
  117.  
  118.  
  119. Opposite directions for bounce angles, considering where the touch point (tp) is, are:
  120.  
  121. Bump        tp      Bounce
  122. direction           direction
  123.               _
  124. U           U ^     D
  125.  
  126. D           D _     U
  127.  
  128. L           L |<    R
  129.  
  130. R           R >|    L
  131.  
  132.               _
  133. UL          U ^     DL
  134.  
  135. UL          L |<    UR
  136.  
  137.               _
  138. UR          U ^     DR
  139.  
  140. UR          R >|    UL
  141.  
  142.  
  143. DL          L |<    DR
  144.  
  145. DL          D _     UL
  146.  
  147.  
  148. DR          D _     UR
  149.  
  150. DR          R >|    DL
  151.  
  152.  
  153. The Speed (int speed) of movement of the rectangle can be changed
  154. using the + or - keys on the numeric keypad.
  155. Speed can be from 0 (the slowest) to 9 (the fastest), including limits.
  156. Default value is speed = 4.
  157. The higher the speed, the shorter is the wait time and vice versa, by using the formula
  158.     wait( T * (10 - speed) );
  159.  
  160.  
  161. Struct rectangle with default values is:
  162.  
  163. struct Rectangle {
  164.     char ch;                // char to print rectangle
  165.     int xTL;                // x (column) coordinate of (TL) top left corner of rectangle
  166.     int yTL;                // y (row)    coordinate of (TL) top left corner of rectangle
  167.     int width;              // width  (number of columns from x to left) of rectangle
  168.     int height;             // height (number of rows    from y to down) of rectangle
  169.     int direction;          // direction of movement of rectangle
  170.     int speed;              // speed of moving rectangle, can be from 1 (the slowest) to 9 (the fastest)
  171.     int tp;                 // touch point is the point of contact of the rectangle with the wall
  172.     int beep;               // Beep when touching a rectangle with a wall
  173.     int control;            // Control mode of movement of rectangle, can be AUTOMATIC or MANUAL
  174.     int modeOfMovement;     // mode of Movement of rectangle, can be NATURAL or RANDOM
  175. };
  176.  
  177. To further develop the program:
  178. Try to change this program and make it a game of tennis.
  179.  
  180. A player can play alone against a computer (one racquet)
  181. or two players against each other (two racquets on the left and right sides of the court).
  182.  
  183. In the first case, allow 5 balls (small solid rectangle).
  184. The ball is lost if it hits the wall behind the racket.
  185.  
  186. In the second case, count the points and play for example up to 11.
  187.  
  188. Display the current score in the top line of the field.
  189.  
  190.  
  191. Author Dragan Milicev
  192. https://web.facebook.com/dmilicev
  193.  
  194. Tested on Windows 7. Coded in CodeBlocks v16.01.
  195. Let me know of any errors (bugs) in the code you encountered, please.
  196.  
  197. To see Ascii codes for keyboard keys try
  198.  key_codes_with_getch()_v1.c
  199. https://pastebin.com/CTb71BSc
  200. and
  201. keyboard_ascii_codes_with_kbhit()_v1.c
  202. https://pastebin.com/7whsRfyj
  203.  
  204. To see demonstrations of print speed in console window try
  205.  hollow rectangle pattern v2.c
  206. https://pastebin.com/c0jWaxas
  207.  
  208. To see demonstrations of generate random integer numbers
  209. between lower and upper, including them try
  210.  generator_of_random_numbers_v1.c
  211. https://pastebin.com/yrzquvWT
  212.  
  213.  
  214. You can find all my C programs at Dragan Milicev's pastebin:
  215.     https://pastebin.com/u/dmilicev
  216.     https://www.facebook.com/dmilicev
  217.  
  218. */
  219.  
  220.  
  221. // ----------BEGIN OF PROGRAM--------------------------------------------------
  222.  
  223. #include <stdio.h>
  224. //#include <stlib.h>        // RAND_MAX is defined in stdlib.h
  225. #include <conio.h>          // for _getch() and _getche()
  226. #include <string.h>         // for puts()
  227. #include <time.h>           // for random numbers, for function rand()
  228. #include <windows.h>        // tracking cursor all the time, for cursor position functions
  229.                             // gotoxy(x,y) , wherex() , wherey(), showcursor(), hidecursor()
  230.  
  231. #define MAX_COLUMNS 80      // of the console window
  232. #define MAX_ROWS    24      // of the console window
  233.  
  234. #define T           10      // for delay(T), waiting for speed, T=1000 for 1 second
  235.  
  236. #define OFF          0      // for Beep mode
  237. #define ON           1      // for Beep mode
  238.  
  239. #define UP          72      // up arrow
  240. #define DOWN        80      // down arrow
  241. #define LEFT        75      // left arrow
  242. #define RIGHT       77      // right arrow
  243.  
  244. #define UP_LEFT     71      // Home
  245. #define UP_RIGHT    73      // Page Up
  246. #define DOWN_LEFT   79      // End
  247. #define DOWN_RIGHT  81      // Page Down
  248.  
  249. #define ESC         27      // to end the program
  250.  
  251. #define MANUAL      0       // Control mode
  252. #define AUTOMATIC   1       // Control mode
  253.  
  254. #define NATURAL     0       // mode of Movement, bounce angles are equal to bump angles
  255. #define RANDOM      1       // mode of Movement, random bounce angles
  256.  
  257.  
  258. struct Rectangle {
  259.     char ch;                // char to print rectangle
  260.     int xTL;                // x (column) coordinate of (TL) top left corner of rectangle
  261.     int yTL;                // y (row)    coordinate of (TL) top left corner of rectangle
  262.     int width;              // width  (number of columns from x to left) of rectangle
  263.     int height;             // height (number of rows    from y to down) of rectangle
  264.     int direction;          // direction of movement of rectangle
  265.     int speed;              // speed of moving rectangle, can be from 0 (the slowest) to 9 (the fastest)
  266.     int tp;                 // touch point is the point of contact of the rectangle with the wall
  267.     int beep;               // Beep when touching a rectangle with a wall
  268.     int control;            // control mode of movement of rectangle, may be AUTOMATIC or MANUAL
  269.     int modeOfMovement;     // mode of movement of rectangle
  270. };
  271.  
  272.  
  273. // wait (do nothing) for time in milliseconds
  274. void wait( int milliseconds )
  275. {
  276.     clock_t start_time = clock();   // get start time
  277.  
  278.     // looping (do nothing) till required time is not acheived
  279.     while ( clock() < start_time + milliseconds )
  280.         ;                           // do nothing
  281. }
  282.  
  283. // generate and return random integer number between lower and upper, including them.
  284. int get_random_integer_from_lower_to_uppper( int lower, int upper )
  285. {
  286.     // generate and return random number between 0 and upper-1
  287.     //return( rand() % upper );
  288.  
  289.     // generate and return random number between 1 and upper
  290.     //return( rand() % upper + 1 );
  291.  
  292.     // generate and return random integer number between lower and upper
  293.     return( (rand() % (upper - lower + 1)) + lower );
  294. }
  295.  
  296.  
  297. // ----------CURSOR CONTROL FUNCTIONS------------------------------------------
  298.  
  299. // make console cursor invisible
  300. void hidecursor()
  301. {
  302.    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  303.    CONSOLE_CURSOR_INFO info;
  304.    info.dwSize = 20;
  305.    info.bVisible = FALSE;
  306.    SetConsoleCursorInfo(consoleHandle, &info);
  307. }
  308.  
  309. // make console cursor invisible
  310. void showcursor()
  311. {
  312.    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  313.    CONSOLE_CURSOR_INFO info;
  314.    info.dwSize = 20;
  315.    info.bVisible = TRUE;
  316.    SetConsoleCursorInfo(consoleHandle, &info);
  317. }
  318.  
  319. // place cursor at position ( x, y ) = ( row, column )
  320. void gotoxy( int x, int y )
  321. {
  322.     COORD coord;
  323.  
  324.     coord.X = x;
  325.     coord.Y = y;
  326.  
  327.     SetConsoleCursorPosition( GetStdHandle(STD_OUTPUT_HANDLE), coord );
  328. }
  329.  
  330. // return x coordinate (column) of current cursor position
  331. // on failure return -1
  332. int wherex()
  333. {
  334.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  335.  
  336.     if (!GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &csbi ) )
  337.         return -1;
  338.  
  339.     return csbi.dwCursorPosition.X;
  340. }
  341.  
  342. // return y coordinate (row) of current cursor position
  343. // on failure return -1
  344. int wherey()
  345. {
  346.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  347.  
  348.     if (!GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi ) )
  349.         return -1;
  350.  
  351.     return csbi.dwCursorPosition.Y;
  352. }
  353.  
  354. // END OF-----CURSOR CONTROL FUNCTIONS------------------------------------------
  355.  
  356.  
  357. // ----------FUNCTIONS TO PRINT HOLLOW AND SOLID RECTANGLE----------------------
  358.  
  359. // Function to print hollow rectangle with char ch, with puts(), 10 times faster than printf()
  360. // from cursor position (x, y) = (row, column)
  361. // width  must be between 2 and MAX_COLUMNS-2 (the smallest rectangle has no interior space, only the sides of the frame)
  362. // height must be between 2 and MAX_ROWS-2    (the smallest rectangle has no interior space, only the sides of the frame)
  363. void print_hollow_rectangle(char ch, int x, int y, int width, int height)
  364. {
  365.     int i;
  366.     char str1[MAX_COLUMNS+1];       // str1 is string for first and last line of rectangle
  367.     char str2[MAX_COLUMNS+1];       // str2 is string for middle lines of rectangle
  368.  
  369.     if( x + width < 1 )             // 2 for two vertical edges of the rectangle
  370.         width = 2;
  371.  
  372.     if( y + height < 2 )            // 2 for two horizontal edges of the rectangle
  373.         height = 2;
  374.  
  375.     if( x + width > MAX_COLUMNS )   // if right side od rectangle greather then MAX_COLUMNS,
  376.         width = MAX_COLUMNS - x;    // then trunc it
  377.  
  378.     if( y + height > MAX_ROWS - 1 ) // if bottom side od rectangle greather then MAX_ROWS,
  379.         height = MAX_ROWS - y;      // then trunc it
  380.  
  381.  
  382.     for (i = 0; i < width; i++)     // creating string for first and last line of rectangle
  383.         str1[i] = ch;
  384.  
  385.     str1[i+1] = '\0';               // end of first and last line string
  386.  
  387.                                     // creating string for middle lines of rectangle
  388.     str2[0] = ch;                   // first left character of middle lines string
  389.     for (i = 1; i < width-1; i++)   // middle characters of middle lines are blanko (space, ' ')
  390.         str2[i] = ' ';
  391.     str2[i] = ch;                   // last right character of middle lines string
  392.     str2[i+1] = '\0';               // end of middle lines string
  393.  
  394.                                     // print rectangle
  395.     gotoxy( x, y );                 // move cursor to (column, row)
  396.     fputs(str1, stdout);            // print string for first line of rectangle without '\n'
  397.  
  398.     for (i = 0; i < height-2; i++)
  399.     {
  400.         gotoxy( x, y+i+1 );         // move cursor to (column, row+i+1)
  401.         fputs(str2, stdout);        // print string for middle lines of rectangle without '\n'
  402.     }
  403.  
  404.     gotoxy( x, y+i+1 );             // move cursor to (column, row+i+1)
  405.     fputs(str1, stdout);            // print string for last line of rectangle without '\n'
  406. }
  407.  
  408.  
  409. // Function to print solid rectangle with char R.ch, with puts(), 10 times faster than printf()
  410. // from cursor position (column, row) = (R.xTL, R.yTL)
  411. // width  must be between 2 and MAX_ROWS-2    (the smallest rectangle has no interior space, only the sides of the frame)
  412. // height must be between 2 and MAX_COLUMNS-2 (the smallest rectangle has no interior space, only the sides of the frame)
  413. void print_solid_rectangle( struct Rectangle R )
  414. {
  415.     int i;
  416.     char str[MAX_COLUMNS+1];                // str is string for one line of rectangle
  417.  
  418.     if( R.xTL + R.width < 1 )
  419.         R.width = 2;                        // 2 for two vertical edges of the rectangle
  420.  
  421.     if( R.yTL + R.height < 2 )
  422.         R.height = 2;                       // 2 for two horizontal edges of the rectangle
  423.  
  424.     if( R.xTL + R.width > MAX_COLUMNS )     // if right side od rectangle greather then MAX_COLUMNS,
  425.         R.width = MAX_COLUMNS - R.xTL;      // then reduce it
  426.  
  427.     if( R.yTL + R.height > MAX_ROWS - 1 )   // if bottom side od rectangle greather then MAX_ROWS,
  428.         R.height = MAX_ROWS - R.yTL;        // then reduce it
  429.  
  430.     for (i = 0; i < R.width; i++)           // fill string str with characters of one rectangle line
  431.         str[i] = R.ch;
  432.  
  433.     str[i] = '\0';                          // end string str
  434.  
  435.     for (i = 0; i < R.height; i++)          // print solid rectangle
  436.     {
  437.         gotoxy( R.xTL, R.yTL+i );           // move cursor to (R.xTL, R.yTL+i+1)
  438.         fputs(str, stdout);                 // print solid rectangle string  without '\n'
  439.     }
  440. }
  441.  
  442. // Function to delete solid rectangle with char R.ch = ' ', with puts(), 10 times faster than printf()
  443. // from cursor position (column, row) = (R.xTL, R.yTL)
  444. // width  must be between 2 and MAX_ROWS-2    (the smallest rectangle has no interior space, only the sides of the frame)
  445. // height must be between 2 and MAX_COLUMNS-2 (the smallest rectangle has no interior space, only the sides of the frame)
  446. void delete_solid_rectangle( struct Rectangle R )
  447. {
  448.     int i;
  449.  
  450.  // print_solid_rectangle() and delete_solid_rectangle only differ along this line of code:
  451.     R.ch = ' ';                     // to erase rectangle, we overwrite it with ' '
  452.  
  453.    char str[MAX_COLUMNS+1];         // str is string for one line of rectangle
  454.  
  455.     if( R.xTL + R.width < 1 )
  456.         R.width = 2;                // 2 for two vertical edges of the rectangle
  457.  
  458.     if( R.yTL + R.height < 2 )
  459.         R.height = 2;               // 2 for two horizontal edges of the rectangle
  460.  
  461.     if( R.xTL + R.width > MAX_COLUMNS )     // if right side od rectangle greather then MAX_COLUMNS,
  462.         R.width = MAX_COLUMNS - R.xTL;      // then reduce it
  463.  
  464.     if( R.yTL + R.height > MAX_ROWS - 1 )   // if bottom side od rectangle greather then MAX_ROWS,
  465.         R.height = MAX_ROWS - R.yTL;        // then reduce it
  466.  
  467.     for (i = 0; i < R.width; i++)   // fill string str with characters of one rectangle line
  468.         str[i] = R.ch;
  469.  
  470.     str[i] = '\0';                  // end string str
  471.  
  472.     for (i = 0; i < R.height; i++)  // print solid rectangle
  473.     {
  474.         gotoxy( R.xTL, R.yTL+i );   // move cursor to (R.xTL, R.yTL+i+1)
  475.         fputs(str, stdout);         // print solid rectangle string  without '\n'
  476.     }
  477. }
  478.  
  479. // END OF---FUNCTIONS TO PRINT HOLLOW AND SOLID RECTANGLE----------------------
  480.  
  481.  
  482. // ----------FUNCTIONS TO MOVE SOLID RECTANGLE---------------------------------
  483.  
  484. // erase current solid rectangle on that place by overwriting it with char ' '
  485. // print new     solid rectangle one row up
  486. void move_solid_rectangle_up( struct Rectangle *R )
  487. {
  488.     if( R->yTL > 1 )                    // if rectangle is below top line of console window frame
  489.     {
  490.         delete_solid_rectangle( *R );   // erase current solid rectangle on that place by overwriting it with char ' '
  491.         (R->yTL)--;                     // one row up
  492.         print_solid_rectangle( *R );    // print new solid rectangle one row up
  493.     }
  494. }
  495.  
  496. // erase current solid rectangle on that place by overwriting it with char ' '
  497. // print new     solid rectangle one row down
  498. void move_solid_rectangle_down( struct Rectangle *R )
  499. {
  500.     if( R->yTL < MAX_ROWS-(R->width) )      // if rectangle is above the penultimate bottom line of the console window frame
  501.     {
  502.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  503.         (R->yTL)++;                         // one row down
  504.         print_solid_rectangle( *R );        // print new solid rectangle one row down
  505.     }
  506. }
  507.  
  508. // erase current solid rectangle on that place by overwriting it with char ' '
  509. // print new     solid rectangle one column left
  510. void move_solid_rectangle_left( struct Rectangle *R )
  511. {
  512.     if( R->xTL > 1 )                        // if rectangle is right from second column of console window frame
  513.     {
  514.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  515.         (R->xTL)--;                         // one column left
  516.         print_solid_rectangle( *R );        // print new solid rectangle one column left
  517.     }
  518. }
  519.  
  520. // erase current solid rectangle on that place by overwriting it with char ' '
  521. // print new     solid rectangle one column right
  522. void move_solid_rectangle_right( struct Rectangle *R )
  523. {
  524.     if( R->xTL < MAX_COLUMNS-(R->width)-1 ) // if rectangle is left from the penultimate right line of the console window frame
  525.     {
  526.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  527.         (R->xTL)++;                         // one column right
  528.         print_solid_rectangle( *R );        // print new solid rectangle one column right
  529.     }
  530. }
  531.  
  532.  
  533.  
  534. // erase current solid rectangle on that place by overwriting it with char ' '
  535. // print new     solid rectangle one row up and one column left
  536. void move_solid_rectangle_up_left( struct Rectangle *R )
  537. {                                           // if rectangle is right from second column of console window frame and
  538.     if( R->xTL > 1 && R->yTL > 1)           // if rectangle is below top line of console window frame
  539.     {
  540.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  541.         (R->xTL)--;                         // one column left
  542.         (R->yTL)--;                         // one row up
  543.         print_solid_rectangle( *R );        // print new solid rectangle one row up and one column left
  544.     }
  545. }
  546.  
  547. // erase current solid rectangle on that place by overwriting it with char ' '
  548. // print new     solid rectangle one row down and one column left
  549. void move_solid_rectangle_down_left( struct Rectangle *R )
  550. {       // if rectangle is right from second column of console window frame and
  551.         // if rectangle is above the penultimate bottom line of the console window frame
  552.     if( R->xTL > 1 && R->yTL < MAX_ROWS-(R->height)-1 )
  553.     {
  554.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  555.         (R->xTL)--;                         // one column left
  556.         (R->yTL)++;                         // one row down
  557.         print_solid_rectangle( *R );        // print new solid rectangle one row down and one column left
  558.     }
  559. }
  560.  
  561. // erase current solid rectangle on that place by overwriting it with char ' '
  562. // print new     solid rectangle one row down and one column right
  563. void move_solid_rectangle_down_right( struct Rectangle *R )
  564. {       // if rectangle is left from the penultimate right line of the console window frame and
  565.         // if rectangle is above the penultimate bottom line of the console window frame
  566.     if( R->xTL < MAX_COLUMNS-(R->width)-1 && R->yTL < MAX_ROWS-(R->height)-1 )
  567.     {
  568.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  569.         (R->xTL)++;                         // one column right
  570.         (R->yTL)++;                         // one row down
  571.         print_solid_rectangle( *R );        // print new solid rectangle one row down and one column right
  572.     }
  573. }
  574.  
  575. // erase current solid rectangle on that place by overwriting it with char ' '
  576. // print new     solid rectangle one row up and one column right
  577. void move_solid_rectangle_up_right( struct Rectangle *R )
  578. {       // if rectangle is below top line of console window frame and
  579.         // if rectangle is left from the penultimate right line of the console window frame
  580.     if( R->yTL > 1 && R->xTL < MAX_COLUMNS-(R->width)-1)
  581.     {
  582.         delete_solid_rectangle( *R );       // erase current solid rectangle on that place by overwriting it with char ' '
  583.         (R->xTL)++;                         // one column right
  584.         (R->yTL)--;                         // one row up
  585.         print_solid_rectangle( *R );        // print new solid rectangle one row up and one column right
  586.     }
  587. }
  588.  
  589. // END OF----FUNCTIONS TO MOVE SOLID RECTANGLE---------------------------------
  590.  
  591.  
  592. // Print the speed status (1-9)
  593. void print_speed_status( struct Rectangle R )
  594. {
  595.     gotoxy( 5, MAX_ROWS-1 );
  596.     printf(" SPEED=%d ", R.speed);
  597. }
  598.  
  599. // Print the Control status ( AUTOMATIC / MANUAL )
  600. void print_control_status( struct Rectangle R )
  601. {
  602.     gotoxy( 20, MAX_ROWS-1 );
  603.  
  604.     if( R.control == AUTOMATIC)
  605.         printf(" CONTROL=AUTOMATIC ");
  606.     else
  607.         printf(" CONTROL=MANUAL ***");
  608. }
  609.  
  610. // Print the current sound mode ( ON / OFF )
  611. void print_beep_status( struct Rectangle R )
  612. {
  613.     gotoxy( 45, MAX_ROWS-1 );
  614.  
  615.     if( R.beep == ON)
  616.         printf(" BEEP=ON *");
  617.     else
  618.         printf(" BEEP=OFF ");
  619. }
  620.  
  621. // Print the mode of movement status ( NATURAL / RANDOM )
  622. void print_mode_status( struct Rectangle R )
  623. {
  624.     gotoxy( 61, MAX_ROWS-1 );
  625.  
  626.     if( R.modeOfMovement == NATURAL )
  627.         printf(" MODE=NATURAL ");
  628.     else
  629.         printf(" MODE=RANDOM *");
  630. }
  631.  
  632. // The first screen at the beginning of the program
  633. // shows the name of the program, the name of the author of the program,
  634. // the instruction manual for the program
  635. void welcome_screen(void)
  636. {
  637.   printf("\n\n Program \"Self Driven Rectangle\" by Dragan Milicev \n\n"
  638.  
  639.              " https://web.facebook.com/dmilicev \n\n\n"
  640.  
  641.              " The solid rectangle can be moved automatic or manualy in 8 directions: \n\n"
  642.              " UP          up arrow \n\n"
  643.              " DOWN        down arrow \n\n"
  644.              " LEFT        left arrow \n\n"
  645.              " RIGHT       right arrow \n\n\n"
  646.  
  647.              " UP_LEFT     Home        or  Q, q \n\n"
  648.              " DOWN_LEFT   End         or  A, a \n\n"
  649.              " UP_RIGHT    Page Up     or  W, w \n\n"
  650.              " DOWN_RIGHT  Page Down   or  S, s \n\n\n"
  651.  
  652.              " Key Escape ESC for quit program. \n\n"
  653.  
  654.              " Also numeric keypad can be used (NumLock must be off). \n\n\n"
  655.  
  656.              " + or - key to change the speed of rectangle \n\n"
  657.  
  658.              " B key changes Beep mode (sound of rectangle touching the wall) ( ON / OFF ) \n\n"
  659.  
  660.              " C key changes Control mode ( AUTOMATIC / MANUAL ) \n\n"
  661.  
  662.              " M key changes mode of Movement of rectangle ( NATURAL / RANDOM ) \n\n\n"
  663.     );
  664.  
  665.     system("PAUSE");    // pause the screen
  666.     system("CLS");      // clear that screen
  667. }
  668.  
  669. // A message at the end of the program
  670. void good_bye_screen(void)
  671. {
  672.     gotoxy( 0, MAX_ROWS );
  673.     printf("\n\n That's All, Folks ! \n\n");
  674. }
  675.  
  676.  
  677. // How to automatic drive rectangle?
  678. // From current position, calculate and make one next move.
  679. // Based on the current direction, position of the touch point and
  680. // mode of movement, we choose new direction.
  681. int automatic_drive_rectangle( struct Rectangle *R )
  682. {
  683. // Based on the direction of movement of the rectangle,
  684. // we move the rectangle and check that it has reached the point of contact with the wall
  685.  
  686.     while( R->tp == 0 )         // while there is no touch point with wall
  687.     {           // keeps the same direction and check for rectangle contact with the wall
  688.         switch( R->direction )
  689.         {
  690.             case UP:
  691.                 if( R->yTL > 1 )
  692.                     move_solid_rectangle_up( &(*R) );
  693.                 else
  694.                     R->tp = UP;
  695.                 break;
  696.             case DOWN:
  697.                 if( R->yTL < MAX_ROWS - R->height -1 )
  698.                     move_solid_rectangle_down( &(*R) );
  699.                 else
  700.                     R->tp = DOWN;
  701.                 break;
  702.             case LEFT:
  703.                 if( R->xTL > 1 )
  704.                     move_solid_rectangle_left( &(*R) );
  705.                 else
  706.                     R->tp = LEFT;
  707.                 break;
  708.             case RIGHT:
  709.                 if( R->xTL < MAX_COLUMNS - R->width - 1   )
  710.                     move_solid_rectangle_right( &(*R) );
  711.                 else
  712.                     R->tp = RIGHT;
  713.                 break;
  714.             case UP_LEFT:
  715.                 if( R->xTL > 1 &&  R->yTL > 1 )
  716.                     move_solid_rectangle_up_left( &(*R) );
  717.                 if( R->xTL == 1 )
  718.                     R->tp = LEFT;
  719.                 if( R->yTL == 1 )
  720.                     R->tp = UP;
  721.                 break;
  722.             case UP_RIGHT:
  723.                 if( R->xTL < MAX_COLUMNS - R->width -1 &&  R->yTL > 1 )
  724.                     move_solid_rectangle_up_right( &(*R) );
  725.                 if( R->xTL == MAX_COLUMNS - R->width -1 )
  726.                     R->tp = RIGHT;
  727.                 if( R->yTL == 1 )
  728.                     R->tp = UP;
  729.                 break;
  730.             case DOWN_LEFT:
  731.                 if( R->xTL > 1 &&  R->yTL < MAX_ROWS - R->height -1 )
  732.                     move_solid_rectangle_down_left( &(*R) );
  733.                 if( R->xTL == 1 )
  734.                     R->tp = LEFT;
  735.                 if( R->yTL == MAX_ROWS - R->height -1 )
  736.                     R->tp = DOWN;
  737.                 break;
  738.             case DOWN_RIGHT:
  739.                 if( R->xTL < MAX_COLUMNS - R->width -1 &&  R->yTL < MAX_ROWS - R->height -1 )
  740.                     move_solid_rectangle_down_right( &(*R) );
  741.                 if( R->xTL == MAX_COLUMNS - R->width -1 )
  742.                     R->tp = RIGHT;
  743.                 if( R->yTL == MAX_ROWS - R->height -1 )
  744.                     R->tp = DOWN;
  745.                 break;
  746.             default:
  747.                 break;
  748.         } // switch( R->direction )
  749.  
  750.         // We calculate the waiting time based on the speed of the rectangle
  751.         // The speed changes from 1 to 9, the waiting time changes from 9 to 1 times T
  752.         wait( T * (10 - R->speed) );
  753.  
  754.     } // while( R->tp == 0 )
  755.  
  756. // Now the rectangle touched the wall. Based on the current direction
  757. // and position of the touch point, we choose new direction:
  758.  
  759. // First, make a sound:     // For greater speeds there is a problem with sound,
  760.     if( R->beep == ON )     // because the rectangle moves faster than the sound can complete
  761.         printf("\a");       // The sound of the rectangle touching the wall
  762.  
  763. /*
  764. Opposite directions for bounce angles, considering where the touch point (tp) is, are:
  765.  
  766. Bump        tp      Bounce
  767. direction           direction
  768.               _
  769. U           U ^     D
  770.  
  771. D           D _     U
  772.  
  773. L           L |<    R
  774.  
  775. R           R >|    L
  776.  
  777.               _
  778. UL          U ^     DL
  779.  
  780. UL          L |<    UR
  781.  
  782.               _
  783. UR          U ^     DR
  784.  
  785. UR          R >|    UL
  786.  
  787.  
  788. DL          L |<    DR
  789.  
  790. DL          D _     UL
  791.  
  792.  
  793. DR          D _     UR
  794.  
  795. DR          R >|    DL
  796. */
  797.  
  798. // Choose bounce angles
  799.     if ( R->modeOfMovement == NATURAL )
  800.     {       // Bounce angles are equal to bump angles.
  801.                 // When rectangle hitting a wall,
  802.                 // the bounce angle is equal to the bump angle,
  803.                 // considering where the touch point is.
  804.         if(R->direction==UP && R->tp==UP)             R->direction=DOWN;
  805.         if(R->direction==DOWN && R->tp==DOWN)         R->direction=UP;
  806.         if(R->direction==LEFT && R->tp==LEFT)         R->direction=RIGHT;
  807.         if(R->direction==RIGHT && R->tp==RIGHT)       R->direction=LEFT;
  808.  
  809.         if(R->direction==UP_LEFT && R->tp==UP)        R->direction=DOWN_LEFT;
  810.         if(R->direction==UP_LEFT && R->tp==LEFT)      R->direction=UP_RIGHT;
  811.  
  812.         if(R->direction==UP_RIGHT && R->tp==UP)       R->direction=DOWN_RIGHT;
  813.         if(R->direction==UP_RIGHT && R->tp==RIGHT)    R->direction=UP_LEFT;
  814.  
  815.         if(R->direction==DOWN_LEFT && R->tp==LEFT)    R->direction=DOWN_RIGHT;
  816.         if(R->direction==DOWN_LEFT && R->tp==DOWN)    R->direction=UP_LEFT;
  817.  
  818.         if(R->direction==DOWN_RIGHT && R->tp==DOWN)   R->direction=UP_RIGHT;
  819.         if(R->direction==DOWN_RIGHT && R->tp==RIGHT)  R->direction=DOWN_LEFT;
  820.     }
  821.     else    // modeOfMovement == RANDOM
  822.     {       // Random bounce angles:
  823.                 // after contact of the rectangle with the wall,
  824.                 // a new direction of movement of the rectangle is accidental.
  825.                 // There are 8 directons of movement and because of that
  826.                 // we need random number form 1 to 8
  827.         switch( get_random_integer_from_lower_to_uppper(1,8) )
  828.         {
  829.             case 1:
  830.                 R->direction=UP;
  831.                 break;
  832.             case 2:
  833.                 R->direction=DOWN;
  834.                 break;
  835.             case 3:
  836.                 R->direction=LEFT;
  837.                 break;
  838.             case 4:
  839.                 R->direction=RIGHT;
  840.                 break;
  841.             case 5:
  842.                 R->direction=UP_LEFT;
  843.                 break;
  844.             case 6:
  845.                 R->direction=UP_RIGHT;
  846.                 break;
  847.             case 7:
  848.                 R->direction=DOWN_LEFT;
  849.                 break;
  850.             case 8:
  851.                 R->direction=DOWN_RIGHT;
  852.                 break;
  853.             default:
  854.                 break;
  855.         } // switch( get_random_integer_from_lower_to_uppper(1,8) )
  856.  
  857.     } // else   // modeOfMovement == RANDOM
  858.  
  859.  
  860.     R->tp = 0;  // reset, now there is no contact of the rectangle with the wall
  861.  
  862. // Now we have new direction and we are redy for next move.
  863.  
  864.     wait( T * (10 - R->speed) );    // waiting time, slowing down
  865.  
  866.     return 0;
  867. }
  868.  
  869.  
  870. // ----------KEYBOARD CONTROL--------------------------------------------------
  871.  
  872. /*
  873.     Keyboard control:
  874.  
  875. The solid rectangle can be manualy moved in 8 directions:
  876.  
  877. UP          up arrow
  878. DOWN        down arrow
  879. LEFT        left arrow
  880. RIGHT       right arrow
  881.  
  882. UP_LEFT     Home        or  Q, q
  883. DOWN_LEFT   End         or  A, a
  884. UP_RIGHT    Page Up     or  W, w
  885. DOWN_RIGHT  Page Down   or  S, s
  886.  
  887. Key Escape, ESC (27) for quit.
  888. */
  889. int keyboard_control(void)
  890. {
  891.     int choice;                                 // for pressed key
  892.     struct Rectangle R;
  893.  
  894.     R.ch = '*';                                 // initial values for rectangle R
  895.     R.xTL = 35;                                 // starting position of hollow rectangle
  896.     R.yTL = 10;
  897.     R.width = 4;                                // dimension of solid rectangle
  898.     R.height = 3;
  899.     R.direction = UP_LEFT;                      // starting move of solid rectangle
  900.     R.speed = 4;                                // speed can be from 1 to 10
  901.     R.tp = 0;                                   // there is no touch point of rectangle with wall
  902.     R.beep = ON;                                // Beep mode is default ON
  903.     R.control = AUTOMATIC;      // Control mode of movement of rectangle, may be AUTOMATIC or MANUAL
  904.     R.modeOfMovement = NATURAL;                 // mode of Movement of rectangle
  905.  
  906.     hidecursor();
  907.                                                 // print console window frame
  908.     print_hollow_rectangle( '*', 0, 0, MAX_COLUMNS, MAX_ROWS );
  909.  
  910.                                                 // Print default values
  911.     print_speed_status( R );                    // Print the initial speed for the first time
  912.     print_control_status( R );                  // Print the default Control mode for the first time
  913.     print_beep_status( R );                     // Print the default Beep mode for the first time
  914.     print_mode_status( R );                     // Print the default mode of Movement status for the first time
  915.  
  916.     print_solid_rectangle( R );                 // starting position for solid rectangle
  917.  
  918.     while( 1 ) {                                // an infinite loop that exits with choice Ecsape, ESC (27)
  919.  
  920.         if ( R.control == AUTOMATIC )           // If the computer controls a rectangle
  921.         {
  922.             while( !_kbhit() )                  // rotates in that loop until some key is pressed
  923.             {
  924.                 automatic_drive_rectangle( &R );    // because no key was pressed
  925.             }
  926.         }
  927.  
  928.         choice = _getch();                      // now key is pressed, read the keyboard
  929.  
  930.         if( choice == 0 || choice == 224 )      // if is pressed function key with leading 0 or 224
  931.         {
  932.             choice = _getch();                  // let's empty that 0 or 224
  933.  
  934.             if( choice == UP )                  // if pressed up arrow
  935.                 move_solid_rectangle_up( &R );
  936.  
  937.             if( choice == DOWN )                // if pressed down arrow
  938.                 move_solid_rectangle_down( &R );
  939.  
  940.             if( choice == LEFT )                // if pressed left arrow
  941.                 move_solid_rectangle_left( &R );
  942.  
  943.             if( choice == RIGHT )               // if pressed right arrow
  944.                 move_solid_rectangle_right( &R );
  945.  
  946.             if( choice == UP_LEFT )             // if pressed Home
  947.                 move_solid_rectangle_up_left( &R );
  948.  
  949.  
  950.             if( choice == DOWN_LEFT )           // if pressed End
  951.                 move_solid_rectangle_down_left( &R );
  952.  
  953.             if( choice == UP_RIGHT )            // if pressed Page Up
  954.                 move_solid_rectangle_up_right( &R );
  955.  
  956.             if( choice == DOWN_RIGHT )          // if pressed Page Down
  957.                 move_solid_rectangle_down_right( &R );
  958.  
  959.         } // end of: if is pressed function key with leading 0 or 224
  960.         else    // if pressed ordinary key
  961.         {
  962.             if( choice == 'Q' || choice == 'q' )    // if is pressed ordinary key Q or q
  963.                 move_solid_rectangle_up_left( &R );
  964.  
  965.             if( choice == 'A' || choice == 'a' )    // if is pressed ordinary key A or a
  966.                 move_solid_rectangle_down_left( &R );
  967.  
  968.             if( choice == 'W' || choice == 'w' )    // if is pressed ordinary key W or w
  969.                 move_solid_rectangle_up_right( &R );
  970.  
  971.             if( choice == 'S' || choice == 's' )    // if is pressed ordinary key S or s
  972.                 move_solid_rectangle_down_right( &R );
  973.  
  974.             if( choice == '+' )                     // The + key is pressed
  975.             {
  976.                 if( R.speed < 9 )
  977.                     R.speed++;                      // we increase the speed
  978.  
  979.                 print_speed_status( R );            // print the speed
  980.             }
  981.  
  982.             if( choice == '-' )                     // The - key is pressed
  983.             {
  984.                 if( R.speed > 1 )
  985.                     R.speed--;                      // we decrease the speed
  986.  
  987.                 print_speed_status( R );            // print the speed
  988.             }
  989.  
  990.             if( choice == 'b' || choice == 'B' )    // The B key is pressed
  991.             {
  992.                 if( R.beep == ON )                  // we change Beep mode
  993.                     R.beep = OFF;                   // ( ON or OFF )
  994.                 else
  995.                     R.beep = ON;
  996.             }
  997.  
  998.             if( R.speed > 7 )   // At higher speeds there is a problem with Beep
  999.                 R.beep=OFF;     // because the rectangle moves faster than the sound can complete
  1000.  
  1001.             print_beep_status( R );                 // print the Beep status
  1002.  
  1003.             if( choice == 'c' || choice == 'C' )    // The C key is pressed
  1004.             {
  1005.                 if( R.control == AUTOMATIC )        // we change Control mode
  1006.                     R.control = MANUAL;             // ( AUTOMATIC or MANUAL )
  1007.                 else
  1008.                     R.control = AUTOMATIC;
  1009.  
  1010.                 print_control_status( R );          // print the Control mode status
  1011.             }
  1012.  
  1013.             if( choice == 'm' || choice == 'M' )    // The M key is pressed
  1014.             {
  1015.                 if( R.modeOfMovement == NATURAL )   // we change mode of Movement
  1016.                     R.modeOfMovement = RANDOM;      // ( NATURAL or RANDOM )
  1017.                 else
  1018.                     R.modeOfMovement = NATURAL;
  1019.  
  1020.                 print_mode_status( R );             // print the mode of Movement status
  1021.             }
  1022.  
  1023.             if( choice == ESC )                     // if is pressed ESC
  1024.             {
  1025.                 showcursor();                       // before exiting function
  1026.                 return( choice );                   // end of work, have to return something
  1027.             }
  1028.  
  1029.         } // end of: if pressed ordinary key
  1030.  
  1031.     } // end of: while( 1 )
  1032.  
  1033.     showcursor();                                   // before exiting function
  1034.     return( choice );                               // end of work, have to return something
  1035. }
  1036.  
  1037. // END OF----KEYBOARD CONTROL--------------------------------------------------
  1038.  
  1039.  
  1040. int main(void)
  1041. {
  1042.     time_t t;   // for random number generator
  1043.  
  1044.     // Intializes random number generator, should only be called once.
  1045.     srand((unsigned) time(&t));
  1046.  
  1047.  
  1048.     welcome_screen();
  1049.  
  1050.     keyboard_control();
  1051.  
  1052.     good_bye_screen();
  1053.  
  1054.  
  1055.     return 0;
  1056. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement