Many changes.
[funnysort.git] / funnysort.c
blob7696ef60c2b16966c4f4ef781448ba0e883479f3
1 /* funnysort.c */
3 /* remove the next line to enable asserts */
4 /*#define NDEBUG*/
6 #include <stdio.h>
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <pthread.h>
10 #include <unistd.h>
11 #include <stdbool.h>
12 #include <signal.h>
14 #include "congl.h"
16 #define WIDTH 50
17 #define HEIGHT 30
18 #define NCYCLES 300
19 #define SLEEP_TIME 0
20 #define SORTER_MOVE_TRIES 100
21 #define FREE_PER_ITEM 50
22 #define NSORTERS 20
24 typedef enum {A=0, EMPTY} item_t;
26 struct board_s {
27 unsigned int width;
28 unsigned int height;
29 bool size_valid;
30 item_t **surface;
31 pthread_mutex_t **lock;
32 bool surface_valid;
34 typedef struct board_s board_t;
36 struct sorter_s {
37 unsigned int column;
38 unsigned int line;
39 item_t item;
41 typedef struct sorter_s sorter_t;
43 struct sorter_argv_s {
44 board_t *board;
45 sorter_t *sorter;
47 typedef struct sorter_argv_s sorter_argv_t;
49 void count_item (board_t *, item_t *, unsigned int *);
50 void drop_item (unsigned int, unsigned int, board_t *, item_t *);
51 void erase_board (board_t *);
52 void fetch_item (unsigned int, unsigned int, item_t *);
53 void finish_board (board_t *);
54 void move_sorter (board_t *, sorter_t *);
55 void peek_item (unsigned int, unsigned int, board_t *, item_t *);
56 void pick_item (unsigned int, unsigned int, board_t *, item_t *);
57 void poke_item (unsigned int, unsigned int, board_t *, item_t);
58 void print_board (board_t *);
59 void print_item (unsigned int, unsigned int, item_t);
60 void print_mutexes (board_t *board);
61 void *run_sorter (void *);
62 void setup_board(board_t *);
65 /******************************************************************************/
67 * Output related functions.
71 * Erase the output medium.
73 void erase_board (board_t *board)
75 conglReset();
76 conglClearScreen();
77 conglMoveCursor(1, 1);
80 /* Print the base of the board, without any items. */
81 void print_board(board_t *board)
83 assert(board->size_valid);
84 assert(board->surface_valid);
86 conglClearScreen();
87 conglMoveCursor(1, 1);
91 * Print a graphical representation an item.
93 void print_item(unsigned int line, unsigned int column, item_t item)
95 struct properties_s {
96 conglColor_t bg;
97 conglColor_t fg;
98 char symbol;
100 typedef struct properties_s properties_t;
102 properties_t properties[] = {
103 {congl_magenta, congl_white, ' '},
104 {congl_green, congl_white, ' '},
105 {congl_black, congl_white, ' '}
106 //{'i'}, {'f'}, {'s'}
109 properties_t p;
111 p = properties[item];
112 conglDrawCharFull(line+1, column+1, p.symbol, p.fg, p.bg);
114 //printf("%c: %d,%d\n", p.symbol, column, line);
118 * Print a graphical representation of the state of all mutexes.
120 void print_mutexes(board_t *board)
122 int line, column;
124 for (line = 0; line < board->height; ++line) {
125 for (column = 0; column < board->width; ++column) {
126 print_item(line, column, board->surface[line][column]);
127 if (pthread_mutex_trylock((board->lock)[line]+column) == 0) {
128 printf("U");
129 } else {
130 printf("L");
137 /******************************************************************************/
139 * Sorter related functions.
143 * The sorter.
145 void *run_sorter (void *argv)
147 int itera;
148 sorter_t *sorter;
149 board_t *board;
152 * Arguments handling.
154 board = ((sorter_argv_t *)argv)->board;
155 sorter = ((sorter_argv_t *)argv)->sorter;
157 for (itera = 0; itera <= NCYCLES; ++itera) {
158 do {
159 move_sorter(board, sorter);
160 pick_item(sorter->line, sorter->column, board, &(sorter->item));
162 usleep(SLEEP_TIME);
163 } while (sorter->item == EMPTY);
165 while (sorter->item != EMPTY) {
166 drop_item(sorter->line, sorter->column, board, &(sorter->item));
167 move_sorter(board, sorter);
169 usleep(SLEEP_TIME);
172 /* leave the premisses */
174 for (r = 0; (r < 10); ++r) {
175 move(board, sorter);
180 return NULL;
184 * Move the sorter.
186 void move_sorter(board_t *board, sorter_t *sorter)
188 assert(sorter != NULL);
189 assert(sorter->column < board->width);
190 assert(sorter->line < board->height);
192 unsigned int newline, newcolumn;
193 int h, hoffset, hrange;
194 int v, voffset, vrange;
197 * Set default values to range and offset of random movement.
199 hoffset = -1;
200 hrange = 3;
201 voffset = -1;
202 vrange = 3;
205 * Adjust according to sorter position.
207 if (sorter->line == 0) {
208 voffset = 0;
209 vrange--;
211 if (sorter->line == (board->height-1)) {
212 vrange--;
214 if (sorter->column == 0) {
215 hoffset = 0;
216 hrange--;
218 if (sorter->column == (board->width-1)) {
219 hrange--;
222 * Calculate the displacements.
224 h = rand()%hrange + hoffset;
225 v = rand()%vrange + voffset;
227 newline = sorter->line + v;
228 newcolumn = sorter->column + h;
230 sorter->line = newline;
231 sorter->column = newcolumn;
233 assert(sorter->line < board->height);
234 assert(sorter->column < board->width);
238 /******************************************************************************/
240 * Item handling functions.
244 * Try to pick an item.
246 void pick_item (unsigned int line, unsigned int column, board_t *board, item_t *item)
248 assert (board != NULL);
249 assert (board->size_valid);
250 assert (board->surface_valid);
251 assert (line < board->height);
252 assert (column < board->width);
253 assert (item != NULL);
254 assert (*item == EMPTY);
256 int newline, newcolumn;
257 item_t newitem;
259 * h is for horizontal, v is for vertical.
261 int h, hmin, hmax;
262 int v, vmin, vmax;
265 * Set default values for parameters
267 hmin = -1;
268 hmax = 1;
269 vmin = -1;
270 vmax = 1;
273 * Adjust parameters according to position.
275 if (line == 0) vmin = 0;
276 if (line == (board->height-1)) vmax = 0;
277 if (column == 0) hmin = 0;
278 if (column == (board->width-1)) hmax = 0;
280 for (h = hmin; (h <= hmax) && (*item == EMPTY); ++h) {
281 for (v = vmin; (v <= vmax) && (*item == EMPTY); ++v) {
283 * newline and newcolumn need to be allawys positive.
285 newline = line + v;
286 newcolumn = column + h;
288 pthread_mutex_lock((board->lock)[newline]+newcolumn);
289 peek_item(newline, newcolumn, board, &newitem);
290 if (newitem != EMPTY) {
291 *item = newitem;
292 poke_item(newline, newcolumn, board, EMPTY);
294 * We now have the item.
297 pthread_mutex_unlock((board->lock)[newline]+newcolumn);
301 /* we either pick an item or leave it as it is */
302 assert ((*item == newitem) || (*item == EMPTY));
305 /* Try to drop one item. The item needs to be droped in a position adjacent to
306 * a similar item.
308 void drop_item (unsigned int line, unsigned int column, board_t *board, item_t *item)
310 assert (board != NULL);
311 assert (board->size_valid);
312 assert (board->surface_valid);
313 assert (line < board->height);
314 assert (column < board->width);
315 assert (item != NULL);
316 assert (*item != EMPTY);
318 int newline, newcolumn;
320 * h is for horizontal, v is for vertical.
322 int h, hmin, hmax;
323 int v, vmin, vmax;
324 item_t newitem;
327 * Set default values for parameters.
329 hmin = -1;
330 hmax = 1;
331 vmin = -1;
332 vmax = 1;
335 * Adjust parameters according to position.
337 if (line == 0) vmin = 0;
338 if (line == (board->height-1)) vmax = 0;
339 if (column == 0) hmin = 0;
340 if (column == (board->width-1)) hmax = 0;
342 pthread_mutex_lock((board->lock)[line]+column);
345 * Only try to drop if current position is empty.
347 peek_item(line, column, board, &newitem);
348 if (newitem == EMPTY) {
349 for (h = hmin; (h <= hmax) && (*item != EMPTY); ++h) {
350 for (v = vmin; (v <= vmax) && (*item != EMPTY); ++v) {
351 /* newline and newcolumn need to be allawys positive */
352 newline = line + v;
353 newcolumn = column + h;
355 peek_item(newline, newcolumn, board, &newitem);
356 if(newitem == *item) {
357 poke_item(line, column, board, *item);
358 *item = EMPTY;
359 /* and the item is down */
365 pthread_mutex_unlock((board->lock)[line]+column);
368 /* Read an item from the board. */
369 void peek_item (unsigned int line, unsigned int column, board_t *board, item_t *item)
371 assert(board != NULL);
372 assert(board->size_valid);
373 assert(board->surface_valid);
374 assert(line < board->height);
375 assert(column < board->width);
376 assert(item != NULL);
378 *item = board->surface[line][column];
381 assert(*item == board->surface[line][column]);
385 /* Write an item in position (column,line) of the board. At the same time update
386 * any output medium.
388 void poke_item (unsigned int line, unsigned int column, board_t *board, item_t item)
390 assert(board != NULL);
391 assert(board->size_valid);
392 assert(board->surface_valid);
393 assert(line < board->height);
394 assert(column < board->width);
396 board->surface[line][column] = item;
398 print_item (line, column, item);
400 assert(board->surface[line][column] == item);
403 /* Fetch an item from somewhere. The purpose of this functin is to allow the
404 * user to load one pattern every time the program runs. For now all items are
405 * random (sort of).
407 void fetch_item(unsigned int line, unsigned int column, item_t *item)
409 assert(item != NULL);
411 int number;
413 /* generate one block in every FREE_PER_ITEM board cells */
414 number = rand()%FREE_PER_ITEM;
415 switch (number) {
416 case 0:
417 *item = A;
418 break;
419 default:
420 *item = EMPTY;
421 break;
426 * Count all items of a specific type.
428 void count_items(board_t *board, item_t *item, unsigned int *nitems)
430 assert (board != NULL);
431 assert (item != NULL);
432 assert (nitems != NULL);
434 unsigned int line, column;
435 item_t this_item;
436 unsigned int count;
438 count = 0;
439 for (line = 0; line < board->height; ++line) {
440 for (column = 0; column < board->width; ++column) {
441 peek_item(line, column, board, &this_item);
442 if (this_item == *item) count++;
446 *nitems = count;
450 /******************************************************************************/
452 * Board related functions.
455 void setup_board(board_t *board)
457 assert (board->size_valid);
458 assert (!board->surface_valid);
460 unsigned int column, line;
461 item_t item;
463 //printf("Preparing board.\n");
465 /* allocate space for the board */
466 board->surface = (item_t **)calloc (board->height, sizeof(board->surface));
467 board->lock = (pthread_mutex_t **)calloc (board->height, sizeof(board->lock));
468 if (board->surface == NULL) {
469 perror("board_setup");
470 return;
472 if (board->lock == NULL) {
473 perror("board_setup");
474 return;
476 for (line = 0; line < board->height; ++line) {
477 board->surface[line] = (item_t *)calloc (board->width, sizeof(item_t));
478 board->lock[line] = (pthread_mutex_t *)calloc (board->width, sizeof(pthread_mutex_t));
479 if (board->surface[line] == NULL) {
480 perror("board_setup");
481 return;
483 if (board->lock[line] == NULL) {
484 perror("board_setup");
485 return;
488 board->surface_valid = true;
490 //printf("Printing board.\n");
491 print_board(board);
492 //printf("Board printed.\n");
494 /* fill the board with initial values */
495 for (line = 0; line < board->height; ++line) {
496 for (column = 0; column < board->width; ++column) {
497 fetch_item(line, column, &item);
498 poke_item(line, column, board, item);
499 pthread_mutex_init((board->lock)[line]+column, NULL);
503 assert (board->surface_valid);
506 void finish_board (board_t *board)
508 assert (board->surface_valid);
510 int line;
512 for (line = 0; line < board->height; ++line) {
513 free (board->surface[line]);
514 free (board->lock[line]);
516 free (board->surface);
517 free (board->lock);
518 board->surface_valid = false;
520 erase_board(board);
522 assert (!board->surface_valid);
526 /******************************************************************************/
527 int main (int argc, char *argv[])
529 board_t board;
530 unsigned int nitems_begin, nitems_finish;
531 pthread_attr_t thread_attributes;
532 pthread_t sorter_threads[NSORTERS];
533 sorter_t sorters[NSORTERS];
534 item_t item;
535 unsigned int n;
536 unsigned int line, column;
537 sorter_argv_t sorters_argv[NSORTERS];
539 board.width = WIDTH;
540 board.height = HEIGHT;
541 board.size_valid = true;
542 board.surface_valid = false;
545 * Intialize random number generator
547 srand((unsigned int)time(NULL));
549 setup_board (&board);
551 item = A;
552 count_items(&board, &item, &nitems_begin);
555 * Launch sorters.
557 pthread_attr_init(&thread_attributes);
558 for (n = 0; n < NSORTERS; ++n) {
560 * Initialize sorter parameters.
562 sorters[n].line = rand() % board.height;
563 sorters[n].column = rand() % board.width;
564 sorters[n].item = EMPTY;
566 sorters_argv[n].board = &board;
567 sorters_argv[n].sorter = sorters+n;
569 pthread_create(sorter_threads+n, &thread_attributes, run_sorter, (void *)(sorters_argv+n));
573 * Wait for keypress (return).
575 getchar();
578 * Lock the board so sorters finish any pending operation
580 for (line = 0; line < board.height; ++line) {
581 for (column = 0; column < board.width; ++column) {
582 pthread_mutex_lock((board.lock)[line]+column);
587 * Kill all sorters.
589 for (n = 0; n < NSORTERS; ++n) {
590 pthread_cancel(sorter_threads[n]);
593 //print_mutexes(&board);
596 * Make sure the sorters didn't ate items.
598 count_items(&board, &item, &nitems_finish);
599 assert(nitems_begin == nitems_finish);
601 finish_board (&board);
603 printf("All good.\n");
605 exit(0);