Skip to content

Commit 9c5b73c

Browse files
committed
dupes n merging
1 parent e574d41 commit 9c5b73c

6 files changed

Lines changed: 772 additions & 62 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Water Sort Screenshot Solver
22

3+
[Live on Github Pages](https://doublemover.github.io/WaterSortScreenshotSolver/)
4+
35
This is a **static single-page app** that:
46

57
1. Parses a Water-Sort style puzzle screenshot in the browser using OpenCV.js (WASM) in a Web Worker
68
2. Reads the bottom powerup badges (retries / shuffles / add-bottles) using Tesseract.js (WASM OCR)
79
3. Runs a BFS solver to separate colors into single-color bottles
810

11+
<img width="1885" height="930" alt="image" src="https://github.com/user-attachments/assets/89cf8e67-e4e2-49e2-90c8-9a1d5d62a6f9" />

colors.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,54 @@ export function buildColorLabels(colorsById) {
105105
const rawNames = new Map();
106106
for (const id of ids) rawNames.set(id, guessColorName(colorsById[String(id)]));
107107

108+
// Resolve the only two "legit" near-duplicate naming cases we expect in this game:
109+
// - Blue vs Periwinkle
110+
// - Green vs Lime
111+
// Everything else should ideally be unique; if not, we still fall back to numbering.
112+
const hsvById = new Map();
113+
for (const id of ids) {
114+
const { r, g, b } = hexToRgb(colorsById[String(id)]);
115+
hsvById.set(id, rgbToHsv(r, g, b));
116+
}
117+
118+
const blueGroup = ids.filter((id) => {
119+
const n = rawNames.get(id);
120+
return n === 'Blue' || n === 'Periwinkle';
121+
});
122+
123+
if (blueGroup.length >= 2) {
124+
// Least saturated => Periwinkle, most saturated => Blue
125+
blueGroup.sort((a, b) => (hsvById.get(a).s - hsvById.get(b).s) || (hsvById.get(b).v - hsvById.get(a).v));
126+
const perId = blueGroup[0];
127+
const blueId = blueGroup[blueGroup.length - 1];
128+
rawNames.set(perId, 'Periwinkle');
129+
rawNames.set(blueId, 'Blue');
130+
for (let i = 1; i < blueGroup.length - 1; i++) {
131+
const id = blueGroup[i];
132+
const { s } = hsvById.get(id);
133+
rawNames.set(id, s <= 0.55 ? 'Periwinkle' : 'Blue');
134+
}
135+
}
136+
137+
const greenGroup = ids.filter((id) => {
138+
const n = rawNames.get(id);
139+
return n === 'Green' || n === 'Lime';
140+
});
141+
142+
if (greenGroup.length >= 2) {
143+
// Brightest => Lime, darkest => Green
144+
greenGroup.sort((a, b) => (hsvById.get(b).v - hsvById.get(a).v) || (hsvById.get(a).h - hsvById.get(b).h));
145+
const limeId = greenGroup[0];
146+
const greenId = greenGroup[greenGroup.length - 1];
147+
rawNames.set(limeId, 'Lime');
148+
rawNames.set(greenId, 'Green');
149+
for (let i = 1; i < greenGroup.length - 1; i++) {
150+
const id = greenGroup[i];
151+
const { v } = hsvById.get(id);
152+
rawNames.set(id, v >= 0.6 ? 'Lime' : 'Green');
153+
}
154+
}
155+
108156
// ensure uniqueness: if duplicates, append numbers
109157
const counts = new Map();
110158
for (const id of ids) {

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<header>
1313
<h1>Water Sort Screenshot Solver (WASM)</h1>
1414
<p class="subtle">
15-
Client-side bottle parsing with OpenCV.js (WASM), then BFS solver.
15+
Client-side bottle parsing with OpenCV.js (WASM), then BFS solver. Code available on <a href="https://github.com/doublemover/WaterSortScreenshotSolver">Github</a>.
1616
</p>
1717
</header>
1818

0 commit comments

Comments
 (0)