Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <string.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <termios.h> //termios, TCSANOW, ECHO, ICANON
- #include <unistd.h> //STDIN_FILENO
- #include <sys/time.h>
- #define NROFTOWERS 3
- #define LOWERLIMIT 3
- #define UPPERLIMIT 10
- #define LEFT 0
- #define MIDDLE 1
- #define RIGHT 2
- #define SPACE 32
- #define ARROW '\033'
- #define ARIGHT 'C'
- #define ALEFT 'D'
- typedef struct timer {
- struct timeval t1;
- struct timeval t2;
- }timer;
- typedef struct tower {
- int* plates;
- int capacity;
- int cur_size;
- }tower;
- typedef struct hanoi {
- bool solver;
- bool tutorial;
- bool debug;
- int height;
- char height_str[UPPERLIMIT + 1];
- unsigned int moves;
- double playtime;
- int cursor_pos;
- int selection;
- tower** towers;
- }hanoi;
- bool init(int);
- void draw(const char*);
- void play();
- void unload();
- // tower helper
- bool push(tower*, int);
- int pop(tower*);
- bool movePlate(tower*, tower*);
- // gamestate
- void solve(int, tower*, tower*, tower*);
- //void cliffordSolveAtAnyPoint(int, int, int, int);
- bool won();
- void debug();
- void tutorial();
- // options
- void right();
- void left();
- void tselect();
- void unselect();
- void moveplate();
- hanoi* h;
- timer ptime;
- int main (int argc, char* argv[]) {
- int n = 0;
- if (argc == 2) {
- n = atoi(argv[1]);
- }
- if ((argc != 2) || (n < LOWERLIMIT) || (n > UPPERLIMIT)) {
- fprintf(stderr, "%5s: ./hanoi n\n", "Usage" );
- fprintf(stderr, "%5s: Number of tower height. [%i - %i]\n", "n", LOWERLIMIT, UPPERLIMIT);
- return 1;
- }
- if (!init(n)) {
- return 1;
- }
- //solve(h->height, h->towers[LEFT], h->towers[RIGHT], h->towers[MIDDLE]);
- play();
- unload();
- return 0;
- }
- bool init(int n) {
- h = malloc(sizeof(hanoi));
- if (h == NULL) {
- fprintf(stderr, "Can't allocate hanoi memory.\n");
- return false;
- }
- memset(h, 0, sizeof(hanoi));
- // initialize hanoi values
- h->selection = -1;
- h->height = n;
- for (int i = 0; i < n; ++i) {
- h->height_str[i] = '*';
- }
- h->height_str[n] = '\0';
- h->towers = malloc(NROFTOWERS * sizeof(tower*));
- if (h->towers == NULL) {
- fprintf(stderr, "Can't allocate tower* memory.\n");
- return false;
- }
- for (int i = 0; i < NROFTOWERS; ++i) {
- h->towers[i] = malloc(sizeof(tower));
- if (h->towers[i] == NULL) {
- fprintf(stderr, "Can't allocate tower memory.\n");
- return false;
- }
- memset(h->towers[i], 0, sizeof(tower));
- h->towers[i]->plates = malloc(n * sizeof(int));
- if (h->towers[i]->plates == NULL) {
- fprintf(stderr, "Can't allocate plate memory.\n");
- return false;
- }
- memset(h->towers[i]->plates, 0, n * sizeof(int));
- h->towers[i]->capacity = n;
- }
- while (push(h->towers[LEFT], n--)); // fill left tower with plates
- return true;
- }
- void unload() {
- for (int i = 0; i < NROFTOWERS; ++i) {
- free(h->towers[i]->plates);
- h->towers[i]->plates = NULL;
- free(h->towers[i]);
- h->towers[i] = NULL;
- }
- free(h->towers);
- h->towers = NULL;
- free(h);
- h = NULL;
- }
- void draw(const char* msg) {
- int ws, dashs, tildes;
- gettimeofday(&ptime.t2, NULL);
- h->playtime = (ptime.t2.tv_sec - ptime.t1.tv_sec); // sec to ms
- system("clear");
- // draw stats and how to navigate
- printf("%7s: %-10s\t\t%12s: %s\n", "Height", h->height_str, "<Arrow-Keys>", "Move Cursor");
- printf("%7s: %-10i\t\t%12s: %s\n", "Moves", h->moves, "<Space>", "Select / Move Plates");
- printf("%7s: %-10i\t\t%12s: %s\n", "Time(s)", (int)h->playtime, "<q>", "Quit");
- printf("%7s %10s\t\t%12s: %s\n", "", "", "<t>", "Tutorial");
- printf("\n\n");
- // draw towers of hanoi
- for (int i = h->height - 1; i >= 0; --i) { // print nr of height lines
- for (int j = 0; j < NROFTOWERS; ++j) { // build towers
- ws = h->height - h->towers[j]->plates[i];
- dashs = h->towers[j]->plates[i];
- printf(" "); // start with space
- for (int w = 0; w < ws ; ++w) putchar(' ');
- for (int d = 0; d < dashs; ++d) putchar('-');
- putchar('|');
- for (int d = 0; d < dashs; ++d) putchar('-');
- for (int w = 0; w < ws ; ++w) putchar(' ');
- printf(" "); // ends with space
- }
- putchar('\n');
- }
- tildes = NROFTOWERS * (2 * h->height + 5);
- for (int t = 0; t < tildes; ++t) putchar('~');
- putchar('\n');
- // draw interface
- ws = h->height + 1;
- for (int j = 0; j < NROFTOWERS; ++j) { // selection [x] [ ] [ ]
- for (int w = 0; w < ws; ++w) putchar(' ');
- putchar('[');
- if (h->selection == j) putchar('x');
- //
- else putchar(' ');
- putchar(']');
- for (int w = 0; w < ws; ++w) putchar(' ');
- }
- putchar('\n');
- for (int j = 0; j < NROFTOWERS; ++j) { // cursor ^
- for (int w = 0; w < ws; ++w) putchar(' ');
- putchar(' ');
- if (h->cursor_pos == j) putchar('^');
- else putchar(' ');
- putchar(' ');
- for (int w = 0; w < ws; ++w) putchar(' ');
- }
- printf("\n");
- if (h->debug) debug();
- printf("\n%s\n", msg);
- if (h->solver) system("sleep 0.5");
- if (h->tutorial) system("sleep 1.0");
- }
- void play() {
- static struct termios oldt, newt;
- tcgetattr( STDIN_FILENO, &oldt); // changes that getchar() buffers char by char read, not by pressing enter
- newt = oldt;
- newt.c_lflag &= ~(ICANON | ECHO);
- tcsetattr( STDIN_FILENO, TCSANOW, &newt);
- bool exit = false;
- gettimeofday(&ptime.t1, NULL); // start stopwatch
- draw("Welcome to the Tower of Hanoi game!");
- while (!exit) {
- int ch = getchar();
- switch ((ch)) {
- case 'q':
- draw("Exit");
- exit = true;
- break;
- case SPACE:
- if (h->selection == h->cursor_pos) { // position is already selected (remove selection at cursor position)
- unselect();
- }
- else if (h->selection == -1) { // no position selected (select cursor position)
- tselect();
- }
- else { // move plate from top of selected tower to tower at cursor_pos (if possible)
- moveplate();
- if (won()) {
- printf("You have won the game!\n");
- exit = true;
- }
- }
- break;
- case 'd':
- h->debug = !h->debug;
- draw(h->debug ? "Debug-Mode activated" : "Debug-Mode deactivated");
- break;
- case 's': // activate auto solver to help
- h->solver = !h->solver; // idea to turn on and off autosolver
- draw(h->solver ? "Automatic Solving" : "Manual Solving");
- // to solve with recursion you need to find out the actual state of towers to know how to move on
- // FIND HERE
- //solve()
- break;
- case 'h': // help
- break;
- case 't': // tutorial
- tutorial();
- break;
- case ARROW: // == ESCAPE
- getchar(); // consume [ only if ESC Sequence is hit, just an escape get stuck here
- switch (ch = getchar()) {
- case ARIGHT:
- right();
- break;
- case ALEFT:
- left();
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- }
- /*restore the old settings*/
- tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
- }
- void solve(int plate, tower* source, tower* dest, tower* spare) {
- if (plate == 1) { // only 1 plate
- movePlate(source, dest);
- }
- else {
- solve(plate - 1, source, spare, dest);
- movePlate(source, dest);
- solve(plate - 1, spare, dest, source);
- }
- }
- /**
- * Cliffords Solving Algorithm
- * int s: Stack Number (0: LEFT, 1: MIDDLE, 2: RIGHT)
- * int m: Move Number (0: Initial State)
- * int d: Disk Number (1 = Topmost Disk)
- * int n: Total Number Of Disks
- */
- /*void cliffordSolveAtAnyPoint(int s, int m, int d, int n) {
- }*/
- //helper
- bool push(tower* t, int plate) {
- if (t->cur_size == 0) { // empty field, free to push
- t->plates[t->cur_size++] = plate;
- return true;
- }
- 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
- return false;
- }
- t->plates[t->cur_size++] = plate;
- return true;
- }
- int pop(tower* t) {
- if (t->cur_size == 0) {
- return -1; // no more plates to pop
- }
- int plate = t->plates[t->cur_size - 1];
- --t->cur_size;
- t->plates[t->cur_size] = 0;
- return plate; // return top plate and reduce cur_size
- }
- bool movePlate(tower* source, tower* dest) {
- int plate = pop(source);
- if (plate == -1) {
- return false;
- }
- if (push(dest, plate)) {
- ++h->moves;
- return true;
- }
- push(source, plate);
- return false;
- }
- void debug() {
- for (int i = 0; i < NROFTOWERS; ++i) {
- printf("T%i: [", i + 1);
- for (int j = 0; j < h->height; ++j) {
- printf(" %2i", h->towers[i]->plates[j]);
- }
- printf(" ]\n");
- }
- }
- void help() {
- }
- void tutorial() {
- // save old settings
- hanoi tmp;
- hanoi* h_oldadr = &*h; // safe adress of data where h points to
- memcpy(&tmp, h, sizeof(hanoi));
- // create new game
- init(tmp.height);
- h->tutorial = true;
- if (h_oldadr->debug) h->debug = true;
- draw("The aim of the game is to move all plates from the left side to...");
- system("sleep 3.0");
- solve(h->height, h->towers[LEFT], h->towers[RIGHT], h->towers[MIDDLE]);
- h->cursor_pos = 2;
- draw("... the right side. Got it? Press any Key to proceed...");
- getchar();
- solve(h->height, h->towers[RIGHT], h->towers[LEFT], h->towers[MIDDLE]);
- h->cursor_pos = 0;
- h->moves = 0;
- draw("You move the cursor ^ with your Arrow-Keys to the right or left! Here we go...");
- system("sleep 4.0");
- right();
- system("sleep 2.0");
- left();
- system("sleep 2.0");
- draw("Press key to move on...");
- getchar();
- 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...");
- system("sleep 4.0");
- left();
- system("sleep 2.0");
- right();
- system("sleep 2.0");
- draw("Press key to move on...");
- getchar();
- draw("You select a tower by hitting the SPACE button.");
- system("sleep 4.0");
- tselect();
- system("sleep 2.0");
- draw("The selected tower is marked now by the [x]. Press key to move on...");
- getchar();
- draw("Now you can move a plate by selecting another tower...");
- system("sleep 4.0");
- right();
- right();
- system("sleep 1.0");
- moveplate();
- system("sleep 2.0");
- 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");
- getchar();
- draw("You can't move a bigger plate on top of a smaller plate! I'll show you...");
- system("sleep 4.0");
- // move sequence for tutorial
- right();
- tselect();
- left();
- moveplate();
- system("sleep 2.0");
- draw("You see that shit? I told you can't move a bigger plate onto a smaller one!");
- system("sleep 4.0");
- draw("Let me make some moves for you, then you see how this works, ok bro? Press a key...");
- getchar();
- // * _ -
- right();
- tselect();
- right();
- moveplate(); // * --- -
- right();
- tselect();
- left(); // -
- moveplate(); // * --- _
- left();
- tselect();//
- left(); // -
- moveplate(); //* --- -----
- left();
- tselect();
- left();
- moveplate(); // - --- -----
- right();
- tselect();//
- right(); // ---
- moveplate(); // - _ -----
- right();
- tselect();// -
- left(); // ---
- moveplate(); //* _ -----
- system("sleep 2.0");
- draw("Build tower by tower from level to level! You got this, now have fun! Press key to return to your game!");
- getchar();
- 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");
- getchar();
- 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.");
- getchar();
- unload();
- h = h_oldadr; // return h to old memory
- memcpy(h, &tmp, sizeof(hanoi));
- draw("Play your game :)");
- }
- bool won() {
- return (h->towers[NROFTOWERS - 1]->cur_size == h->height); // tower is tranfered to the right.
- }
- /**
- * MOVES
- */
- void right() {
- h->cursor_pos = ++h->cursor_pos % NROFTOWERS; // 3 different cursor positions
- draw("RIGHT");
- }
- void left() {
- int cursor = h->cursor_pos - 1;
- if (cursor < 0) cursor = NROFTOWERS + cursor; // jump from left to right boundary
- h->cursor_pos = cursor;
- draw("LEFT");
- }
- void tselect() {
- h->selection = h->cursor_pos; // select position
- draw("Tower selected!");
- }
- void unselect() {
- h->selection = -1; // unselect
- draw("Tower unselected!");
- }
- void moveplate() {
- bool platemoved = false;
- platemoved = movePlate(h->towers[h->selection], h->towers[h->cursor_pos]);
- h->selection = -1;
- draw(platemoved ? "Plate moved!" : "Can't move plate!");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement