about summary refs log tree commit diff stats
path: root/Source/Validator.cpp
blob: cb0ffa8f87e57e5de088dac7bf93a7ae8dbe5a82 (plain) (blame)
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
#include "pch.h"
#include "Validator.h"
#include "Puzzle.h"

void Validator::Validate(Puzzle& p) {
    // console.log('Validating', puzzle);
    p.valid = true; // Assume valid until we find an invalid element
    p.invalidElements.clear();
    p.negations.clear();

    bool puzzleHasSymbols = false;
    bool puzzleHasStart = false;
    bool puzzleHasEnd = false;
    // Validate gap failures as an early exit.
    for (int x = 0; x < p.width; x++) {
        for (int y = 0; y < p.height; y++) {
            Cell cell = p.grid[x][y];
            auto decoration = cell.decoration;
            if (decoration) {
                if (decoration->type == Type::Stone ||
                    decoration->type == Type::Star ||
                    decoration->type == Type::Nega ||
                    decoration->type == Type::Poly ||
                    decoration->type == Type::Ylop) {
                    puzzleHasSymbols = true;
                    continue;
                }
                if (decoration->type == Type::Triangle) {
                    int actualCount = 0;
                    if (p.GetLine(x - 1, y) != Cell::Color::NONE) actualCount++;
                    if (p.GetLine(x + 1, y) != Cell::Color::NONE) actualCount++;
                    if (p.GetLine(x, y - 1) != Cell::Color::NONE) actualCount++;
                    if (p.GetLine(x, y + 1) != Cell::Color::NONE) actualCount++;
                    if (decoration->count != actualCount) {
                        // console.log('Triangle at grid['+x+']['+y+'] has', actualCount, 'borders')
                        p.invalidElements.emplace_back(x, y);
                    }
                }
            }
            if (cell.gap != Cell::Gap::NONE && cell.color != Cell::Color::NONE) {
                // console.log('Gap at', x, y, 'is covered')
                p.valid = false;
            }
            if (cell.dot != Cell::Dot::NONE) {
                if (cell.color == Cell::Color::NONE) {
                    // console.log('Dot at', x, y, 'is not covered')
                    p.invalidElements.emplace_back(x, y);
                } else if (cell.color == Cell::Color::BLUE && cell.dot == Cell::Dot::YELLOW) {
                    // console.log('Yellow dot at', x, y, 'is covered by blue line')
                    p.valid = false;
                } else if (cell.color == Cell::Color::YELLOW && cell.dot == Cell::Dot::BLUE) {
                    // console.log('Blue dot at', x, y, 'is covered by yellow line')
                    p.valid = false;
                }
            }
            if (cell.color != Cell::Color::NONE) {
                if (cell.start == true) puzzleHasStart = true;
                if (cell.end != Cell::Dir::NONE) puzzleHasEnd = true;
            }
        }
    }
    if (!puzzleHasStart || !puzzleHasEnd) {
        // console.log('There is no covered start or endpoint')
        p.valid = false;
    }

    // Perf optimization: We can skip computing regions if the grid has no symbols.
    if (!puzzleHasSymbols) { // No additional symbols, and we already checked dots & gaps
        p.valid &= (p.invalidElements.size() == 0);
    } else { // Additional symbols, so we need to discard dots & divide them by region
        /*
        p.invalidElements.clear();
        std::vector<Region> regions = p.GetRegions();
        // console.log('Found', regions.length, 'regions');
        // console.debug(regions);

        for (const Region& region : regions) {
          std::string key = region.grid.ToString();
          auto regionData = puzzle.regionCache[key];
          if (regionData == undefined) {
            console.log('Cache miss for region', region, 'key', key);
            regionData = _regionCheckNegations(puzzle, region);
            // Entirely for convenience
            regionData.valid = (regionData.invalidElements.size() == 0)
            // console.log('Region valid:', regionData.valid);

            if (!DISABLE_CACHE) {
              p.regionCache[key] = regionData;
            }
          }
          p.negations = p.negations.concat(regionData.negations);
          p.invalidElements = p.invalidElements.concat(regionData.invalidElements);
          p.valid = p.valid && regionData.valid;
        }
        */
    }
    // console.log('Puzzle has', puzzle.invalidElements.length, 'invalid elements')
}