86 static constexpr int WIDTH = 7;
87 static constexpr int HEIGHT = 6;
91 using position_t =
typename std::conditional<WIDTH *(HEIGHT + 1) <= 64,
92 uint64_t, __int128>::type;
96 using position_t = uint64_t;
99 static constexpr int MIN_SCORE = -(WIDTH * HEIGHT) / 2 + 3;
100 static constexpr int MAX_SCORE = (WIDTH * HEIGHT + 1) / 2 - 3;
102 static_assert(WIDTH < 10,
"Board's width must be less than 10");
103 static_assert(WIDTH * (HEIGHT + 1) <=
sizeof(position_t) * 8,
104 "Board does not fit into position_t bitmask");
114 current_position ^= mask;
133 unsigned int play(
const std::string &seq) {
134 for (
unsigned int i = 0; i < seq.size(); i++) {
135 int col = seq[i] -
'1';
136 if (col < 0 || col >= Position::WIDTH || !
canPlay(col) ||
147 bool canWinNext()
const {
return winning_position() & possible(); }
157 position_t
key()
const {
return current_position + mask; }
177 uint64_t key_forward = 0;
178 for (
int i = 0; i < Position::WIDTH; i++)
179 partialKey3(key_forward, i);
181 uint64_t key_reverse = 0;
182 for (
int i = Position::WIDTH; i--;)
183 partialKey3(key_reverse, i);
185 return key_forward < key_reverse
202 position_t possible_mask = possible();
203 position_t opponent_win = opponent_winning_position();
204 position_t forced_moves = possible_mask & opponent_win;
210 possible_mask = forced_moves;
212 return possible_mask &
213 ~(opponent_win >> 1);
225 return popcount(compute_winning_position(current_position | move, mask));
231 Position() : current_position{0}, mask{0}, moves{0} {}
239 bool canPlay(
int col)
const {
return (mask & top_mask_col(col)) == 0; }
249 play((mask + bottom_mask_col(col)) & column_mask(col));
260 return winning_position() & possible() & column_mask(col);
264 position_t current_position;
271 void partialKey3(uint64_t &
key,
int col)
const {
272 for (position_t pos = UINT64_C(1) << (col * (Position::HEIGHT + 1));
273 pos & mask; pos <<= 1) {
275 if (pos & current_position)
286 position_t winning_position()
const {
287 return compute_winning_position(current_position, mask);
293 position_t opponent_winning_position()
const {
294 return compute_winning_position(current_position ^ mask, mask);
301 position_t possible()
const {
return (mask + bottom_mask) & board_mask; }
306 static unsigned int popcount(position_t m) {
319 static position_t compute_winning_position(position_t position,
322 position_t r = (position << 1) & (position << 2) & (position << 3);
325 position_t p = (position << (HEIGHT + 1)) & (position << 2 * (HEIGHT + 1));
326 r |= p & (position << 3 * (HEIGHT + 1));
327 r |= p & (position >> (HEIGHT + 1));
328 p = (position >> (HEIGHT + 1)) & (position >> 2 * (HEIGHT + 1));
329 r |= p & (position << (HEIGHT + 1));
330 r |= p & (position >> 3 * (HEIGHT + 1));
333 p = (position << HEIGHT) & (position << 2 * HEIGHT);
334 r |= p & (position << 3 * HEIGHT);
335 r |= p & (position >> HEIGHT);
336 p = (position >> HEIGHT) & (position >> 2 * HEIGHT);
337 r |= p & (position << HEIGHT);
338 r |= p & (position >> 3 * HEIGHT);
341 p = (position << (HEIGHT + 2)) & (position << 2 * (HEIGHT + 2));
342 r |= p & (position << 3 * (HEIGHT + 2));
343 r |= p & (position >> (HEIGHT + 2));
344 p = (position >> (HEIGHT + 2)) & (position >> 2 * (HEIGHT + 2));
345 r |= p & (position << (HEIGHT + 2));
346 r |= p & (position >> 3 * (HEIGHT + 2));
348 return r & (board_mask ^ mask);
352 template <
int w
idth,
int height>
struct bottom {
353 static constexpr position_t mask =
354 bottom<width - 1, height>::mask | position_t(1)
355 << (width - 1) * (height + 1);
357 template <
int height>
struct bottom<0, height> {
358 static constexpr position_t mask = 0;
361 static constexpr position_t bottom_mask = bottom<WIDTH, HEIGHT>::mask;
362 static constexpr position_t board_mask = bottom_mask * ((1LL << HEIGHT) - 1);
366 static constexpr position_t top_mask_col(
int col) {
367 return UINT64_C(1) << ((HEIGHT - 1) + col * (HEIGHT + 1));
372 static constexpr position_t bottom_mask_col(
int col) {
373 return UINT64_C(1) << col * (HEIGHT + 1);
378 static constexpr position_t column_mask(
int col) {
379 return ((UINT64_C(1) << HEIGHT) - 1) << col * (HEIGHT + 1);