3 /* remove the next line to enable asserts */
20 #define SORTER_MOVE_TRIES 100
21 #define FREE_PER_ITEM 50
24 typedef enum {A
=0, EMPTY
} item_t
;
31 pthread_mutex_t
**lock
;
34 typedef struct board_s board_t
;
41 typedef struct sorter_s sorter_t
;
43 struct sorter_argv_s
{
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
)
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
);
87 conglMoveCursor(1, 1);
91 * Print a graphical representation an item.
93 void print_item(unsigned int line
, unsigned int column
, item_t item
)
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'}
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
)
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) {
137 /******************************************************************************/
139 * Sorter related functions.
145 void *run_sorter (void *argv
)
152 * Arguments handling.
154 board
= ((sorter_argv_t
*)argv
)->board
;
155 sorter
= ((sorter_argv_t
*)argv
)->sorter
;
157 for (itera
= 0; itera
<= NCYCLES
; ++itera
) {
159 move_sorter(board
, sorter
);
160 pick_item(sorter
->line
, sorter
->column
, board
, &(sorter
->item
));
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
);
172 /* leave the premisses */
174 for (r = 0; (r < 10); ++r) {
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.
205 * Adjust according to sorter position.
207 if (sorter
->line
== 0) {
211 if (sorter
->line
== (board
->height
-1)) {
214 if (sorter
->column
== 0) {
218 if (sorter
->column
== (board
->width
-1)) {
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
;
259 * h is for horizontal, v is for vertical.
265 * Set default values for parameters
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.
286 newcolumn
= column
+ h
;
288 pthread_mutex_lock((board
->lock
)[newline
]+newcolumn
);
289 peek_item(newline
, newcolumn
, board
, &newitem
);
290 if (newitem
!= EMPTY
) {
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
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.
327 * Set default values for parameters.
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 */
353 newcolumn
= column
+ h
;
355 peek_item(newline
, newcolumn
, board
, &newitem
);
356 if(newitem
== *item
) {
357 poke_item(line
, column
, board
, *item
);
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
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
407 void fetch_item(unsigned int line
, unsigned int column
, item_t
*item
)
409 assert(item
!= NULL
);
413 /* generate one block in every FREE_PER_ITEM board cells */
414 number
= rand()%FREE_PER_ITEM
;
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
;
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
++;
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
;
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");
472 if (board
->lock
== NULL
) {
473 perror("board_setup");
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");
483 if (board
->lock
[line
] == NULL
) {
484 perror("board_setup");
488 board
->surface_valid
= true;
490 //printf("Printing board.\n");
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
);
512 for (line
= 0; line
< board
->height
; ++line
) {
513 free (board
->surface
[line
]);
514 free (board
->lock
[line
]);
516 free (board
->surface
);
518 board
->surface_valid
= false;
522 assert (!board
->surface_valid
);
526 /******************************************************************************/
527 int main (int argc
, char *argv
[])
530 unsigned int nitems_begin
, nitems_finish
;
531 pthread_attr_t thread_attributes
;
532 pthread_t sorter_threads
[NSORTERS
];
533 sorter_t sorters
[NSORTERS
];
536 unsigned int line
, column
;
537 sorter_argv_t sorters_argv
[NSORTERS
];
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
);
552 count_items(&board
, &item
, &nitems_begin
);
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).
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
);
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");