Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
#ifndef TWENTY48_LINE_HPP
#include <array>
#include <iomanip>
#include <map>
#include <iostream>
#include "twenty48.hpp"
namespace twenty48 {
template <int size> class line_t {
uint16_t nybbles;
public:
typedef std::array<uint8_t, size> array_t;
line_t(uint16_t initial_nybbles = 0) {
nybbles = initial_nybbles;
}
explicit line_t(const array_t &array) {
nybbles = 0;
for (size_t i = 0; i < size; ++i) {
set_nybble(i, array[i]);
}
}
line_t<size> move() {
array_t line = to_a();
size_t done = 0;
size_t merged = 0;
for (size_t i = 0; i < size; ++i) {
uint8_t value = line[i];
if (value == 0) {
continue;
}
if (done > merged && line[done - 1] == value) {
line[done - 1] += 1;
line[i] = 0;
merged = done;
} else {
if (i > done) {
line[done] = value;
line[i] = 0;
}
++done;
}
}
return line_t(line);
}
/**
* Does the line contain a pair of cells, both with value `value`, separated
* only by zero or more zeros? If so, we can always swipe along the line to
* get the `value + 1` tile.
*/
bool has_adjacent_pair(uint8_t value) const {
bool found_first = false;
for (size_t i = 0; i < size; ++i) {
uint8_t cell_value = (*this)[i];
if (found_first) {
if (cell_value == 0) continue;
return cell_value == value;
}
if (cell_value == value) {
found_first = true;
}
}
return false;
}
uint16_t get_nybbles() const {
return nybbles;
}
uint8_t operator[](size_t i) const {
return twenty48::get_nybble(nybbles, i, size);
}
array_t to_a() const {
array_t result;
for (size_t i = 0; i < size; ++i) result[i] = (*this)[i];
return result;
}
#ifndef SWIG
/**
* Precompute all possible moves. It only takes about 1MiB, even for the
* 4x4 board. This actually computes moves with tiles up to 2^15.
*/
struct table_t {
const static size_t TABLE_SIZE = UINT16_MAX >> 4 * (4 - size);
uint16_t table[TABLE_SIZE + 1];
table_t() {
for (uint32_t nybbles = 0; nybbles <= TABLE_SIZE; ++nybbles) {
table[nybbles] = line_t(nybbles).move().get_nybbles();
}
}
};
#endif
/**
* Look up the result of moving the given line.
*/
static uint16_t lookup_move(uint16_t nybbles) {
static table_t table;
return table.table[nybbles];
};
static uint16_t lookup_move(const line_t<size> &line) {
return lookup_move(line.get_nybbles());
};
static uint8_t get_nybble(uint16_t nybbles, size_t i) {
return twenty48::get_nybble(nybbles, i, size);
}
static uint16_t set_nybble(uint16_t nybbles, size_t i, uint8_t value) {
return twenty48::set_nybble(nybbles, i, value, size);
}
private:
void set_nybble(size_t i, uint8_t value) {
nybbles = set_nybble(nybbles, i, value);
}
};
template <int size>
std::ostream &operator << (std::ostream &os, const line_t<size> &line) {
for (size_t i = 0; i < size; ++i) {
if (line[i] == 0) {
os << " ";
} else {
os << (1 << line[i]) << ' ';
}
}
os << "(0x" << std::hex << line.get_nybbles() << std::dec << ')';
return os;
}
}
#define TWENTY48_LINE_HPP
#endif