-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathnonogram.cpp
More file actions
158 lines (149 loc) · 3.12 KB
/
Copy pathnonogram.cpp
File metadata and controls
158 lines (149 loc) · 3.12 KB
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
151
152
153
154
155
156
157
158
#include "nonogram.h"
Nonogram::Nonogram(int w, int h) : width(w), height(h), solids(0), dots(0), field(new size_t[h]) {
if ((xAxis = (vector<size_t>**)malloc(width * sizeof(vector<size_t>*))) == NULL ||
(yAxis = (vector<size_t>**)malloc(height * sizeof(vector<size_t>*))) == NULL) {
cerr << "ERROR: Malloc failed." << endl;
exit(1);
}
generateField();
generatePuzzle();
}
Nonogram::~Nonogram() {
delete[] field;
for (size_t i = 0; i < width; ++i) {
delete xAxis[i];
}
for (size_t i = 0; i < height; ++i) {
delete yAxis[i];
}
free(xAxis);
free(yAxis);
}
vector<size_t>** Nonogram::getXAxis() {
return xAxis;
}
vector<size_t>** Nonogram::getYAxis() {
return yAxis;
}
size_t* Nonogram::getField() {
return field;
}
// Prints the puzzle. Mostly usable for debugging.
void Nonogram::print() {
for (size_t i = 0; i < height; ++i) {
for (size_t j = (1 << (width - 1)); j > 0; j >>= 1) {
if (field[i] & j) {
cout << "X";
}
else {
cout << " ";
}
}
cout << endl;
}
}
// Generates the puzzle (i.e. the numbers shown to the user) from the existing field.
void Nonogram::generatePuzzle() {
size_t temp;
for (size_t i = 0; i < height; ++i) {
temp = 0;
yAxis[i] = new vector<size_t>;
for (size_t j = (1 << (width - 1)); j > 0; j >>= 1) {
if (!(field[i] & j)) {
if (temp > 0) {
yAxis[i]->push_back(temp);
}
temp = 0;
}
else {
++temp;
}
}
if (temp > 0 || yAxis[i]->size() == 0) {
yAxis[i]->push_back(temp);
}
}
size_t mask = 1 << width;
for(size_t i = 0; i < width; ++i) {
mask >>= 1;
xAxis[i] = new vector<size_t>;
temp = 0;
for (size_t j = 0; j < height; ++j) {
if (!(field[j] & mask)) {
if (temp > 0) {
xAxis[i]->push_back(temp);
}
temp = 0;
}
else {
++temp;
}
}
if (temp > 0 || xAxis[i]->size() == 0) {
xAxis[i]->push_back(temp);
}
}
}
// Generate a semi-random playing field.
void Nonogram::generateField() {
int random, above, left;
size_t mask = 1 << (width - 1);
double prob;
srand(time(NULL));
for (size_t i = 0; i < height; ++i) {
field[i] = 0;
for (size_t j = mask; j > 0; j >>=1) {
if (i == 0) {
above = -1;
}
else {
above = ((field[i - 1] & j) > 0);
}
if (j == mask) {
left = -1;
}
else {
left = ((field[i] & (j << 1)) > 0);
}
prob = probability(above, left);
random = rand();
if (random > prob * RAND_MAX) {
++dots;
}
else {
field[i] |= j;
++solids;
}
}
}
}
/* Calculates the probability for the next block being black.
The purpose of this function is to have the generated field be random, but
not too random. We want a (roughly) 50-50 split between white and black fields,
and we'd rather see that the black & white fields are (again roughly) collected
in "islands" rather than a chessboard-type distribution.
*/
double Nonogram::probability(int above, int left) {
double p = 0.5;
switch (above + left) {
case -2:
case 1:
break;
case -1:
p = 0.25;
break;
case 0:
if (above == 0) {
p = 0.1;
}
else {
p = 0.75;
}
break;
case 2:
p = 0.9;
break;
}
p += (1.0 / (width * height)) * (dots - solids);
return p;
}