Advertisement
algore87

towers_of_hanoi_cterminal_game

Sep 25th, 2017
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.26 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdbool.h>
  4. #include <stdlib.h>
  5. #include <termios.h>            //termios, TCSANOW, ECHO, ICANON
  6. #include <unistd.h>             //STDIN_FILENO
  7. #include <sys/time.h>
  8.  
  9. #define NROFTOWERS 3
  10. #define LOWERLIMIT 3
  11. #define UPPERLIMIT 10
  12.  
  13. #define LEFT 0
  14. #define MIDDLE 1
  15. #define RIGHT 2
  16.  
  17. #define SPACE 32
  18. #define ARROW '\033'
  19. #define ARIGHT 'C'
  20. #define ALEFT 'D'
  21.  
  22. typedef struct timer {
  23.     struct timeval t1;
  24.     struct timeval t2;
  25. }timer;
  26.  
  27. typedef struct tower {
  28.     int* plates;
  29.     int capacity;
  30.     int cur_size;
  31. }tower;
  32.  
  33. typedef struct hanoi {
  34.     bool solver;
  35.     bool tutorial;
  36.     bool debug;
  37.     int height;
  38.     char height_str[UPPERLIMIT + 1];
  39.     unsigned int moves;
  40.     double playtime;
  41.     int cursor_pos;
  42.     int selection;
  43.     tower** towers;
  44. }hanoi;
  45.  
  46.  
  47. bool init(int);
  48. void draw(const char*);
  49. void play();
  50. void unload();
  51. // tower helper
  52. bool push(tower*, int);
  53. int pop(tower*);
  54. bool movePlate(tower*, tower*);
  55. // gamestate
  56. void solve(int, tower*, tower*, tower*);
  57. //void cliffordSolveAtAnyPoint(int, int, int, int);
  58. bool won();
  59. void debug();
  60. void tutorial();
  61. // options
  62. void right();
  63. void left();
  64. void tselect();
  65. void unselect();
  66. void moveplate();
  67.  
  68. hanoi* h;
  69. timer ptime;
  70.  
  71. int main (int argc, char* argv[]) {
  72.     int n = 0;
  73.     if (argc == 2) {
  74.         n = atoi(argv[1]);
  75.     }
  76.  
  77.     if ((argc != 2) || (n < LOWERLIMIT) || (n > UPPERLIMIT)) {
  78.         fprintf(stderr, "%5s: ./hanoi n\n", "Usage" );
  79.         fprintf(stderr, "%5s: Number of tower height. [%i - %i]\n", "n", LOWERLIMIT, UPPERLIMIT);
  80.         return 1;
  81.     }
  82.  
  83.     if (!init(n)) {
  84.         return 1;
  85.     }
  86.     //solve(h->height, h->towers[LEFT], h->towers[RIGHT], h->towers[MIDDLE]);
  87.     play();
  88.  
  89.     unload();
  90.     return 0;
  91. }
  92.  
  93.  
  94. bool init(int n) {
  95.     h = malloc(sizeof(hanoi));
  96.     if (h == NULL) {
  97.         fprintf(stderr, "Can't allocate hanoi memory.\n");
  98.         return false;
  99.     }
  100.     memset(h, 0, sizeof(hanoi));
  101.  
  102.     // initialize hanoi values
  103.     h->selection = -1;
  104.     h->height = n;
  105.     for (int i = 0; i < n; ++i) {
  106.         h->height_str[i] = '*';
  107.     }
  108.     h->height_str[n] = '\0';
  109.  
  110.     h->towers = malloc(NROFTOWERS * sizeof(tower*));
  111.     if (h->towers == NULL) {
  112.         fprintf(stderr, "Can't allocate tower* memory.\n");
  113.         return false;
  114.     }
  115.  
  116.     for (int i = 0; i < NROFTOWERS; ++i) {
  117.         h->towers[i] = malloc(sizeof(tower));
  118.         if (h->towers[i] == NULL) {
  119.             fprintf(stderr, "Can't allocate tower memory.\n");
  120.             return false;
  121.         }
  122.         memset(h->towers[i], 0, sizeof(tower));
  123.         h->towers[i]->plates = malloc(n * sizeof(int));
  124.         if (h->towers[i]->plates == NULL) {
  125.             fprintf(stderr, "Can't allocate plate memory.\n");
  126.             return false;
  127.         }
  128.         memset(h->towers[i]->plates, 0, n * sizeof(int));
  129.         h->towers[i]->capacity = n;
  130.     }
  131.  
  132.  
  133.     while (push(h->towers[LEFT], n--)); // fill left tower with plates
  134.  
  135.     return true;
  136. }
  137.  
  138. void unload() {
  139.     for (int i = 0; i < NROFTOWERS; ++i) {
  140.         free(h->towers[i]->plates);
  141.         h->towers[i]->plates = NULL;
  142.         free(h->towers[i]);
  143.         h->towers[i] = NULL;
  144.     }
  145.     free(h->towers);
  146.     h->towers = NULL;
  147.     free(h);
  148.     h = NULL;
  149. }
  150.  
  151. void draw(const char* msg) {
  152.     int ws, dashs, tildes;
  153.     gettimeofday(&ptime.t2, NULL);
  154.     h->playtime = (ptime.t2.tv_sec - ptime.t1.tv_sec);      // sec to ms
  155.     system("clear");
  156.     // draw stats and how to navigate
  157.     printf("%7s: %-10s\t\t%12s: %s\n", "Height", h->height_str, "<Arrow-Keys>", "Move Cursor");
  158.     printf("%7s: %-10i\t\t%12s: %s\n", "Moves", h->moves, "<Space>", "Select / Move Plates");
  159.     printf("%7s: %-10i\t\t%12s: %s\n", "Time(s)", (int)h->playtime, "<q>", "Quit");
  160.     printf("%7s %10s\t\t%12s: %s\n", "", "", "<t>", "Tutorial");
  161.  
  162.     printf("\n\n");
  163.     // draw towers of hanoi
  164.     for (int i = h->height - 1; i >= 0; --i) { // print nr of height lines
  165.         for (int j = 0; j < NROFTOWERS; ++j) { // build towers
  166.             ws = h->height - h->towers[j]->plates[i];
  167.             dashs = h->towers[j]->plates[i];
  168.             printf("  "); // start with space
  169.             for (int w = 0; w < ws ; ++w) putchar(' ');
  170.             for (int d = 0; d < dashs; ++d) putchar('-');
  171.             putchar('|');
  172.             for (int d = 0; d < dashs; ++d) putchar('-');
  173.             for (int w = 0; w < ws ; ++w) putchar(' ');
  174.             printf("  "); // ends with space
  175.         }
  176.         putchar('\n');
  177.     }
  178.     tildes = NROFTOWERS * (2 * h->height + 5);
  179.     for (int t = 0; t < tildes; ++t) putchar('~');
  180.     putchar('\n');
  181.     // draw interface
  182.     ws = h->height + 1;
  183.     for (int j = 0; j < NROFTOWERS; ++j) { // selection [x] [ ] [ ]
  184.         for (int w = 0; w < ws; ++w) putchar(' ');
  185.         putchar('[');
  186.         if (h->selection == j) putchar('x');
  187.         //
  188.         else putchar(' ');
  189.         putchar(']');
  190.         for (int w = 0; w < ws; ++w) putchar(' ');
  191.     }
  192.     putchar('\n');
  193.     for (int j = 0; j < NROFTOWERS; ++j) { // cursor      ^
  194.         for (int w = 0; w < ws; ++w) putchar(' ');
  195.         putchar(' ');
  196.         if (h->cursor_pos == j) putchar('^');
  197.         else putchar(' ');
  198.         putchar(' ');
  199.         for (int w = 0; w < ws; ++w) putchar(' ');
  200.     }
  201.     printf("\n");
  202.     if (h->debug) debug();
  203.     printf("\n%s\n", msg);
  204.     if (h->solver) system("sleep 0.5");
  205.     if (h->tutorial) system("sleep 1.0");
  206.  
  207. }
  208.  
  209. void play() {
  210.     static struct termios oldt, newt;
  211.     tcgetattr( STDIN_FILENO, &oldt); // changes that getchar() buffers char by char read, not by pressing enter
  212.     newt = oldt;
  213.     newt.c_lflag &= ~(ICANON | ECHO);
  214.     tcsetattr( STDIN_FILENO, TCSANOW, &newt);
  215.  
  216.  
  217.     bool exit = false;
  218.     gettimeofday(&ptime.t1, NULL); // start stopwatch
  219.     draw("Welcome to the Tower of Hanoi game!");
  220.     while (!exit) {
  221.         int ch = getchar();
  222.         switch ((ch)) {
  223.             case 'q':
  224.                 draw("Exit");
  225.                 exit = true;
  226.                 break;
  227.             case SPACE:
  228.                 if (h->selection == h->cursor_pos) { // position is already selected (remove selection at cursor position)
  229.                     unselect();
  230.                 }
  231.                 else if (h->selection == -1) { // no position selected (select cursor position)
  232.                     tselect();
  233.                 }
  234.                 else { // move plate from top of selected tower to tower at cursor_pos (if possible)
  235.                     moveplate();
  236.                     if (won()) {
  237.                         printf("You have won the game!\n");
  238.                         exit = true;
  239.                     }
  240.                 }
  241.                 break;
  242.             case 'd':
  243.                 h->debug = !h->debug;
  244.                 draw(h->debug ? "Debug-Mode activated" : "Debug-Mode deactivated");
  245.                 break;
  246.             case 's': // activate auto solver to help
  247.                 h->solver = !h->solver; // idea to turn on and off autosolver
  248.                 draw(h->solver ? "Automatic Solving" : "Manual Solving");
  249.                 // to solve with recursion you need to find out the actual state of towers to know how to move on
  250.                 // FIND HERE
  251.                 //solve()
  252.                 break;
  253.             case 'h': // help
  254.                 break;
  255.             case 't': // tutorial
  256.                 tutorial();
  257.                 break;
  258.             case ARROW: // == ESCAPE
  259.                 getchar(); // consume [ only if ESC Sequence is hit, just an escape get stuck here
  260.                 switch (ch = getchar()) {
  261.                     case ARIGHT:
  262.                         right();
  263.                         break;
  264.                     case ALEFT:
  265.                         left();
  266.                         break;
  267.                     default:
  268.                         break;
  269.                 }
  270.                 break;
  271.             default:
  272.                 break;
  273.         }
  274.     }
  275.  
  276.     /*restore the old settings*/
  277.     tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
  278. }
  279.  
  280. void solve(int plate, tower* source, tower* dest, tower* spare) {
  281.     if (plate == 1) { // only 1 plate
  282.         movePlate(source, dest);
  283.     }
  284.     else {
  285.         solve(plate - 1, source, spare, dest);
  286.         movePlate(source, dest);
  287.         solve(plate - 1, spare, dest, source);
  288.     }
  289. }
  290.  
  291. /**
  292.  * Cliffords Solving Algorithm
  293.  * int s: Stack Number (0: LEFT, 1: MIDDLE, 2: RIGHT)
  294.  * int m: Move Number (0: Initial State)
  295.  * int d: Disk Number (1 = Topmost Disk)
  296.  * int n: Total Number Of Disks
  297.  */
  298. /*void cliffordSolveAtAnyPoint(int s, int m, int d, int n) {
  299.  
  300. }*/
  301.  
  302. //helper
  303. bool push(tower* t, int plate) {
  304.     if (t->cur_size == 0) { // empty field, free to push
  305.         t->plates[t->cur_size++] = plate;
  306.         return true;
  307.     }
  308.     if ((t->cur_size >= t->capacity) || (t->plates[t->cur_size - 1] < plate) || (plate < 1) || (plate > h->height)) { // maximum size reached || moving greater plate on smaller one || not a plate
  309.         return false;
  310.     }
  311.     t->plates[t->cur_size++] = plate;
  312.     return true;
  313. }
  314.  
  315. int pop(tower* t) {
  316.     if (t->cur_size == 0) {
  317.         return -1; // no more plates to pop
  318.     }
  319.     int plate = t->plates[t->cur_size - 1];
  320.     --t->cur_size;
  321.     t->plates[t->cur_size] = 0;
  322.     return plate; // return top plate and reduce cur_size
  323. }
  324.  
  325. bool movePlate(tower* source, tower* dest) {
  326.     int plate = pop(source);
  327.     if (plate == -1) {
  328.         return false;
  329.     }
  330.     if (push(dest, plate)) {
  331.         ++h->moves;
  332.         return true;
  333.     }
  334.     push(source, plate);
  335.     return false;
  336. }
  337.  
  338. void debug() {
  339.     for (int i = 0; i < NROFTOWERS; ++i) {
  340.         printf("T%i: [", i + 1);
  341.         for (int j = 0; j < h->height; ++j) {
  342.             printf(" %2i", h->towers[i]->plates[j]);
  343.         }
  344.         printf(" ]\n");
  345.     }
  346. }
  347.  
  348. void help() {
  349.  
  350. }
  351.  
  352. void tutorial() {
  353.     // save old settings
  354.     hanoi tmp;
  355.     hanoi* h_oldadr = &*h; // safe adress of data where h points to
  356.  
  357.     memcpy(&tmp, h, sizeof(hanoi));
  358.     // create new game
  359.     init(tmp.height);
  360.  
  361.     h->tutorial = true;
  362.     if (h_oldadr->debug) h->debug = true;
  363.  
  364.     draw("The aim of the game is to move all plates from the left side to...");
  365.     system("sleep 3.0");
  366.  
  367.     solve(h->height, h->towers[LEFT], h->towers[RIGHT], h->towers[MIDDLE]);
  368.     h->cursor_pos = 2;
  369.  
  370.     draw("... the right side. Got it? Press any Key to proceed...");
  371.     getchar();
  372.  
  373.     solve(h->height, h->towers[RIGHT], h->towers[LEFT], h->towers[MIDDLE]);
  374.     h->cursor_pos = 0;
  375.     h->moves = 0;
  376.  
  377.     draw("You move the cursor ^ with your Arrow-Keys to the right or left! Here we go...");
  378.     system("sleep 4.0");
  379.     right();
  380.     system("sleep 2.0");
  381.     left();
  382.     system("sleep 2.0");
  383.     draw("Press key to move on...");
  384.     getchar();
  385.  
  386.     draw("You can jump from one side to the other, by pressing the Arrow-Keys if the cursor is on a boundary position! Check this out...");
  387.     system("sleep 4.0");
  388.     left();
  389.     system("sleep 2.0");
  390.     right();
  391.     system("sleep 2.0");
  392.     draw("Press key to move on...");
  393.     getchar();
  394.  
  395.     draw("You select a tower by hitting the SPACE button.");
  396.     system("sleep 4.0");
  397.     tselect();
  398.     system("sleep 2.0");
  399.     draw("The selected tower is marked now by the [x]. Press key to move on...");
  400.     getchar();
  401.  
  402.     draw("Now you can move a plate by selecting another tower...");
  403.     system("sleep 4.0");
  404.     right();
  405.     right();
  406.     system("sleep 1.0");
  407.     moveplate();
  408.     system("sleep 2.0");
  409.     draw("That's how it works, but now to the rules which makes the hole game much more interesting! You want to know more? Guess what... PUSH THAT BUTTON");
  410.     getchar();
  411.  
  412.     draw("You can't move a bigger plate on top of a smaller plate! I'll show you...");
  413.     system("sleep 4.0");
  414.  
  415.     // move sequence for tutorial
  416.     right();
  417.     tselect();
  418.     left();
  419.     moveplate();
  420.     system("sleep 2.0");
  421.     draw("You see that shit? I told you can't move a bigger plate onto a smaller one!");
  422.     system("sleep 4.0");
  423.  
  424.     draw("Let me make some moves for you, then you see how this works, ok bro? Press a key...");
  425.     getchar();
  426.                  // *     _   -
  427.     right();
  428.     tselect();
  429.     right();
  430.     moveplate(); // *   ---   -
  431.     right();
  432.     tselect();
  433.     left();      //      -
  434.     moveplate(); // *   ---   _
  435.     left();
  436.     tselect();//
  437.     left();       //   -
  438.     moveplate();  //* --- -----
  439.     left();
  440.     tselect();
  441.     left();
  442.     moveplate();  // - --- -----
  443.     right();
  444.     tselect();//
  445.     right(); //             ---
  446.     moveplate();  // -  _  -----
  447.     right();
  448.     tselect();//             -
  449.     left();  //             ---
  450.     moveplate();  //*   _  -----
  451.  
  452.     system("sleep 2.0");
  453.     draw("Build tower by tower from level to level! You got this, now have fun! Press key to return to your game!");
  454.     getchar();
  455.     draw("Hahaha sorry, one last piece of information. This game is about a story of Brahmin priests, acting out the command of an ancient prophecy, they have to play this with 64 plates!!! KEY");
  456.     getchar();
  457.     draw("If they move one disk round about 1 second, they would need roughly 585 billion years to finish, which is about 42 times the current age of the Universe. If that doesn't blow your MIND, then you have no imagination! KLICK IT.");
  458.     getchar();
  459.  
  460.     unload();
  461.     h = h_oldadr; // return h to old memory
  462.     memcpy(h, &tmp, sizeof(hanoi));
  463.     draw("Play your game :)");
  464. }
  465.  
  466. bool won() {
  467.     return (h->towers[NROFTOWERS - 1]->cur_size == h->height); // tower is tranfered to the right.
  468. }
  469.  
  470. /**
  471.  * MOVES
  472.  */
  473. void right() {
  474.     h->cursor_pos = ++h->cursor_pos % NROFTOWERS; // 3 different cursor positions
  475.     draw("RIGHT");
  476. }
  477.  
  478. void left() {
  479.     int cursor = h->cursor_pos - 1;
  480.     if (cursor < 0) cursor = NROFTOWERS + cursor; // jump from left to right boundary
  481.     h->cursor_pos = cursor;
  482.     draw("LEFT");
  483. }
  484.  
  485. void tselect() {
  486.     h->selection = h->cursor_pos; // select position
  487.     draw("Tower selected!");
  488. }
  489.  
  490. void unselect() {
  491.     h->selection = -1; // unselect
  492.     draw("Tower unselected!");
  493. }
  494.  
  495. void moveplate() {
  496.     bool platemoved = false;
  497.     platemoved = movePlate(h->towers[h->selection], h->towers[h->cursor_pos]);
  498.     h->selection = -1;
  499.     draw(platemoved ? "Plate moved!" : "Can't move plate!");
  500. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement