~e93b5ae3/+junk/github-import-readonly

36 by fossilet
Changed logo; remove other game modes. Start over.
1
/*
2
   4digits - A guess-the-number game, aka Bulls and Cows
40 by fossilet
1.0 release.
3
   Copyright (c) 2004-2011 Pan Yongzhi <http://fourdigits.sourceforge.net>
36 by fossilet
Changed logo; remove other game modes. Start over.
4
5
   4digits is a guess-the-number puzzle game. It's called Bulls and Cows,
6
   and in China people simply call it Guess-the-Number. The game's
7
   objective is to guess a four-digit number in 8 times using as less time
8
   as possible. It is similar to Mastermind, but the four digits are
9
   different to each other. 4digits has a graphical user interface version
10
   4digits and a textual user interface version 4digits-text. 
11
12
   4digits is free software; you can redistribute it and/or
13
   modify it under the terms of the GNU General Public License as
14
   published by the Free Software Foundation; either version 2 of
15
   the License, or (at your option) any later version.
16
17
   4digits is distributed in the hope that it will be useful,
18
   but WITHOUT ANY WARRANTY; without even the implied warranty of
19
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
   GNU General Public License for more details.
21
22
   You should have received a copy of the GNU General Public License
23
   along with 4digits; if not, write to the Free Software Foundation,
24
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
25
   */
1 by fossilet
Initial import
26
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <time.h>
30
#include <ctype.h>
31
#include <string.h>
32
#include <stdbool.h>
33
#include <getopt.h>
34
#include <unistd.h>
35
36 by fossilet
Changed logo; remove other game modes. Start over.
36
//#define DEBUG
40 by fossilet
1.0 release.
37
#define VERSION_STRING "1.0, Jul 2011"
1 by fossilet
Initial import
38
39
const char COPYRIGHT[] = "4digits " VERSION_STRING "\n"
36 by fossilet
Changed logo; remove other game modes. Start over.
40
"4digits comes with NO WARRANTY to the extent permitted by law.\n"
41
"This program is free software; you can redistribute it and/or\n"
42
"modify it under the terms of the GNU General Public License as\n"
43
"published by the Free Software Foundation - version 2. For more\n"
44
"information about these matters, see the file named COPYING.\n";
45
const char AUTHOR[] = "Written by Pan Yongzhi.\n";
46
47
const char HELP[] = 
48
"4digits, a guess-the-number game.\n"
49
"Usage: 4digits [OPTION] ...\n"
50
"\n"
51
"You are given eight times to guess a four-digit number. You get\n"
52
"one A if its value and position are both correct, and you get one\n"
53
"B if only its value is correct. You win the game when you get 4A0B.\n"
54
"\n"
55
"-v, --version \t display the version of 4digits and exit.\n"
56
"-h, -?, --help \t print this help.\n"      
57
"\n"
58
"Report bugs at <http://sourceforge.net/projects/fourdigits/>.";
59
60
static const char *optString = "vh?";
1 by fossilet
Initial import
61
struct globalArgs_t {
36 by fossilet
Changed logo; remove other game modes. Start over.
62
    char *version; // version option
1 by fossilet
Initial import
63
} globalArgs;
64
65
static const struct option longOpts[] = {
36 by fossilet
Changed logo; remove other game modes. Start over.
66
    { "version", no_argument, NULL, 'v' },
67
    { "help", no_argument, NULL, 'h' },
68
    { NULL, no_argument, NULL, 0 }
1 by fossilet
Initial import
69
};
70
71
void print_help(void);
72
void display_usage(void);
36 by fossilet
Changed logo; remove other game modes. Start over.
73
void gen_rand(int ans_digits[]);
74
int enter_number(void);
75
void save_score(const int time_taken);
76
void compare(const int *in_digits, const int *ans_digits, int *A, int *B);
77
int tenpow(int power);
78
1 by fossilet
Initial import
79
void print_help(void) {
36 by fossilet
Changed logo; remove other game modes. Start over.
80
    (void)puts(HELP);
81
    exit(EXIT_FAILURE);
1 by fossilet
Initial import
82
}
83
84
void display_usage(void) {
36 by fossilet
Changed logo; remove other game modes. Start over.
85
    (void)puts("Usage: 4digits [OPTION]...\n");
86
    (void)puts("Try `4digits --help' for more information.");
87
    exit(EXIT_FAILURE);
88
}
89
1 by fossilet
Initial import
90
/* generate a random number */
26 by Fossilet
Version 0.9 release.
91
void gen_rand(int ans_digits[]) {
36 by fossilet
Changed logo; remove other game modes. Start over.
92
    srand((unsigned)time(NULL));
93
    int ans = 1000 + (int)(8999.0*rand()/RAND_MAX);
94
    for(int i=0; i<4; i++)
95
        ans_digits[i] = (int)(ans/tenpow(3-i)) % 10;
1 by fossilet
Initial import
96
36 by fossilet
Changed logo; remove other game modes. Start over.
97
    /* if 4 digits is not different from each other, regenerate it*/
98
    while(ans_digits[0]==ans_digits[1] || ans_digits[1]==ans_digits[2]
99
            || ans_digits[2]==ans_digits[3] || ans_digits[0]==ans_digits[2]
100
            || ans_digits[0]==ans_digits[3] || ans_digits[1]==ans_digits[3])
26 by Fossilet
Version 0.9 release.
101
    {
36 by fossilet
Changed logo; remove other game modes. Start over.
102
        ans = 1000 + (int)(8999.0 * ((double)rand()/RAND_MAX)); 
103
        for(int i=0; i<4; i++)
104
            ans_digits[i] = (int)(ans / tenpow(3-i))%10;
1 by fossilet
Initial import
105
    }
106
#ifdef DEBUG
36 by fossilet
Changed logo; remove other game modes. Start over.
107
    printf("%d\n", ans);
1 by fossilet
Initial import
108
#endif
109
}
110
111
/* enter a 4-digit number */
36 by fossilet
Changed logo; remove other game modes. Start over.
112
int enter_number() {
113
    char mstr[5]={'\0','\0','\0','\0','\0'}; 
114
    int c;
115
    int input;
116
    int in_digits[4]={0,0,0,0}; /* arrays for the 4 digits of input*/
117
    bool reinput;
118
    do {
119
        reinput = false;
120
        printf("Input a 4-digit number:");
121
        if(fgets(mstr, sizeof mstr, stdin) == NULL) {
122
            fprintf(stderr, "Something's got wrong, I'd better quit...\n");
123
            exit(EXIT_FAILURE); 
124
        }
125
        // fgets appends the newline entered, if it appears in the first 4
126
        // elements of mstr, then it's sure less than 4 digits are entered
127
        bool flag = false;
128
        if(mstr[0]!='\n'&& mstr[1]!='\n'&& mstr[2]!='\n' &&mstr[3]!='\n') 
129
            /* discard the character */
130
            while((c = getchar()) != '\n' && c != EOF)
131
                flag = true;
132
        if (flag == true) {
133
            fprintf(stderr, "Input too long!\n");
134
            reinput = true;
135
            continue;
136
        }
137
        input = atoi(mstr);
138
        if (input < 1000 || input > 9999) {
139
            fprintf(stderr, "Must be a number between 1000 and 9999!\n");
140
            reinput = true;
141
            continue;
142
        }
143
        for(int i=0; i<4; i++)
144
            in_digits[i]=(int) (input / tenpow(3-i) )%10;
145
        if(in_digits[0]==in_digits[1] || in_digits[1]==in_digits[2] 
146
                || in_digits[2]==in_digits[3] || in_digits[0]==in_digits[2]
147
                || in_digits[0]==in_digits[3] || in_digits[1]==in_digits[3])
148
        {
149
            fprintf(stderr, "Four digits must be unique.\n");
150
            reinput = true;
151
            continue;
152
        }
153
    }while(reinput);
154
    return input;
1 by fossilet
Initial import
155
}
156
157
/* compare answer and input, refresh A & B */
36 by fossilet
Changed logo; remove other game modes. Start over.
158
void compare(const int *in_digits, const int *ans_digits, int *a, int *b) {
159
    for(register int i=0 ; i<4; i++)
160
        for(register int j=0 ; j<4; j++)
161
            if(in_digits[i] == ans_digits[j])
162
                (i == j) ? (*a)++ : (*b)++;
1 by fossilet
Initial import
163
}
164
165
/* save current score in the score file */
36 by fossilet
Changed logo; remove other game modes. Start over.
166
void save_score(const int time_taken) {
167
    time_t tm = time(NULL);
168
    struct tm *today = localtime(&tm);
169
    char tmpbuffer[129];
170
    today = localtime(&tm);
171
    const char *sfpath = getenv("HOME");
172
    const char score_filename[] = "/.4digits/4digits-text.4digits.scores";
173
    char *scorefile = (char *)malloc(
174
            strlen(sfpath) + strlen(score_filename) + 1);
175
    if(!scorefile) {
176
        fprintf(stderr, "Memory allocation error.\n");
177
        exit(EXIT_FAILURE);
178
    }
179
    strcpy(scorefile, sfpath);
180
    strcat(scorefile, score_filename);
181
    FILE *sfp = fopen(scorefile, "a+");
182
    if (!sfp) {
183
        fprintf(stderr, "Cannot open score file.\n");
184
        exit(EXIT_FAILURE);
185
    }
186
    strftime(tmpbuffer, 128, "%a %b %d %H:%M:%S %Y", today); 
187
    fprintf(sfp, "%s %ds %s\n", getlogin(), time_taken, tmpbuffer);
188
    free(scorefile);
189
}
190
191
int tenpow(int exponent) {
192
    int output = 1;
193
    for(int i=0; i < exponent; i++)
194
        output *= 10;
195
    return output;
1 by fossilet
Initial import
196
}
197
198
int main(int argc, char *argv[]) {
36 by fossilet
Changed logo; remove other game modes. Start over.
199
    int opt = 0;
200
    int longIndex = 0;
201
202
    /* Initialize globalArgs before we get to work. */
203
    globalArgs.version = NULL;    /* false */
204
205
    // Process the arguments with getopt_long(), then populate globalArgs
1 by fossilet
Initial import
206
    opt = getopt_long(argc, argv, optString, longOpts, &longIndex);
36 by fossilet
Changed logo; remove other game modes. Start over.
207
    while(opt != -1) {
208
        switch(opt) {
209
            case 'v':
210
                globalArgs.version = VERSION_STRING;
211
                printf("%s\n%s", COPYRIGHT, AUTHOR);
212
                exit(1);
213
            case 'h': 
214
                print_help();
215
                break;
216
            case '?': /* fall-through is intentional */
217
                display_usage();
218
                break; 
219
            case 0:    /* long option without a short arg */
220
                if(strcmp("version", longOpts[longIndex].name) == 0)
221
                    break; 
222
            default:
223
                /* You won't actually get here. */
224
                break;
225
        }
226
        opt = getopt_long(argc, argv, optString, longOpts, &longIndex);
227
    }
228
229
    int ans_digits[4];
230
    gen_rand(ans_digits); /* array for the 4 digits of n*/
231
    time_t temp = time(NULL);
232
    time_t tic = temp;
233
    int guessed[8] = {0, 0, 0, 0, 0, 0, 0, 0};
234
    int i;
235
    bool dup = false;
236
237
    for (int num_guess = 0; num_guess < 8; num_guess++) {
238
        int A = 0, B = 0;
239
        int input = enter_number();
240
241
        for(int i=0; i < num_guess; i++)
242
            // duplicated input
243
            if (input == guessed[i]) {
244
                fprintf(stderr, "You've already guessed it.\n");
245
                --num_guess;
246
                dup = true;
247
                break;
248
            }
249
250
        if (dup == true) {
251
            dup = false;
252
            continue;
253
        }
254
255
        int in_digits[4]; /* arrays for the 4 digits of input*/
256
        for(i=0; i<4; i++) {
257
            in_digits[i]=(int) (input / tenpow(3-i) )%10;
258
        }
259
260
        compare(in_digits, ans_digits, &A, &B);
261
        printf("%dA%dB    ", A, B);
262
        if (num_guess != 7)
263
            printf("\t %d times left.\n", 7-num_guess);
264
        guessed[num_guess] = input;
265
266
        if(A == 4) {
267
            time_t toc = time(NULL);
268
            int score = (int)(toc-tic);
269
            printf("You win! :) Used %d sec.\n", score);
270
            save_score(score); /* save score in the score file */
271
            return 0;
272
        }
273
    }
274
    printf("\nHaha, you lose. It is ");
275
    for(int i = 0; i < 4; i++)
276
        printf("%d", ans_digits[i]);
277
    printf(".\n");
278
    return 0;
1 by fossilet
Initial import
279
}