summaryrefslogtreecommitdiff
path: root/test/c/chomp.c
blob: 7c8e61104fd39dfd1b2276354be23ffbd81b75d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#include <stdio.h>
#include <stdlib.h>

#define NDATA (int *)malloc(ncol * sizeof(int))
#define NLIST (struct _list *)malloc(sizeof(struct _list))
#define NPLAY (struct _play *)malloc(sizeof(struct _play))

struct _list
{
  int *data;
  struct _list *next;
} *wanted;

struct _play
{
  int value;
  int *state;
  struct _list *first;
  struct _play *next;
} *game_tree;

int nrow,ncol;      /* global so as to avoid passing them all over the place */

int *copy_data(int* data) /* creates a duplicate of a given -data list */
{
  int *new = NDATA;
  int counter = ncol;
  while (counter --)
      new[counter] = data[counter];
  return new;
}

int next_data(int *data)  /* gives the next logical setup to the one passed */
                          /* new setup replaces the old. Returns 0 if no valid */
{                         /* setup exists after the one passed */
  int counter = 0;
  int valid = 0;     /* default to none */
  while ((counter != ncol) && (! valid)) /* until its done */
    {
      if (data[counter] == nrow) /* if we hit a border */
        {
	  data[counter] = 0;     /* reset it to zero     */
	  counter ++;      /* and take next column */
	}
       else
        {
	  data[counter] ++;      /* otherwise, just increment row number */
	  valid = 1;                /* and set valid to true. */
	}
    }
  return valid;                     /* return whether or not */
}                                   /* a next could be found */

void melt_data(int *data1,int *data2) /* melts 2 _data's into the first one. */
{
  int counter = ncol;
  while (counter --)     /* do every column */
    {
      if (data1[counter] > data2[counter]) /* take the lowest one */
          data1[counter] = data2[counter]; /* and put in first _data */
    }
}

int equal_data(int *data1,int *data2) /* check if both _data's are equal */
{
  int counter = ncol;
  while ((counter --) && (data1[counter] == data2[counter]));
  return (counter < 0);
}

int valid_data(int *data) /* checks if the play could ever be achieved. */
{
  int low;      /* var to hold the current height */
  int counter = 0;
  low = nrow;   /* default to top of board */
  while (counter != ncol) /* for every column */
    {
      if (data[counter] > low) break;  /* if you get something higher */
      low = data[counter];             /* set this as current height */
      counter ++;
    }
  return (counter == ncol);
}

void dump_list(struct _list *list) /* same for a _list structure */
{
  if (list != NULL)
    {
      dump_list(list -> next); /* dump the rest of it */
      free(list -> data); /* and its _data structure */
      free(list);
    }
}

void dump_play(struct _play *play) /* and for the entire game tree */
{
  if (play != NULL)
    {
      dump_play(play -> next);  /* dump the rest of the _play */
      dump_list(play -> first); /* its _list */
      free(play -> state); /* and its _data */
      free(play);
    }
}

int get_value(int *data) /* get the value (0 or 1) for a specific _data */
{
  struct _play *search;
  search = game_tree; /* start at the begginig */
  while (! equal_data(search -> state,data)) /* until you find a match */
      search = search -> next; /* take next element */
  return search -> value; /* return its value */
}

void show_data(int *data) /* little display routine to give off results */
{
  int counter = 0;
  while (counter != ncol)
    {
      printf("%d",data[counter ++]);
      if (counter != ncol) putchar(',');
    }
}

void show_move(int *data) /* puts in the "(" and ")" for show_data() */
{
  putchar('(');
  show_data(data);
  printf(")\n");
}

void show_list(struct _list *list) /* show the entire list of moves */
{
  while (list != NULL)
    {
      show_move(list -> data);
      list = list -> next;
    }
}

void show_play(struct _play *play) /* to diplay the whole tree */
{
  while (play != NULL)
    {
      printf("For state :\n");
      show_data(play -> state);
      printf("  value = %d\n",play -> value);
      printf("We get, in order :\n");
      show_list(play -> first);
      play = play -> next;
    }
}

int in_wanted(int *data) /* checks if the current _data is in the wanted list */
{
  struct _list *current;
  current = wanted; /* start at the begginig */
  while (current != NULL) /* unitl the last one */
    {
      if (equal_data(current -> data,data)) break; /* break if found */
      current = current -> next; /* take next element */
    }
  if (current == NULL) return 0; /* if at the end, not found */
  return 1;
}

int *make_data(int row,int col) /* creates a new _data with the correct */
                                /* contents for the specified row & col */
{
  int count;
  int *new = NDATA;
  for (count = 0;count != col;count ++) /* creates col-1 cells with nrow */
      new[count] = nrow;
  for (;count != ncol;count ++) /* and the rest with row as value */
      new[count] = row;
  return new;         /* and return pointer to first element */
}

struct _list *make_list(int *data,int *value,int *all) /* create the whole _list of moves */
                                                          /* for the _data structure data */
{
  int row,col;
  int *temp;
  struct _list *head,*current;
  *value = 1; /* set to not good to give */
  head = NLIST; /* create dummy header */
  head -> next = NULL; /* set NULL as next element */
  current = head;      /* start from here */
  for (row = 0;row != nrow;row ++) /* for every row */
    {
      for (col = 0;col != ncol;col ++) /* for every column */
        {
	  temp = make_data(row,col); /* create _data for this play */
	  melt_data(temp,data);      /* melt it with the current one */
	  if (! equal_data(temp,data)) /* if they are different, it good */
	    {
	      current -> next = NLIST; /* create new element in list */
	      current -> next -> data = copy_data(temp); /* copy data, and place in list */
	      current -> next -> next = NULL; /* NULL the next element */
	      current = current -> next; /* advance pointer */
	      if (*value == 1) /* if still not found a good one */
	          *value = get_value(temp); /* look at this value */
	      if ((! *all) && (*value == 0))
	        {  /* if we found it, and all is not set */
		  col = ncol - 1; /* do what it take sto break out now */
		  row = nrow - 1;
	          if (in_wanted(temp)) /* if in the wanted list */
		      *all = 2; /* flag it */
		}
	    }
	   else /* if its not a valid move */
	    {
	      if (col == 0) row = nrow - 1; /* break out if at first column */
	      col = ncol - 1;               /* but make sure you break out */
	    }                               /* of the col for-loop anyway */
	  free(temp); /* dump this unneeded space */
	}
    }
  current = head -> next; /* skip first element */
  free(head); /* dump it */
  if (current != NULL) *value = 1 - *value; /* invert value if its */
  return current;                           /* not the empty board */
}

struct _play *make_play(int all) /* make up the entire tree-like stuff */
{
  int val;
  int *temp;
  struct _play *head,*current;
  head = NPLAY; /* dummy header again */
  current = head; /* start here */
  game_tree = NULL; /* no elements yet */
  temp = make_data(0,0); /* new data, for empty board */
  temp[0] --;   /* set it up at (-1,xx) so that next_data() returns (0,xx) */
  while (next_data(temp)) /* take next one, and break if none */
    {
      if (valid_data(temp)) /* if board position is possible */
        {
	  current -> next = NPLAY; /* create a new _play cell */
	  if (game_tree == NULL) game_tree = current -> next;
	      /* set up game_tree if it was previously NULL */
	  current -> next -> state = copy_data(temp); /* make a copy of temp */
	  current -> next -> first = make_list(temp,&val,&all);
	      /* make up its whole list of possible moves */
	  current -> next -> value = val; /* place its value */
	  current -> next -> next = NULL; /* no next element */
	  current = current -> next;      /* advance pointer */
	  if (all == 2)                   /* if found flag is on */
	    {
	      free(temp);            /* dump current temp */
	      temp = make_data(nrow,ncol); /* and create one that will break */
	    }
	}
    }
  current = head -> next; /* skip first element */
  free(head);             /* dump it */
  return current;         /* and return pointer to start of list */
}

void make_wanted(int *data) /* makes up the list of positions from the full board */
{
         /* everything here is almost like in the previous function. */
	 /* The reason its here, is that it does not do as much as   */
	 /* the one before, and thus goes faster. Also, it saves the */
	 /* results directly in wanted, which is a global variable.  */

  int row,col;
  int *temp;
  struct _list *head,*current;
  head = NLIST;
  head -> next = NULL;
  current = head;
  for (row = 0;row != nrow;row ++)
    {
      for (col = 0;col != ncol;col ++)
        {
	  temp = make_data(row,col);
	  melt_data(temp,data);
	  if (! equal_data(temp,data))
	    {
	      current -> next = NLIST;
	      current -> next -> data = copy_data(temp);
	      current -> next -> next = NULL;
	      current = current -> next;
	    }
	   else
	    {
	      if (col == 0) row = nrow - 1;
	      col = ncol - 1;
	    }
	  free(temp);
	}
    }
  current = head -> next;
  free(head);
  wanted = current;
}

int *get_good_move(struct _list *list) /* gets the first good move from a _list */
{
  if (list == NULL) return NULL; /* if list is NULL, say so */
      /* until end-of-list or a good one is found */
      /* a good move is one that gives off a zero value */
  while ((list -> next != NULL) && (get_value(list -> data)))
      list = list -> next;
  return copy_data(list -> data); /* return the value */
}

int *get_winning_move(struct _play *play) /* just scans for the first good move */
                                          /* in the last _list of a _play. This */
{                                         /* is the full board */
  int *temp;
  while (play -> next != NULL) play = play -> next; /* go to end of _play */
  temp = get_good_move(play -> first); /* get good move */
  return temp;                         /* return it */
}

struct _list *where(int *data,struct _play *play)
{
  while (! equal_data(play -> state,data)) /* search for given _data */
      play = play -> next;
  return play -> first;  /* return the pointer */
}

void get_real_move(int *data1,int *data2,int *row,int *col) /* returns row & col of the move */
                                                           /* which created data1 from data2 */
{
  *col = 0;
  while (data1[*col] == data2[*col]) /* until there is a change */
      (*col) ++;             /* and increment col number */
  *row = data1[*col];  /* row is given by the content of the structure */
}

int main(void)
{
  int row,col,player;
  int *current,*temp;
  struct _play *tree;


  ncol = 7;
#ifdef SMALL_PROBLEM_SIZE
  nrow = 7;
#else
  nrow = 8;
#endif
  tree = make_play(1); /* create entire tree structure, not just the */
  player = 0;          /* needed part for first move */
  current = make_data(nrow,ncol); /* start play at full board */
  while (current != NULL)
    {
      temp = get_good_move(where(current,tree)); /* get best move */
      if (temp != NULL)  /* temp = NULL when the poison pill is taken */
        {
          get_real_move(temp,current,&row,&col); /* calculate coordinates */
          /* print it out nicely */
          printf("player %d plays at (%d,%d)\n",player,row,col);
          player = 1 - player; /* next player to do the same */
          free(current);  /* dump for memory management */
        }
      current = temp; /* update board */
    }
  dump_play(tree); /* dump unneeded tree */
  printf("player %d loses\n",1 - player); /* display winning player */
  return 0;
}

/*****************************************************************************/