C two-bucket: final version + separate main
This commit is contained in:
26
c/two-bucket/main.c
Normal file
26
c/two-bucket/main.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/* Standalone tests.
|
||||||
|
* See GNUmakefile below for explanation
|
||||||
|
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||||
|
*/
|
||||||
|
#include "two_bucket.h"
|
||||||
|
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
int main(int ac, char **av)
|
||||||
|
{
|
||||||
|
int arg=1;
|
||||||
|
int b1, b2, goal, start;
|
||||||
|
bucket_result_t res;;
|
||||||
|
|
||||||
|
for (; arg<ac-3; arg+=4) {
|
||||||
|
b1 = atoi(av[arg]);
|
||||||
|
b2 = atoi(av[arg+1]);
|
||||||
|
goal = atoi(av[arg+2]);
|
||||||
|
start = atoi(av[arg+3]);
|
||||||
|
printf("b1=%d, b2=%d, goal=%d, start=%d\n", b1, b2, goal, start);
|
||||||
|
res = measure(b1, b2, goal, start);
|
||||||
|
printf(" pos=%d count=%d goal=%d liters=%d\n",
|
||||||
|
res.possible, res.move_count, res.goal_bucket,
|
||||||
|
##res.other_bucket_liters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@@ -37,13 +37,11 @@
|
|||||||
|
|
||||||
/* danger zone !! - this macro is BAD™ in general, dangerous double
|
/* danger zone !! - this macro is BAD™ in general, dangerous double
|
||||||
* evaluation, but ok here.
|
* evaluation, but ok here.
|
||||||
* What did you ask ? Oh, yes, of course, I never use this macro, this is
|
* If unsure why this is very bad, leave me a comment on exercism.
|
||||||
* the first and last time ;-)
|
|
||||||
* If unsure why this is very bad™, let me a comment on exercism.
|
|
||||||
*/
|
*/
|
||||||
#define MIN(x, y) ((x) <= (y)? (x): (y))
|
#define MIN(x, y) ((x) <= (y)? (x): (y))
|
||||||
|
|
||||||
/* a queue for moves (BFS). I use a stupid max value, a linked list would
|
/* a queue for moves (BFS). I use a max X*Y array, a linked list would
|
||||||
* be much better, would the buckets sizes being extremely huge.
|
* be much better, would the buckets sizes being extremely huge.
|
||||||
*/
|
*/
|
||||||
struct stack {
|
struct stack {
|
||||||
@@ -52,109 +50,65 @@ struct stack {
|
|||||||
int s[];
|
int s[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* our board: Warning, X/Y are from 0 to size, not C array size.
|
/* our game board
|
||||||
* Example, if cols=2 and rows
|
*/
|
||||||
*/
|
|
||||||
struct board {
|
struct board {
|
||||||
int X;
|
int X;
|
||||||
int Y;
|
int Y;
|
||||||
int board[];
|
int board[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void board_print(struct board *board)
|
static inline void board_init(struct board *board, int X, int Y, int goal)
|
||||||
{
|
{
|
||||||
int x=board->X, y=board->Y;
|
int i;
|
||||||
printf("board(%d, %d)\n", x, y);
|
board->X=X;
|
||||||
for (int row = y-1; row >= 0; --row) {
|
board->Y=Y;
|
||||||
printf("%03d ", row);
|
for (i=0; i < board->X*board->Y; ++i)
|
||||||
for (int col = 0; col < x; ++col) {
|
|
||||||
//printf("C: i=%d j=%d cell %d\n", i, j, i*x+j);
|
|
||||||
//printf(" %d ", board[i*x+j]);
|
|
||||||
printf(" %2d ", board->board[SQUARE(col, row, board)]);
|
|
||||||
//printf("row=%d col=%d x=%d square=%d\n", row, col, x, SQUARE(col, row, x));
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void board_init(struct board *board, int goal)
|
|
||||||
{
|
|
||||||
int i, x=board->X, y=board->Y;
|
|
||||||
|
|
||||||
printf("board_init(%d, %d, goal=%d)\n", x, y, goal);
|
|
||||||
//board_print(board, x, y);
|
|
||||||
for (i=0; i < x*y; ++i) {
|
|
||||||
printf("setting square %d (%d, %d)\n", i, COL(i, board), ROW(i, board));
|
|
||||||
*(board->board+i) = AVAILABLE;
|
*(board->board+i) = AVAILABLE;
|
||||||
}
|
|
||||||
board_print(board);
|
|
||||||
/* set target on goal row */
|
/* set target on goal row */
|
||||||
if (x > goal) {
|
if (board->X > goal) {
|
||||||
for (i = 0; i < y; ++i) {
|
for (i = 0; i < board->Y; ++i)
|
||||||
printf("A: x=%d i=%d goal=%d setting %d\n", x, i, goal, SQUARE(goal, i, board));
|
|
||||||
board->board[SQUARE(goal, i, board)] = GOAL;
|
board->board[SQUARE(goal, i, board)] = GOAL;
|
||||||
//board_print(board, x, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* set target on goal col */
|
/* set target on goal col */
|
||||||
board_print(board);
|
if (board->Y > goal) {
|
||||||
if (y > goal) {
|
for (i = 0; i < board->X; ++i)
|
||||||
for (i = 0; i < x; ++i) {
|
|
||||||
printf("B: x=%d i=%d goal=%d setting %d\n", x, i, goal, SQUARE(i, goal, board));
|
|
||||||
board->board[SQUARE(i, goal, board)] = GOAL;
|
board->board[SQUARE(i, goal, board)] = GOAL;
|
||||||
}
|
|
||||||
board_print(board);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enqueue(struct stack *s, int v)
|
static inline void enqueue(struct stack *s, int v)
|
||||||
{
|
{
|
||||||
printf("pushing v=%d\n", v);
|
|
||||||
//if (s->stack[s->last] == AVAILABLE)
|
|
||||||
s->s[s->last++] = v;
|
s->s[s->last++] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int dequeue(struct stack *s)
|
static inline int dequeue(struct stack *s)
|
||||||
{
|
{
|
||||||
int res;
|
return s->first < s->last ? s->s[s->first++] : -1;
|
||||||
printf("dequeue: first=%d last=%d val=%d\n", s->first, s->last, s->s[s->first]);
|
|
||||||
res = s->first < s->last ? s->s[s->first++] : -1;
|
|
||||||
printf("popping v=%d\n", res);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int move(struct board *board, struct stack *stack, int col, int row,
|
static int move(struct board *board, struct stack *stack, int col, int row,
|
||||||
int level, char *text)
|
int level)
|
||||||
{
|
{
|
||||||
printf("move to [%s] on (%d, %d) - level=%d curval=%d : ",
|
|
||||||
text, col, row, level, board->board[SQUARE(col, row, board)]);
|
|
||||||
board->board[SQUARE(col, row, board)] = level;
|
board->board[SQUARE(col, row, board)] = level;
|
||||||
enqueue (stack, SQUARE(col, row, board));
|
enqueue (stack, SQUARE(col, row, board));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int move_maybe(struct board *board, struct stack *stack, int col, int row,
|
static int move_maybe(struct board *board, struct stack *stack,
|
||||||
int level, char *text)
|
int col, int row, int level)
|
||||||
{
|
{
|
||||||
printf("trying to [%s] on (%d, %d) - level=%d curval=%d : ",
|
switch (board->board[SQUARE(col, row, board)]) {
|
||||||
text, col, row, level, board->board[SQUARE(col, row, board)]);
|
case GOAL:
|
||||||
if (board->board[SQUARE(col, row, board)] == AVAILABLE) {
|
return 1;
|
||||||
printf("OK\n");
|
case AVAILABLE:
|
||||||
|
return move(board, stack, col, row, level);
|
||||||
move(board, stack, col, row, level, text);
|
default:
|
||||||
//board->board[SQUARE(col, row, board)] = level;
|
return 0;
|
||||||
//enqueue (stack, SQUARE(col, row, board));
|
|
||||||
} else if (board->board[SQUARE(col, row, board)] == GOAL) {
|
|
||||||
printf("**************** GOAL\n");
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
printf("Impossible\n");
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bucket_result_t board_bfs(struct board *board, struct stack *stack, int start,
|
static bucket_result_t board_bfs(struct board *board, struct stack *stack,
|
||||||
const int goal)
|
const int goal)
|
||||||
{
|
{
|
||||||
int level = 0;
|
int level = 0;
|
||||||
@@ -162,57 +116,52 @@ static bucket_result_t board_bfs(struct board *board, struct stack *stack, int s
|
|||||||
int min, row, col, col1, row1;
|
int min, row, col, col1, row1;
|
||||||
int X=board->X, Y=board->Y;
|
int X=board->X, Y=board->Y;
|
||||||
bucket_result_t res = { .possible = false, .move_count = 0 };
|
bucket_result_t res = { .possible = false, .move_count = 0 };
|
||||||
/* initialize 1st square used */
|
|
||||||
printf("bfs(start=%d, X=%d, Y=%d)\n", start, board->X, board->Y);
|
|
||||||
|
|
||||||
/* now we consume as we can... */
|
/* now we consume as we can... */
|
||||||
while ((cur_square = dequeue(stack)) >= 0) {
|
while ((cur_square = dequeue(stack)) >= 0) {
|
||||||
col=COL(cur_square, board);
|
col=COL(cur_square, board);
|
||||||
row=ROW(cur_square, board);
|
row=ROW(cur_square, board);
|
||||||
level=board->board[cur_square];
|
level=board->board[cur_square];
|
||||||
board_print(board);
|
|
||||||
printf("move[pop=%d](col=%d, row=%d)=%d level=%d\n",
|
|
||||||
cur_square, col, row, board->board[cur_square], level);
|
|
||||||
if (col > 0) {
|
if (col > 0) {
|
||||||
col1 = 0;
|
col1 = 0;
|
||||||
row1 = row;
|
row1 = row;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "empty b1"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
if (row > 0) {
|
if (row > 0) {
|
||||||
col1 = col;
|
col1 = col;
|
||||||
row1 = 0;
|
row1 = 0;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "empty b2"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
if (col < X-1) {
|
if (col < X-1) {
|
||||||
col1 = X-1;
|
col1 = X-1;
|
||||||
row1 = row;
|
row1 = row;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "fill b1"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
if (row < Y-1) {
|
if (row < Y-1) {
|
||||||
col1 = col;
|
col1 = col;
|
||||||
row1 = Y-1;
|
row1 = Y-1;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "fill b2"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
if (col > 0 && row < Y-1) {
|
if (col > 0 && row < Y-1) {
|
||||||
min = MIN(col, Y-row-1);
|
min = MIN(col, Y-row-1);
|
||||||
col1 = col-min;
|
col1 = col - min;
|
||||||
row1 = row+min;
|
row1 = row + min;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "pour b1 in b2"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
if (row > 0 && col < X-1) {
|
if (row > 0 && col < X-1) {
|
||||||
min = MIN(row, X-col-1);
|
min = MIN(row, X-col-1);
|
||||||
col1 = col+min;
|
col1 = col + min;
|
||||||
row1 = row-min;
|
row1 = row - min;
|
||||||
if (move_maybe(board, stack, col1, row1, level+1, "pour b2 in b1"))
|
if (move_maybe(board, stack, col1, row1, level+1))
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto end; /* no more possible move */
|
goto end; /* fail: no more moves */
|
||||||
found:
|
found:
|
||||||
res.possible = true;
|
res.possible = true;
|
||||||
res.move_count = level+1;
|
res.move_count = level+1;
|
||||||
@@ -224,10 +173,6 @@ found:
|
|||||||
res.other_bucket_liters=col1;
|
res.other_bucket_liters=col1;
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
printf("END: possible=%d\n", res.possible);
|
|
||||||
printf(" move-count=%d\n", res.move_count);
|
|
||||||
printf(" goal-bucket=%d\n", res.goal_bucket);
|
|
||||||
printf(" other-bucket=%d\n", res.other_bucket_liters);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,12 +190,13 @@ bucket_result_t measure(const bucket_liters_t b1,
|
|||||||
struct board *board;
|
struct board *board;
|
||||||
struct stack *stack;
|
struct stack *stack;
|
||||||
|
|
||||||
printf("measure(b1=%d, b2=%d, goal=%d, start=%d)\n", b1, b2, goal, start);
|
/* impossible goal */
|
||||||
if (goal > b1 && goal > b2)
|
if (goal > b1 && goal > b2)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* initial move is the solution ? */
|
||||||
if ((start == BUCKET_ID_1 && goal == b1) ||
|
if ((start == BUCKET_ID_1 && goal == b1) ||
|
||||||
(start == BUCKET_ID_2 && goal == b2)) {
|
(start == BUCKET_ID_2 && goal == b2)) {
|
||||||
printf("done in 1\n");
|
|
||||||
res.possible = true;
|
res.possible = true;
|
||||||
res.move_count = 1;
|
res.move_count = 1;
|
||||||
res.goal_bucket = start;
|
res.goal_bucket = start;
|
||||||
@@ -259,18 +205,13 @@ bucket_result_t measure(const bucket_liters_t b1,
|
|||||||
|
|
||||||
if (!(stack = malloc(sizeof(*stack) + sizeof(*stack->s)*(b1+1)*(b2+1))))
|
if (!(stack = malloc(sizeof(*stack) + sizeof(*stack->s)*(b1+1)*(b2+1))))
|
||||||
return res;
|
return res;
|
||||||
stack->first = 0;
|
//int i;
|
||||||
stack->last = 0;
|
stack->first = stack->last = 0;
|
||||||
printf("board size: %lu int=%lu n=%d, %lu\n", sizeof(*board), sizeof(int),
|
|
||||||
(b1+1)*(b2+1),
|
|
||||||
sizeof(*board) + sizeof(*board->board)*(b1+1)*(b2+1));
|
|
||||||
if (!(board = malloc(sizeof(*board) + sizeof(*board->board)*(b1+1)*(b2+1)))) {
|
if (!(board = malloc(sizeof(*board) + sizeof(*board->board)*(b1+1)*(b2+1)))) {
|
||||||
free(stack);
|
free(stack);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
board->X = b1+1;
|
board_init(board, b1+1, b2+1, goal);
|
||||||
board->Y = b2+1;
|
|
||||||
board_init(board, goal);
|
|
||||||
/* only for exercism. better solutions could be found. Remove the next
|
/* only for exercism. better solutions could be found. Remove the next
|
||||||
* 3 lines to allow a different starting bucket (possibly better solution).
|
* 3 lines to allow a different starting bucket (possibly better solution).
|
||||||
*/
|
*/
|
||||||
@@ -278,43 +219,11 @@ bucket_result_t measure(const bucket_liters_t b1,
|
|||||||
board->board[SQUARE(0, b2, board)] = FORBIDDEN;
|
board->board[SQUARE(0, b2, board)] = FORBIDDEN;
|
||||||
board->board[SQUARE(b1, 0, board)] = FORBIDDEN;
|
board->board[SQUARE(b1, 0, board)] = FORBIDDEN;
|
||||||
|
|
||||||
if (start == BUCKET_ID_1) {
|
/* initial move */
|
||||||
move(board, stack, b1, 0, 1, "start with b1");
|
move(board, stack, start==BUCKET_ID_1? b1: 0, start==BUCKET_ID_2? b2: 0, 1);
|
||||||
//enqueue(stack, SQUARE(b1, 0, board));
|
|
||||||
//board->board[SQUARE(b1, 0, board)] = 1;
|
|
||||||
} else {
|
|
||||||
move(board, stack, 0, b2, 1, "start with b1");
|
|
||||||
//enqueue(stack, SQUARE(0, b2, board));
|
|
||||||
//board->board[SQUARE(0, b2, board)] = 1;
|
|
||||||
}
|
|
||||||
board_print(board);
|
|
||||||
|
|
||||||
res = board_bfs(board, stack, start, goal);
|
res = board_bfs(board, stack, goal);
|
||||||
free(stack);
|
free(stack);
|
||||||
free(board);
|
free(board);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See GNUmakefile below for explanation
|
|
||||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
|
||||||
*/
|
|
||||||
#ifdef UNIT_TEST
|
|
||||||
int main(int ac, char **av)
|
|
||||||
{
|
|
||||||
int arg=1;
|
|
||||||
int b1, b2, goal, start;
|
|
||||||
bucket_result_t res;;
|
|
||||||
|
|
||||||
for (; arg<ac-3; arg+=4) {
|
|
||||||
b1 = atoi(av[arg]);
|
|
||||||
b2 = atoi(av[arg+1]);
|
|
||||||
goal = atoi(av[arg+2]);
|
|
||||||
start = atoi(av[arg+2]);
|
|
||||||
printf("b1=%d, b2=%d, goal=%d, start=%d\n", b1, b2, goal, start);
|
|
||||||
res = measure(b1, b2, goal, start);
|
|
||||||
printf(" pos=%d count=%d goal=%d liters=%d\n",
|
|
||||||
res.possible, res.move_count, res.goal_bucket,
|
|
||||||
res.other_bucket_liters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
Reference in New Issue
Block a user