You are not logged in.

#1 2010-02-26 01:05:46

ldvx
Member
Registered: 2007-01-02
Posts: 33

Easy game in C

Hello, I am starting to learn programming. I wanted to share the first program I have written in C besides from some K&R2 exercises. It helped me learning functions and pointers. I think it is working well, except because of the fact that I can't get it to do what I want within the while loop

1) For instance, I would like to do this:

get input from user, if input is not a number then print "It is a number" and start the loop again.

  I wrote this as if('0' > userinput || '9' < userinput) {printf("Not a number\n"); continue;}
 
but all I get is an infinite loop, I though that continue within the if  statement was supposed to start the loop from the start, but it does never asks me to input the number again and it loops infinitely.

2) I guess I could use a goto, but I have read is it never a good programming practice
3) I have read also that I should never use scanf. I found sscanf, but I don't know how to get a string input from the user (I saw gets() but the compiler warned me about not using it).

After I get the infite loop while user input is not a letter fixed I intend to generate the numbers randomly (I think I know how to do this, either rand() or something like random_shuffle algorithm in <algorithm> in C++) and finally 'beautify' the program by either using ncurses or getting printf flush previous printed statements.


Here is the code, thanks a lot for your patience and for any feedback.

1 #include <stdio.h>
  2 #include <stdlib.h>
  3 void printTable(int *numbers_ptr);
  4 void swapVariables(int *numbers_ptr, int userinput);
  5 int compareArrays(int *numbers_ptr);
  6 
  7 int main()
  8 {
  9     //0 in numbers[] will represent an empty space
 10     int numbers[16] = {1,2,4,3,5,6,7,8,9,10,11,12,13,14,15,0};
 11     int *numbers_ptr;
 12     int userinput=0;
 13     numbers_ptr = numbers;
 14 
 15     printf("Let's start a game!\n");
 16     printTable(numbers_ptr);
 17 
 18 
 19     while(1)
 20     {
 21 
 22         printf("Enter number: ");
 23         scanf("%d",&userinput);
 24         swapVariables(numbers_ptr,userinput);
 25         printTable(numbers_ptr);
 26 
 27 
 28         if(compareArrays(numbers_ptr) == 1){break;}
 29     }
 30 
 31 
 32     printf("Congratulations. You have completed the game!\n");
 33     return 0;
 34 }
 35 
 36 
 37 void printTable(int *numbers_ptr){
 38 /* The loop starts with 1 for 
 39  * formatting purposes and the magic -1 fixes computations
 40  */
 41     int i;
 42     for(i=1; i <= 16; i++){
 43         printf("%4d ",*(numbers_ptr+i-1));
 44         if(i % 4 == 0)
 45             printf("\n");}
 46 }
 47 
48 
 49 void swapVariables(int *numbers_ptr, int userinput){
 50     int i,swap;
 51     int loc1,loc2; //Store indexes of array that need swapping
 52                     // loc1 is 0 and loc2 is the user input.
 53 
 54     for(i=0; i<16; i++){
 55         if(*(numbers_ptr+i) == 0)
 56             loc1 = i;
 57         if(*(numbers_ptr+i) == userinput)
 58             loc2 = i;}
 59 // Make sure you can swap only with contigous numbers
 60     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
 61         swap = *(numbers_ptr+loc1);
 62         *(numbers_ptr+loc1) = *(numbers_ptr+loc2);
 63         *(numbers_ptr+loc2) = swap;
 64     }
 65     else
 66         printf("That move is not allowed\n");
 67 }
 68 
 69 
 70 int compareArrays(int *numbers_ptr){
 71     int numbersFinal[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
 72     int i;
 73     for(i=0; i<16; i++){
 74         if(numbersFinal[i] != *(numbers_ptr+i))
 75             return(0);
 76     }
 77     return(1);
 78 }

Offline

#2 2010-02-26 01:17:50

n0dix
Member
Registered: 2009-09-22
Posts: 956

Re: Easy game in C

1) you can use the function isdigit().
See this example:http://www.elook.org/programming/c/isdigit.html
2) Never use goto

Last edited by n0dix (2010-02-26 01:18:01)

Offline

#3 2010-02-26 03:17:45

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,804

Re: Easy game in C

You know, this looks suspiciously like a homework problem.

Never-the-less, since you stated it was a learning exercise, allow me to just suggest you compare and contrast  continue with break

Also look at the effect of {} on things -- especially continue and break.

Take a look at getc.

edit: added more hints

Last edited by ewaller (2010-02-26 03:23:44)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#4 2010-02-26 09:36:04

ldvx
Member
Registered: 2007-01-02
Posts: 33

Re: Easy game in C

Thank you n0dix and ewaller. The code is working fairly well now, I think I'll try to 'beautify' a little the game. As a matter of fact, I got the idea out of a cs51 class from a harvard podcast (http://academicearth.org/courses/introd … -science-i). I ended up using fgets() with sscanf(), but I'll try out getc() as soon as I can. I think I understand break and continue better now. However, I do not understand what effects the brackets have on them. I thought it didn't matter if you used brackets or not when you have only one statement. And that brackets mattered when using nested loops to avoid, for instance, an else going with an undesirable if. Do you recommend any links on this subject?

This is how my code ended up, thanks for any feedback.

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 void printTable(int *numbers_ptr);
  4 void swapVariables(int *numbers_ptr, int user_input2);
  5 int compareArrays(int *numbers_ptr);
  6 
  7 int main()
  8 {
  9     //0 in numbers[] will represent an empty space
 10     int numbers[16] = {1,2,4,3,5,6,7,8,9,10,11,12,13,14,15,0};
 11     int *numbers_ptr;
 12     int user_input2=0;    //user input after sanity check
 13     char user_input[10]; //user input originally
 14 
 15     numbers_ptr = numbers;
 16     printf("Let's start a game!\n");
 17     printTable(numbers_ptr);
 18 
 19     while(1)
 20     {
 21         fputs("Enter a number: ",stdout);
 22         fflush(stdout);
 23         if (fgets(user_input,sizeof user_input, stdin)){
 24             if (sscanf(user_input, "%d", &user_input2) == 1)
 25                 printf("number = %d\n",user_input2);}
 26 
 27         if(*user_input >= '0' && *user_input <= '9') {
 28             swapVariables(numbers_ptr,user_input2);
 29             printTable(numbers_ptr);}
 30 
 31         else if(compareArrays(numbers_ptr) == 1)
 32             break;
 33 
 34         else
 35             printf("You did not enter a number!\n");
 36     }
 37 
 38     printf("Congratulations. You have completed the game!\n");
 39     return 0;
 40 }
 41 
 42 
 43 void printTable(int *numbers_ptr){
 44 /* The loop starts with 1 for 
 45  * formatting purposes and the magic -1 fixes computations
 46  */
 47     int i;
 48     for(i=1; i <= 16; i++){
 49         printf("%4d ",*(numbers_ptr+i-1));
 50         if(i % 4 == 0)
 51             printf("\n");}
 52 }
 53 
 54 
 55 void swapVariables(int *numbers_ptr, int user_input2){
 56     int i,swap;
 57     int loc1,loc2; //Store indexes of array that need swapping
 58                     // loc1 is 0 and loc2 is the user input.
 59 
 60     for(i=0; i<16; i++){
 61         if(*(numbers_ptr+i) == 0)
 62             loc1 = i;
 63         else if(*(numbers_ptr+i) == user_input2)
 64             loc2 = i;}
 65 // Make sure you can swap only with contigous numbers
 66     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
 67         swap = *(numbers_ptr+loc1);
 68         *(numbers_ptr+loc1) = *(numbers_ptr+loc2);
 69         *(numbers_ptr+loc2) = swap;
 70     }
 71     else
 72         printf("That move is not allowed\n");
 73 }
 74 
 75 
 76 int compareArrays(int *numbers_ptr){
 77     int numbersFinal[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
 78     int i;
 79     for(i=0; i<16; i++){
 80         if(numbersFinal[i] != *(numbers_ptr+i))
 81             return(0);
 82     }
 83     return(1);
 84 }

note:

if(*user_input >= '0' && *user_input <= '9')

checks if the original input by user corresponds to numbers from 0 to 9 according to the ASCII table. I used the dereference  operator to get the ASCII value of user_input (otherwise I think I only got the memory address of user_input). I tried using isdigit() with user_input and user_input2, but it didn't give me the same results.

Last edited by ldvx (2010-02-26 09:38:12)

Offline

#5 2010-02-26 13:44:51

n0dix
Member
Registered: 2009-09-22
Posts: 956

Re: Easy game in C

The idea of use is to use with a int argument. If you use isdigit(user_input) != isdigit(user_input2).
Btw, if your code do want you want cheers you that.

Offline

#6 2010-02-26 14:00:11

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: Easy game in C

ldvx wrote:

Thank you n0dix and ewaller. The code is working fairly well now, I think I'll try to 'beautify' a little the game. As a matter of fact, I got the idea out of a cs51 class from a harvard podcast (http://academicearth.org/courses/introd … -science-i). I ended up using fgets() with sscanf(), but I'll try out getc() as soon as I can. I think I understand break and continue better now. However, I do not understand what effects the brackets have on them. I thought it didn't matter if you used brackets or not when you have only one statement. And that brackets mattered when using nested loops to avoid, for instance, an else going with an undesirable if. Do you recommend any links on this subject?

Brackets are required when a block has more than one code statement in it.  I wouldn't go so far as to say "it doesn't matter", because it can make an immense difference to readability.  You can use brackets to "force" an else to go with the if you want it to go with.  It seems like your understanding is correct, so I'm not sure what you (or ewaller) meant by what effect brackets have on break/continue.  (Note that a break jumps out of the inmost nested loop -- there's no multi-level break in C.)

This is how my code ended up, thanks for any feedback.

Well, you asked for it.

int main()

I, and many C experts, prefer int main(void).

     int user_input2=0;    //user input after sanity check
     char user_input[10]; //user input originally
 
     numbers_ptr = numbers;

You're being inconsistent in your use of whitespace.  I prefer to have space on both sides of the equals sign in an assignment statement.  If you think that's unnecessary, that's great, but I would advise picking a consistent style.

     while(1)

for(;;) is idiomatic, but in this case it might be better to loop on a variable that you can set to 0 within the loop when you want to stop playing.

     {

You're also inconsistent with brace placement.  The most common C usage I have seen is to leave the opening brace on the same line as the conditional and give the closing brace a line to itself, and to have both the opening and closing braces of a function block on their own lines.  There are lots of other, equally acceptable styles, but consistency is key.

         fputs("Enter a number: ",stdout);

Any reason not to use printf here?

         fflush(stdout);

Good job.  I always forget to do this.

         if (fgets(user_input,sizeof user_input, stdin)){

Inserting whitespace after commas in a list and before the opening brace will aid readability.

             if (sscanf(user_input, "%d", &user_input2) == 1)
                 printf("number = %d\n",user_input2);}

This is probably the stylistic choice I like the least about your code.  I would drop that } onto a line of its own if I were you.

         if(*user_input >= '0' && *user_input <= '9') {

if (isdigit(*user_input)) {

     return 0;

return EXIT_SUCCESS is more explicit.

 void printTable(int *numbers_ptr){
 44 /* The loop starts with 1 for 
 45  * formatting purposes and the magic -1 fixes computations
 46  */

I understand why you did that, but to me it would make more sense to loop on a number that is meaningful to your data and manipulate it for formatting rather than the other way around.

     int i;
     for(i=1; i <= 16; i++){
         printf("%4d ",*(numbers_ptr+i-1));

How about printf("%4d ", *(numbers_ptr++)); ?  Idiomatic, perhaps a little difficult to get your brain around at first, but much more C-like.

         if(i % 4 == 0)
             printf("\n");}

This is why I don't like having the brace on the end of the last line of the block.  It's ambiguous whether the brace goes with the for, or the if, or (perhaps) something else farther up the line, and there's no way to know for sure except by counting the indentation level of the next line (which could easily go wrong) or digging through yourself to find the opening brace.  (This is a fairly obvious case, but I just want you to understand how it could be ambiguous.)

 void swapVariables(int *numbers_ptr, int user_input2){
     int i,swap;
     int loc1,loc2; //Store indexes of array that need swapping
                     // loc1 is 0 and loc2 is the user input.
 
     for(i=0; i<16; i++){
         if(*(numbers_ptr+i) == 0)
             loc1 = i;
         else if(*(numbers_ptr+i) == user_input2)
             loc2 = i;}
 // Make sure you can swap only with contigous numbers
     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
         swap = *(numbers_ptr+loc1);
         *(numbers_ptr+loc1) = *(numbers_ptr+loc2);
         *(numbers_ptr+loc2) = swap;

What's with all the *(array + index) stuff?  That is exactly equivalent to array[index], and the latter form is preferred when you're dealing with actual arrays.  Or were you not familiar with that notation?

     }
     else

Minor stylistic nit:  I would put the else on the same line as the closing brace.

         printf("That move is not allowed\n");
 }
 
 75 
 76 int compareArrays(int *numbers_ptr){
 77     int numbersFinal[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
 78     int i;
 79     for(i=0; i<16; i++){
 80         if(numbersFinal[i] != *(numbers_ptr+i))
 81             return(0);
 82     }
 83     return(1);
 84 }

note:

if(*user_input >= '0' && *user_input <= '9')

checks if the original input by user corresponds to numbers from 0 to 9 according to the ASCII table. I used the dereference  operator to get the ASCII value of user_input (otherwise I think I only got the memory address of user_input). I tried using isdigit() with user_input and user_input2, but it didn't give me the same results.

You need to pass isdigit a character, not a string.  As it happens, the C standard requires that 0-9 be in consecutive numeric order (not the case for alphabetic characters, e.g. 'b' is not necessarily one greater than 'a'), but isdigit() is clearer anyway.

A few points.
* camelCase and underscore_variables are both acceptable; however, you seem to be mixing the two styles.  It's preferable to use one style consistently.
* If you have a copy of K&R2, I would strongly encourage you to attempt all the exercises in it.  They will give you valuable practice and some insight into how C is used to solve problems.
* I think C is a great language to learn data structures with.  If you're bored, look up some resources on linked lists, binary search trees, heaps, that sort of thing, and sorting algorithms.
* Never say never.  goto is most useful for jumping out of multiply nested loops (where a simple 'break' won't do).  Use with discretion.
* scanf is designed for formatted input (files adhering to a strict format), not user input, so don't use it for interactive programs, but it works great when reading, say, a table of (x,y) pairs.  Don't throw away your refrigerator because it doesn't function as a microwave.

Just out of curiosity, what languages have you used before?  You show much better understanding of C than I had when I first started.

Offline

#7 2010-02-26 16:15:44

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,804

Re: Easy game in C

Trent wrote:

so I'm not sure what you (or ewaller) meant by what effect brackets have on break/continue.

What I meant is that {break;} is essentially a "no-operation".  It opens a block, and then breaks out of that block.  I would bet the compiler optimizes this whole thing away.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#8 2010-02-26 16:34:09

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: Easy game in C

ewaller wrote:
Trent wrote:

so I'm not sure what you (or ewaller) meant by what effect brackets have on break/continue.

What I meant is that {break;} is essentially a "no-operation".  It opens a block, and then breaks out of that block.  I would bet the compiler optimizes this whole thing away.

not really.

while (1) { if (1) { break; } }
while (1) { { break; } }

Both examples will break you out of the while-loop.

Offline

#9 2010-02-26 16:57:31

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,804

Re: Easy game in C

Cerebral wrote:

not really.

Yep, you are right. Mea culpa.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#10 2010-02-27 02:54:38

ldvx
Member
Registered: 2007-01-02
Posts: 33

Re: Easy game in C

Thank you very very much Trent! I hadn't realize the mess I had with consistency. 

Trent wrote:
 void swapVariables(int *numbers_ptr, int user_input2){
     int i,swap;
     int loc1,loc2; //Store indexes of array that need swapping
                     // loc1 is 0 and loc2 is the user input.
 
     for(i=0; i<16; i++){
         if(*(numbers_ptr+i) == 0)
             loc1 = i;
         else if(*(numbers_ptr+i) == user_input2)
             loc2 = i;}
 // Make sure you can swap only with contigous numbers
     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
         swap = *(numbers_ptr+loc1);
         *(numbers_ptr+loc1) = *(numbers_ptr+loc2);
         *(numbers_ptr+loc2) = swap;

What's with all the *(array + index) stuff?  That is exactly equivalent to array[index], and the latter form is preferred when you're dealing with actual arrays.  Or were you not familiar with that notation?

Here I have a question (I commented poorly on that piece of code). numbers_ptr is a pointer that points to the array numbers[]. Therefore, numbers_ptr isn't technically an array, right? Nevertheless, I can treat it like one. *(numbers_ptr+i) is equivalent to numbers_ptr[i]. I changed all my code to treat that pointer like an array (I think it is easier to read as the syntax is easier)... is this a recommended style or should I just use *(numbers_ptr+i) when dealing with pointers pointing to arrays?
Thank you for post, it is extremely helpful. Before C I wrote some extremely basic C++ programs. One to generate 5 random numbers, and another one to get the time on the system and computate working days left until the end of the year (it could also accept input as in dd/mm/yy). I think it gave me a decent grasp on arrays.

So here is how the code ended up, again, thanks a lot. Oh, I had a bit of a hard time trying to use EXIT_SUCCESS but I think I understand why: it is a keyword and to use it I have to include the header <stdlib.h> and its value is 0.

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <ctype.h>
  4 void print_table(int *numbers_ptr);
  5 void swap_variables(int *numbers_ptr, int user_input2);
  6 int compare_arrays(int *numbers_ptr);
  7 
  8 int main(void)
  9 {
 10     //0 in numbers[] will represent an empty space
 11     int numbers[16] = {1,2,4,3,5,6,7,8,9,10,11,12,13,14,15,0};
 12     int *numbers_ptr;
 13     int user_input2 = 0;    //user input after sanity check
 14     char user_input[10];    //user input originally
 15 
 16     numbers_ptr = numbers;
 17     printf("Let's start a game!\n");
 18     print_table(numbers_ptr);
 19 
 20     while(1)
 21     {
 22         printf("Enter a number: ");
 23         fflush(stdout);
 24         if(fgets(user_input, sizeof user_input, stdin)){
 25         //  if(sscanf(user_input, "%d", &user_input2) == 1)
 26         //  sscanf returns 1 if it copies successfully?
 27             sscanf(user_input, "%d", &user_input2);
 28         }
 29 
 30         if(isdigit(*user_input)){
 31             swap_variables(numbers_ptr, user_input2);
 32             print_table(numbers_ptr);
 33         }
 34 
 35         else if(compare_arrays(numbers_ptr) == EXIT_SUCCESS)
 36             break;
 37         else if(*user_input == 'q')
 38             break;
 39         else
 40             printf("You did not enter a number!\n");
 41     }
 42 
 43     printf("Congratulations. You have completed the game!\n");
 44     return(EXIT_SUCCESS);
 45 }
 46 
 47                 
48 void print_table(int *numbers_ptr){
 49     int i;
 50     for(i = 0; i < 16; i++){
 51         if(numbers_ptr[i] == 0)
 52             printf("%5c", NULL);
 53         else
 54             printf("%4d", numbers_ptr[i]);
 55         // i+1 fixes computations for formatting purposes
 56         if((i + 1) % 4 == 0)
 57             printf("\n");
 58     }
 59 }
 60 
 61 
 62 void swap_variables(int *numbers_ptr, int user_input2){
 63     int i,swap;
 64     int loc1,loc2; //Store indexes that need swapping
 65                     // loc1 is 0 and loc2 is the user input.
 66 
 67     for(i = 0; i < 16; i++){
 68         if(numbers_ptr[i] == 0)
 69             loc1 = i;
 70         else if(numbers_ptr[i] == user_input2)
 71             loc2 = i;
 72     }
 73     // Make sure you can swap only with contigous numbers
 74     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
 75         swap = numbers_ptr[loc1];
 76         numbers_ptr[loc1] = numbers_ptr[loc2];
 77         numbers_ptr[loc2] = swap;
 78     } else
 79         printf("That move is not allowed\n");
 80 }
 81 
 82 
 83 int compare_arrays(int *numbers_ptr){
 84     int numbers_final[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
 85     int i;
 86     for(i = 0; i < 16; i++){
 87         if(numbers_final[i] != numbers_ptr[i])
 88             return(1);
 89     }
 90     return(EXIT_SUCCESS);
 91 }

edit: note

 
 50     for(i = 0; i < 16; i++){
 51         if(numbers_ptr[i] == 0)
 52             printf("%5c", NULL);

this replaces the number 0 with a null to make it easier on the eye of the player
I also added this line of code within the while(1) loop

 
37         else if(*user_input == 'q')
38             break;

so that when the  user enters the character q the program exits.

Last edited by ldvx (2010-02-27 03:13:08)

Offline

#11 2010-03-01 19:32:46

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: Easy game in C

Sorry for being delayed in my reply, other things have absorbed my time recently...

ldvx wrote:

Thank you very very much Trent! I hadn't realize the mess I had with consistency. 
Here I have a question (I commented poorly on that piece of code). numbers_ptr is a pointer that points to the array numbers[]. Therefore, numbers_ptr isn't technically an array, right? Nevertheless, I can treat it like one. *(numbers_ptr+i) is equivalent to numbers_ptr[ i]. I changed all my code to treat that pointer like an array (I think it is easier to read as the syntax is easier)... is this a recommended style or should I just use *(numbers_ptr+i) when dealing with pointers pointing to arrays?

Your understanding is correct.  numbers is an object of type "array of int".  However, most times when you use it, the name "numbers" doesn't represent the object itself, but the address of its first element.  In conventional C-talk, we say that it "decays" into a pointer to the first element.  This is the case when you pass an array into a function -- you don't copy the array itself, only the address of its first element.  (There are cases where "numbers" will not decay into the address of its first element, e.g. "sizeof numbers").

As to whether it is more stylistically correct to use *(ptr + i) vs. ptr[ i], well, that's a question of taste.  In your situation, numbers_ptr actually does point to the first element of an array, so most C programmers would use the latter form.  You might encounter code that uses pointer arithmetic to access elements of a struct (which is almost always a bad idea, by the way); e.g. if item_a is a pointer to the first element of a struct, you might be able to access the second element via *(item_a + 1).  In that case, although item_a[1] is syntactically identical, it would be better (in my opinion) to use explicit pointer arithmetic, because the array notation would imply to the reader that item_a was in fact an array.

If that last paragraph made only a little bit of sense, I apologize smile  You can probably safely ignore it.

So here is how the code ended up, again, thanks a lot. Oh, I had a bit of a hard time trying to use EXIT_SUCCESS but I think I understand why: it is a keyword and to use it I have to include the header <stdlib.h> and its value is 0.

Yes, I should have mentioned that.  In most programs you will eventually #include <stdlib.h> anyway, so it didn't cross my mind.  EXIT_SUCCESS is guaranteed to contain a value that the implementation will interpret as successful termination of the program.  return 0 is actually guaranteed to do the same thing, but is slightly less explicit.  There is a corresponding EXIT_FAILURE that is defined to be some value not equal to zero (arbitrarily, -1).  You should be careful if you use values other than 0, EXIT_SUCCESS and EXIT_FAILURE when returning from main() or calling exit(), because on some arbitrary system they may be interpreted by the invoking shell or program to mean something you didn't intend.

If you're getting the impression that C requires being very careful, you're right smile  It becomes second nature after a while, or so I'm told big_smile

edit: note

 
 50     for(i = 0; i < 16; i++){
 51         if(numbers_ptr[i] == 0)
 52             printf("%5c", NULL);

this replaces the number 0 with a null to make it easier on the eye of the player
I also added this line of code within the while(1) loop

Interesting.  I'm not sure what that looks like (can't test it now), but are you simply printing 5 blanks?  In that case you could simply printf("     ");

Edit: corrected BBCode oversight

Last edited by Trent (2010-03-01 19:34:47)

Offline

#12 2010-03-03 21:29:03

ldvx
Member
Registered: 2007-01-02
Posts: 33

Re: Easy game in C

Thank you very much Trent! I think I have gotten to the point were I am sattisfied with the program. It was a great learning exercise, and your help was extremely helpful, so again, thanks a lot. What print("%5c", NULL) did was to print 4 blank spaces (I think NULL character printed nothing, not even a space, that's why I needed to add 1 to get a total of 4 blank spaces).  The program had a bug due to a logic mistake, but I fix it. The bug was that whenever you got all the numbers in order then you would have to press any letter or character in order to get the game to tell you "Congratulations. You have completed the game" and exit. I wanted to print that and exit without the user needing to press a letter. I also added a random_shuffle function to get the numbers shuffled so that the numbers are not the same everytime the user runs the program. I realize this needs a more advance algorithm to make sure that the game is actually "solvable", but for this purposes I am happy enough with it. Thank you a lot for your help, I will continue with K&R2 exercises now and then look into data structures as you suggested.

Here is how the code ended up like

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <ctype.h>
  4 #include <time.h>
  5 void print_table(int *numbers_ptr);
  6 void random_shuffle(int *numbers_ptr);
  7 void swap_variables(int *numbers_ptr, int user_input2);
  8 int compare_arrays(int *numbers_ptr);
  9 
 10 int main(void)
 11 {
 12     //0 in numbers[] will represent an empty space
 13     int numbers[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
 14     int *numbers_ptr;
 15     int user_input2 = 0;    //user input after sanity check
 16     char user_input[10];    //user input originally
 17 
 18     numbers_ptr = numbers;
 19 
 20     srand(time(NULL));              //Seed: Timer to avoid repetitions@runtime
 21     random_shuffle(numbers_ptr);    //Shuffle numbers[]
 22     printf("Let's start a game!\n");
 23     print_table(numbers_ptr);
 24 
 25     while(1)
 26     {
 27         printf("Enter a number: ");
 28         fflush(stdout);
 29         fgets(user_input, sizeof user_input, stdin);
 30         sscanf(user_input, "%d", &user_input2);
 31 
 32 
 33         if(isdigit(*user_input)){
 34             swap_variables(numbers_ptr, user_input2);
 35             print_table(numbers_ptr);
 36 
 37             if(compare_arrays(numbers_ptr) == EXIT_SUCCESS){
 38                 printf("Congratulations. You have completed the game!\n");
 39                 break;
 40             }
 41 
 42         }
 43 
 44         else if(*user_input == 'q')
 45             break;
 46 
 47         else
 48             printf("You did not enter a number!\n");
 49     }
 50 
 51     return(EXIT_SUCCESS);
 52 }
 53 
 54 
 55 void print_table(int *numbers_ptr){
 56     int i;
 57     for(i = 0; i < 16; i++){
 58         if(numbers_ptr[i] == 0)
 59             printf("    ");
 60         else
 61             printf("%4d", numbers_ptr[i]);
 62         // i+1 fixes computations for formatting purposes
 63         if((i + 1) % 4 == 0)
 64             printf("\n");
 65     }
 66 }
 67 
 68 
 69 void swap_variables(int *numbers_ptr, int user_input2){
 70     int i,swap;
 71     int loc1,loc2; //Store indexes that need swapping
 72                     // loc1 is 0 and loc2 is the user input.
 73 
 74     for(i = 0; i < 16; i++){
 75         if(numbers_ptr[i] == 0)
 76             loc1 = i;
 77         else if(numbers_ptr[i] == user_input2)
 78             loc2 = i;
 79     }
 80     // Make sure you can swap only with contigous numbers
 81     if(loc2+1 == loc1 || loc2-1 == loc1 || loc2 + 4 == loc1 || loc2-4 == loc1){
 82         swap = numbers_ptr[loc1];
 83         numbers_ptr[loc1] = numbers_ptr[loc2];
 84         numbers_ptr[loc2] = swap;
 85     } else
 86         printf("That move is not allowed\n");
 87 }
 88 
 89 void random_shuffle(int *numbers_ptr){
 90     int i;
 91     int swaping_index,swap;
 92 
 93     for(i = 0; i < 16; i++){
 94         swaping_index = (rand() % 15) + 1; //Choose an index randomly
 95         swap = numbers_ptr[i];
 96         numbers_ptr[i] = numbers_ptr[swaping_index];
 97         numbers_ptr[swaping_index] = swap;
 98     }
 99 }
100 
101 int compare_arrays(int *numbers_ptr){
102     int numbers_final[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
103     int i;
104     for(i = 0; i < 16; i++){
105         if(numbers_final[i] != numbers_ptr[i])
106             return(1);
107     }
108     return(EXIT_SUCCESS);
109 }

Last edited by ldvx (2010-03-03 21:32:41)

Offline

#13 2010-03-04 13:26:37

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: Easy game in C

The code looks pretty good.

I really love C, and I'm always happy to help people who are learning how to use it properly.  So, you're welcome smile  Happy hacking!

Offline

Board footer

Powered by FluxBB