Morpion solitaire: Difference between revisions

Content added Content deleted
m (link to rules)
(→‎{{header|C}}: reinterpreted rules when one position can complete multiple lines)
Line 29: Line 29:


/* option: how long a line is. Options probably should have been made into
/* option: how long a line is. Options probably should have been made into
* commandline args, if I were not lazy. Also, if line_len is set to 3,
* commandline args, if I were not lazy. Also, if line_len is set to 3,
* the game may keep going indefinitely: best use auto mode. */
* the game may keep going indefinitely: best use auto mode. */
int line_len = 5;
int line_len = 5;


/* option: whether two lines are allowed to be in the same direction and
/* option: whether two lines are allowed to be in the same direction and
* connected end to end. Note: two lines crossing are always ok. */
* connected end to end. Note: two lines crossing are always ok. */
int disjoint = 1;
int disjoint = 0;


int **board = 0, width, height;
int **board = 0, width, height;
Line 49: Line 49:
s_dir_nw_se = 1 << 4,
s_dir_nw_se = 1 << 4,
s_newly_added = 1 << 5,
s_newly_added = 1 << 5,
s_current = 1 << 6,
};
};


Line 107: Line 108:
int i, j;
int i, j;
for_i for_j mvprintw(i + 1, j * 2,
for_i for_j mvprintw(i + 1, j * 2,
(board[i][j] & s_newly_added) ? "[]"
(board[i][j] & s_current) ? "X "
: (board[i][j] & s_occupied) ? "* " : " ");
: (board[i][j] & s_newly_added) ? "O "
: (board[i][j] & s_occupied) ? "+ " : " ");
refresh();
refresh();
}
}
Line 130: Line 132:
{1, 1, s_dir_nw_se}
{1, 1, s_dir_nw_se}
};
};

typedef struct { int m, s, seq, x, y; } move_t;


/* test if a point can complete a line, or take that point */
/* test if a point can complete a line, or take that point */
int add_piece(int x, int y, int test_only)
void test_postion(int y, int x, move_t * rec)
{
{
int m, k, s, dx, dy, xx, yy, dir;
int m, k, s, dx, dy, xx, yy, dir;
if (board[y][x] & s_occupied) return;
if (test_only) {
if (board[y][x] & s_occupied) return 0;
} else
board[y][x] |= s_occupied;


for (m = 0; m < 4; m++) { /* 4 directions */
for (m = 0; m < 4; m++) { /* 4 directions */
Line 162: Line 163:
if (k != line_len) continue;
if (k != line_len) continue;


/* position ok */
/* position ok; irand() to even each option's chance of
being picked */
if (test_only) return 1;
if (! irand(++rec->seq))

rec->m = m, rec->s = s, rec->x = x, rec->y = y;
/* mark existing pieces for direction taken */
for (k = 0; k < line_len; k++) {
xx = x + dx * (k + s);
yy = y + dy * (k + s);
board[yy][xx] |= s_newly_added;
if (k >= disjoint || k < line_len - disjoint)
board[yy][xx] |= dir;
}
}
}
}
}
}
return 0;

void add_piece(move_t *rec) {
int dx = ofs[rec->m][0];
int dy = ofs[rec->m][1];
int dir= ofs[rec->m][2];
int xx, yy, k;

board[rec->y][rec->x] |= (s_current | s_occupied);

for (k = 0; k < line_len; k++) {
xx = rec->x + dx * (k + rec->s);
yy = rec->y + dy * (k + rec->s);
board[yy][xx] |= s_newly_added;
if (k >= disjoint || k < line_len - disjoint)
board[yy][xx] |= dir;
}
}
}


int next_move()
int next_move()
{
{
int i, j, x = -1, y = -1, found = 0;
int i, j;
move_t rec;
rec.seq = 0;


/* wipe last iteration's new line markers */
for_i for_j board[i][j] &= ~s_newly_added;
for_i for_j board[i][j] &= ~(s_newly_added | s_current);


/* randomly pick one of next legal moves */
for_i for_j
for_i for_j test_postion(i, j, &rec);
/* irand() ensures every legal move gets equal chance of
* being selected */
if (add_piece(j, i, 1) && !irand(++found))
x = j, y = i;


/* didn't find any move, game over */
if (x == -1) return 0;
if (!rec.seq) return 0;


add_piece(x, y, 0);
add_piece(&rec);


x = (x == width - 1) ? 1 : x ? 0 : -1;
rec.x = (rec.x == width - 1) ? 1 : rec.x ? 0 : -1;
y = (y == height - 1) ? 1 : y ? 0 : -1;
rec.y = (rec.y == height - 1) ? 1 : rec.y ? 0 : -1;


if (x || y) expand_board(x, y);
if (rec.x || rec.y) expand_board(rec.x, rec.y);
return 1;
return 1;
}
}