-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathline.hpp
150 lines (124 loc) · 3.22 KB
/
line.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#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