vfs: check userland buffers before reading them.
[haiku.git] / src / apps / sudoku / SudokuField.cpp
blob279f03e9ccc3b086b86e225863ef7f39776845df
1 /*
2 * Copyright 2007-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "SudokuField.h"
9 #include <new>
10 #include <stdio.h>
11 #include <string.h>
13 #include <Message.h>
14 #include <OS.h>
17 const char*
18 mask(uint32 set)
20 static char text[64];
21 uint32 i = 0;
22 for (int32 number = 9; number > 0; number--) {
23 text[i++] = set & (1UL << (number - 1)) ? number + '0' : '-';
26 text[i] = '\0';
27 return text;
31 // #pragma mark -
34 SudokuField::field::field()
36 hint_mask(0),
37 valid_mask(~0),
38 flags(0),
39 value(0)
44 // #pragma mark -
47 SudokuField::SudokuField(uint32 size)
49 fSize(size * size),
50 fBlockSize(size)
52 fFields = new (std::nothrow) field[fSize * fSize];
53 fMaxMask = (1UL << fSize) - 1;
57 SudokuField::SudokuField(const BMessage* archive)
59 if (archive->FindInt32("block size", (int32*)&fBlockSize) != B_OK)
60 return;
62 fSize = fBlockSize * fBlockSize;
63 fMaxMask = (1UL << fSize) - 1;
65 uint32 count = fSize * fSize;
66 fFields = new (std::nothrow) field[count];
67 if (fFields == NULL)
68 return;
70 for (uint32 i = 0; i < count; i++) {
71 struct field& field = fFields[i];
73 if (archive->FindInt32("value", i, (int32*)&field.value) != B_OK
74 || archive->FindInt32("valid mask", i,
75 (int32*)&field.valid_mask) != B_OK
76 || archive->FindInt32("hint mask", i,
77 (int32*)&field.hint_mask) != B_OK
78 || archive->FindInt32("flags", i, (int32*)&field.flags) != B_OK)
79 break;
84 SudokuField::SudokuField(const SudokuField& other)
85 : BArchivable(other)
87 fSize = other.fSize;
88 fBlockSize = other.fBlockSize;
89 fMaxMask = other.fMaxMask;
91 fFields = new (std::nothrow) field[fSize * fSize];
92 if (fFields != NULL)
93 memcpy(fFields, other.fFields, sizeof(field) * fSize * fSize);
97 SudokuField::~SudokuField()
99 delete[] fFields;
103 status_t
104 SudokuField::InitCheck()
106 if (fBlockSize == 0)
107 return B_BAD_VALUE;
108 return fFields == NULL ? B_NO_MEMORY : B_OK;
112 status_t
113 SudokuField::Archive(BMessage* archive, bool deep) const
115 status_t status = BArchivable::Archive(archive, deep);
116 if (status == B_OK)
117 archive->AddInt32("block size", fBlockSize);
118 if (status < B_OK)
119 return status;
121 uint32 count = fSize * fSize;
122 for (uint32 i = 0; i < count && status == B_OK; i++) {
123 struct field& field = fFields[i];
124 status = archive->AddInt32("value", field.value);
125 if (status == B_OK)
126 status = archive->AddInt32("valid mask", field.valid_mask);
127 if (status == B_OK)
128 status = archive->AddInt32("hint mask", field.hint_mask);
129 if (status == B_OK)
130 status = archive->AddInt32("flags", field.flags);
133 return status;
137 /*static*/ SudokuField*
138 SudokuField::Instantiate(BMessage* archive)
140 if (!validate_instantiation(archive, "SudokuField"))
141 return NULL;
143 return new SudokuField(archive);
147 void
148 SudokuField::Reset()
150 for (uint32 y = 0; y < fSize; y++) {
151 for (uint32 x = 0; x < fSize; x++) {
152 struct field& field = _FieldAt(x, y);
153 field.value = 0;
154 field.flags = 0;
155 field.hint_mask = 0;
156 field.valid_mask = fMaxMask;
162 status_t
163 SudokuField::SetTo(char base, const char* data)
165 if (data != NULL && strlen(data) < fSize * fSize)
166 return B_BAD_VALUE;
168 Reset();
170 if (data == NULL)
171 return B_OK;
173 uint32 i = 0;
175 for (uint32 y = 0; y < fSize; y++) {
176 for (uint32 x = 0; x < fSize; x++) {
177 uint32 value = data[i++] - base;
178 if (value) {
179 struct field& field = _FieldAt(x, y);
180 field.value = value;
181 field.flags = kInitialValue;
186 for (uint32 y = 0; y < fSize; y++) {
187 for (uint32 x = 0; x < fSize; x++) {
188 _ComputeValidMask(x, y, false);
192 return B_OK;
196 void
197 SudokuField::SetTo(const SudokuField* field)
199 if (field == NULL) {
200 Reset();
201 return;
204 for (uint32 y = 0; y < fSize; y++) {
205 for (uint32 x = 0; x < fSize; x++) {
206 _FieldAt(x, y) = field->_FieldAt(x, y);
212 void
213 SudokuField::Dump()
215 for (uint32 y = 0; y < fSize; y++) {
216 for (uint32 x = 0; x < fSize; x++) {
217 if (x != 0 && x % fBlockSize == 0)
218 putchar(' ');
219 printf("%" B_PRIu32, ValueAt(x, y));
221 putchar('\n');
226 bool
227 SudokuField::IsSolved() const
229 for (uint32 y = 0; y < fSize; y++) {
230 for (uint32 x = 0; x < fSize; x++) {
231 if (!_ValidValueAt(x, y))
232 return false;
236 return true;
240 bool
241 SudokuField::IsEmpty() const
243 for (uint32 y = 0; y < fSize; y++) {
244 for (uint32 x = 0; x < fSize; x++) {
245 if (ValueAt(x, y) != 0)
246 return false;
250 return true;
254 bool
255 SudokuField::IsValueCompleted(uint32 value) const
257 uint32 count = 0;
258 for (uint32 y = 0; y < fSize; y++) {
259 for (uint32 x = 0; x < fSize; x++) {
260 if (ValueAt(x, y) == value)
261 count++;
265 return count == Size();
269 void
270 SudokuField::SetHintMaskAt(uint32 x, uint32 y, uint32 hintMask)
272 _FieldAt(x, y).hint_mask = hintMask;
276 uint32
277 SudokuField::HintMaskAt(uint32 x, uint32 y) const
279 return _FieldAt(x, y).hint_mask;
283 bool
284 SudokuField::HasHint(uint32 x, uint32 y, uint32 value) const
286 return (_FieldAt(x, y).hint_mask & (1UL << (value - 1))) != 0;
290 void
291 SudokuField::SetValidMaskAt(uint32 x, uint32 y, uint32 validMask)
293 _FieldAt(x, y).valid_mask = validMask & fMaxMask;
297 uint32
298 SudokuField::ValidMaskAt(uint32 x, uint32 y) const
300 return _FieldAt(x, y).valid_mask;
304 bool
305 SudokuField::IsValid(uint32 x, uint32 y, uint32 value) const
307 return (_FieldAt(x, y).valid_mask & (1UL << (value - 1))) != 0;
311 void
312 SudokuField::SetFlagsAt(uint32 x, uint32 y, uint32 flags)
314 _FieldAt(x, y).flags = flags;
318 uint32
319 SudokuField::FlagsAt(uint32 x, uint32 y) const
321 return _FieldAt(x, y).flags;
325 bool
326 SudokuField::IsInitialValue(uint32 x, uint32 y) const
328 return (_FieldAt(x, y).flags & kInitialValue) != 0;
332 void
333 SudokuField::SetValueAt(uint32 x, uint32 y, uint32 value, bool setSolved)
335 _FieldAt(x, y).value = value;
336 _FieldAt(x, y).hint_mask = 0;
337 _UpdateValidMaskChanged(x, y, setSolved);
341 uint32
342 SudokuField::ValueAt(uint32 x, uint32 y) const
344 return _FieldAt(x, y).value;
348 bool
349 SudokuField::_ValidValueAt(uint32 x, uint32 y) const
351 uint32 value = _FieldAt(x, y).value;
352 if (!value)
353 return false;
355 value = 1UL << (value - 1);
356 return (_FieldAt(x, y).valid_mask & value) != 0;
360 void
361 SudokuField::_ComputeValidMask(uint32 x, uint32 y, bool setSolved)
363 if (ValueAt(x, y))
364 return;
366 // check row
368 uint32 foundMask = 0;
369 for (uint32 i = 0; i < fSize; i++) {
370 uint32 value = ValueAt(i, y);
371 if (value && _ValidValueAt(i, y))
372 foundMask |= 1UL << (value - 1);
375 // check column
377 for (uint32 i = 0; i < fSize; i++) {
378 uint32 value = ValueAt(x, i);
379 if (value && _ValidValueAt(x, i))
380 foundMask |= 1UL << (value - 1);
383 // check block
385 uint32 offsetX = x / fBlockSize * fBlockSize;
386 uint32 offsetY = y / fBlockSize * fBlockSize;
388 for (uint32 partY = 0; partY < fBlockSize; partY++) {
389 for (uint32 partX = 0; partX < fBlockSize; partX++) {
390 uint32 value = ValueAt(partX + offsetX, partY + offsetY);
391 if (value && _ValidValueAt(partX + offsetX, partY + offsetY))
392 foundMask |= 1UL << (value - 1);
396 SetValidMaskAt(x, y, ~foundMask);
398 if (setSolved) {
399 // find the one set bit, if not more
400 uint32 value = 0;
401 for (uint32 i = 0; i < fSize; i++) {
402 if ((foundMask & (1UL << i)) == 0) {
403 if (value != 0) {
404 value = 0;
405 break;
408 value = i + 1;
411 if (value != 0)
412 SetValueAt(x, y, value, true);
417 void
418 SudokuField::_UpdateValidMaskChanged(uint32 x, uint32 y, bool setSolved)
420 // update row
422 for (uint32 i = 0; i < fSize; i++) {
423 _ComputeValidMask(i, y, setSolved);
426 // update column
428 for (uint32 i = 0; i < fSize; i++) {
429 if (i == y)
430 continue;
432 _ComputeValidMask(x, i, setSolved);
435 // update block
437 uint32 offsetX = x / fBlockSize * fBlockSize;
438 uint32 offsetY = y / fBlockSize * fBlockSize;
440 for (uint32 partY = 0; partY < fBlockSize; partY++) {
441 for (uint32 partX = 0; partX < fBlockSize; partX++) {
442 if (partX + offsetX == x || partY + offsetY == y)
443 continue;
445 _ComputeValidMask(partX + offsetX, partY + offsetY, setSolved);
451 const SudokuField::field&
452 SudokuField::_FieldAt(uint32 x, uint32 y) const
454 if (x >= fSize || y >= fSize)
455 debugger("field outside bounds");
457 return fFields[x + y * fSize];
461 SudokuField::field&
462 SudokuField::_FieldAt(uint32 x, uint32 y)
464 if (x >= fSize || y >= fSize)
465 debugger("field outside bounds");
467 return fFields[x + y * fSize];