4 Commits

4 changed files with 91 additions and 20 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "vue-nonograms-solid", "name": "vue-nonograms-solid",
"version": "1.6.1", "version": "1.6.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "vue-nonograms-solid", "name": "vue-nonograms-solid",
"version": "1.6.1", "version": "1.6.3",
"dependencies": { "dependencies": {
"fireworks-js": "^2.10.8", "fireworks-js": "^2.10.8",
"flag-icons": "^7.5.0", "flag-icons": "^7.5.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "vue-nonograms-solid", "name": "vue-nonograms-solid",
"version": "1.6.1", "version": "1.6.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed, onMounted, watch } from 'vue';
import { usePuzzleStore } from '@/stores/puzzle'; import { usePuzzleStore } from '@/stores/puzzle';
import { useI18n } from '@/composables/useI18n'; import { useI18n } from '@/composables/useI18n';
import { calculateDifficulty } from '@/utils/puzzleUtils'; import { calculateDifficulty } from '@/utils/puzzleUtils';
@@ -12,6 +12,26 @@ const customSize = ref(10);
const fillRate = ref(50); const fillRate = ref(50);
const errorMsg = ref(''); const errorMsg = ref('');
onMounted(() => {
const savedSize = localStorage.getItem('nonograms_custom_size');
if (savedSize && !isNaN(savedSize)) {
customSize.value = Math.max(5, Math.min(80, Number(savedSize)));
}
const savedFillRate = localStorage.getItem('nonograms_custom_fill_rate');
if (savedFillRate && !isNaN(savedFillRate)) {
fillRate.value = Math.max(10, Math.min(90, Number(savedFillRate)));
}
});
watch(customSize, (newVal) => {
localStorage.setItem('nonograms_custom_size', newVal);
});
watch(fillRate, (newVal) => {
localStorage.setItem('nonograms_custom_fill_rate', newVal);
});
const snapToStep = (value, step) => { const snapToStep = (value, step) => {
const rounded = Math.round(value / step) * step; const rounded = Math.round(value / step) * step;
return Math.max(5, Math.min(80, rounded)); return Math.max(5, Math.min(80, rounded));

View File

@@ -91,15 +91,33 @@ const solveLineLogic = (lineState, hints) => {
return result; return result;
} }
const len = hints[hintIndex]; const len = hints[hintIndex];
// maxStart logic: we need enough space for this block (len) + subsequent blocks/gaps (suffixMin[hintIndex+1])
// suffixMin[hintIndex] = len + (m - hintIndex - 1) + suffixMin[hintIndex+1]
// Actually suffixMin[hintIndex] already includes everything needed from here to end.
// So if we place block at start, end is start + len.
// Total space needed is suffixMin[hintIndex].
// So start can go up to n - suffixMin[hintIndex].
const maxStart = n - suffixMin[hintIndex]; const maxStart = n - suffixMin[hintIndex];
for (let start = pos; start <= maxStart; start++) { for (let start = pos; start <= maxStart; start++) {
if (hasFilled(pos, start)) continue; if (hasFilled(pos, start)) continue; // Must be empty before this block
if (hasCross(start, start + len)) continue; if (hasCross(start, start + len)) continue; // Block space must be free of crosses
if (start + len < n && lineState[start + len] === 1) continue;
const nextPos = start + len < n ? start + len + 1 : start + len; // If not the last block, we need a gap after
if (canPlaceSuffix(nextPos, hintIndex + 1)) { if (hintIndex < m - 1) {
memoSuffix[pos][hintIndex] = true; if (start + len < n && lineState[start + len] === 1) continue; // Gap must not be filled
return true; // We can assume gap is at start + len. Next block starts at least at start + len + 1
const nextPos = start + len + 1;
if (canPlaceSuffix(nextPos, hintIndex + 1)) {
memoSuffix[pos][hintIndex] = true;
return true;
}
} else {
// Last block
// Check if we can fill the rest with empty
if (hasFilled(start + len, n)) continue;
memoSuffix[pos][hintIndex] = true;
return true;
} }
} }
memoSuffix[pos][hintIndex] = false; memoSuffix[pos][hintIndex] = false;
@@ -115,16 +133,42 @@ const solveLineLogic = (lineState, hints) => {
return result; return result;
} }
const len = hints[hintCount - 1]; const len = hints[hintCount - 1];
const maxStart = pos - len - 1;
// Logic for prefix:
// We are placing the (hintCount-1)-th block ending at 'start + len' <= pos.
// So 'start' <= pos - len.
// But we also need to ensure there is space for previous blocks.
// However, the simple constraint is just iterating backwards.
// maxStart: if this is the only block, maxStart = pos - len.
// If there are previous blocks, we need a gap before this block.
// So previous block ended at start - 1.
// Actually the recursive call will handle space check.
// But for the gap check:
// If we place block at 'start', we need lineState[start-1] != 1 (if start > 0).
// And we recursively check canPlacePrefix(start-1, count-1).
// But if start=0 and count > 1, impossible.
const maxStart = pos - len; // Simplified, loop condition handles rest
for (let start = maxStart; start >= 0; start--) { for (let start = maxStart; start >= 0; start--) {
if (hasCross(start, start + len)) continue; if (hasCross(start, start + len)) continue;
if (start + len < pos && lineState[start + len] === 1) continue; if (hasFilled(start + len, pos)) continue; // Must be empty after this block up to pos
if (hasFilled(start + len, pos)) continue;
if (start > 0 && lineState[start - 1] === 1) continue; // Check gap before
const prevPos = start > 0 ? start - 1 : 0; if (hintCount > 1) {
if (canPlacePrefix(prevPos, hintCount - 1)) { if (start === 0) continue; // No space for previous blocks
memoPrefix[pos][hintCount] = true; if (lineState[start - 1] === 1) continue; // Gap must not be filled
return true; const prevPos = start - 1;
if (canPlacePrefix(prevPos, hintCount - 1)) {
memoPrefix[pos][hintCount] = true;
return true;
}
} else {
// First block
if (hasFilled(0, start)) continue; // Before first block must be empty
memoPrefix[pos][hintCount] = true;
return true;
} }
} }
memoPrefix[pos][hintCount] = false; memoPrefix[pos][hintCount] = false;
@@ -136,7 +180,14 @@ const solveLineLogic = (lineState, hints) => {
const len = hints[i]; const len = hints[i];
const starts = []; const starts = [];
for (let start = 0; start <= n - len; start++) { for (let start = 0; start <= n - len; start++) {
if (!canPlacePrefix(start, i)) continue; if (i === 0) {
if (!canPlacePrefix(start, 0)) continue;
} else {
if (start === 0) continue;
if (lineState[start - 1] === 1) continue;
if (!canPlacePrefix(start - 1, i)) continue;
}
if (hasCross(start, start + len)) continue; if (hasCross(start, start + len)) continue;
if (start + len < n && lineState[start + len] === 1) continue; if (start + len < n && lineState[start + len] === 1) continue;
const nextPos = start + len < n ? start + len + 1 : start + len; const nextPos = start + len < n ? start + len + 1 : start + len;