You are not logged in.
Pages: 1
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
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
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
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
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
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
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
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
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
Thank you very very much Trent! I hadn't realize the mess I had with consistency.
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
Sorry for being delayed in my reply, other things have absorbed my time recently...
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 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 It becomes second nature after a while, or so I'm told
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
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
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 Happy hacking!
Offline
Pages: 1