Skip to content

Commit f50891a

Browse files
v1.61
### Version: Exolve v1.61: February 22, 2025 - Allow parameters in cell-decorators, so that we can vary a decorator depending upon which cell it is in. The mechanism is to allow `$1`, `$2`, etc. to be present anywhere in the SVG specs for a decorator. In the `exolve-grid` section, when a decorator is placed in a cell, values are supplied for the parameters, using colon-prefixed suffixes. E.g.: ``` exolve-cell-decorator: <text x="2" y="15" style="color:$1">$2</text> exolve-grid: 0{1:green:*} . ... ``` - Spaces get stripped from parameter values. Parameter values cannot contain any of `:` or ','. - If the dollar symbol itself is needed in the SVG specs, it needs to be indicated using `$0`. - Bug fix: `addCellText()` was using the next cell to compute some coordinates, but this doesn't work with non-standard grid-spacing. Fixed. Also updated the documentation to say that parameterized `exolve-cell-decorator` is the preferred way to add text decorations to cells. - exolve-from-text.js: Found published grids in the wild that contain the 2x2-all-white-cells pattern that I was rejecting outright. Modify the algo to first try with such 2x2s ruled out, but if that fails, then try everything again, allowing the 2x2. Also relax maxToBlacken to 6 from 5. Finally, add a sorter to sort the results if there are multiple results, using some heuristics (loweset num-unchecked-pairs + max-horiz-black-span + max-vert-black-span + num2x2Whiteo). - In exolve-player.html, delete old Exolve puzzles for multiple-matching choices inferred from text. - Add a test for autogrid that contains a 2x2-all-white block.
1 parent 3548ea2 commit f50891a

14 files changed

+354
-72
lines changed

CHANGELOG.md

+31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
### Version: Exolve v1.61: February 22, 2025
4+
5+
- Allow parameters in cell-decorators, so that we can vary a decorator
6+
depending upon which cell it is in. The mechanism is to allow `$1`,
7+
`$2`, etc. to be present anywhere in the SVG specs for a decorator. In
8+
the `exolve-grid` section, when a decorator is placed in a cell, values
9+
are supplied for the parameters, using colon-prefixed suffixes. E.g.:
10+
```
11+
exolve-cell-decorator: <text x="2" y="15" style="color:$1">$2</text>
12+
exolve-grid:
13+
0{1:green:*} . ...
14+
```
15+
- Spaces get stripped from parameter values. Parameter values cannot
16+
contain any of `:` or ','.
17+
- If the dollar symbol itself is needed in the SVG specs, it needs to be
18+
indicated using `$0`.
19+
- Bug fix: `addCellText()` was using the next cell to compute some
20+
coordinates, but this doesn't work with non-standard grid-spacing. Fixed.
21+
Also updated the documentation to say that parameterized
22+
`exolve-cell-decorator` is the preferred way to add text decorations to cells.
23+
- exolve-from-text.js: Found published grids in the wild that contain
24+
the 2x2-all-white-cells pattern that I was rejecting outright. Modify
25+
the algo to first try with such 2x2s ruled out, but if that fails, then
26+
try everything again, allowing the 2x2. Also relax maxToBlacken to 6
27+
from 5. Finally, add a sorter to sort the results if there are multiple
28+
results, using some heuristics (loweset num-unchecked-pairs +
29+
max-horiz-black-span + max-vert-black-span + num2x2Whiteo).
30+
- In exolve-player.html, delete old Exolve puzzles for multiple-matching
31+
choices inferred from text.
32+
- Add a test for autogrid that contains a 2x2-all-white block.
33+
334
### Version: Exolve v1.60: February 18, 2025
435

536
- Add support for non-standard cell shapes via `exolve-shaped-cell`, which

README.md

+26-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## An Easily Configurable Interactive Crossword Solver
44

5-
### Version: Exolve v1.60 February 18, 2025
5+
### Version: Exolve v1.61 February 22, 2025
66

77
Exolve can help you create online interactively solvable crosswords (simple
88
ones with blocks and/or bars as well as those that are jumbles or are
@@ -2072,6 +2072,25 @@ adjoining cells (otherwise the overlap will get hidden). See the long green
20722072
vertical lines in the example in
20732073
[`test-cell-decorators.html`](test-cell-decorators.html).
20742074

2075+
You can also add cell-specific parameters to cell decorators. Basically, you
2076+
can use markers like `$1` (`$2`, etc.) anywhere in the `exolve-cell-decorator`
2077+
specs. And then, in the `exolve-grid` entry for a cell that's decorated with
2078+
a parameterized decorator, you can specify values for the parameters by
2079+
appending the decorator number with `:val` (or `:val1:val2` if there are
2080+
multiple parameters). The only constraint is that the parameters cannot include
2081+
spaces (as all spaces get stripped off when parsing lines within `exolve-grid`)
2082+
and cannot include colons or commas. If you need to have the dollar symbol
2083+
itself within a decorator, then use `$0`. Here's an example:
2084+
2085+
```
2086+
exolve-cell-decorator: <line stroke="$1" x1="20" y1="28" x2="26" y2="28">
2087+
exolve-cell-decorator: <text x="5" y="14.1">$1$0</text>
2088+
exolve-grid:
2089+
0 0 0 0{2:42}
2090+
0 . . 0{2:!!}
2091+
0{1:red} 0{1:blue} 0{1:red} 0{1:blue,2:*}
2092+
```
2093+
20752094
## `exolve-postscript`
20762095
If this section is provided, it gets rendered under the whole puzzle. Like
20772096
`exolve-preamble`, this is also a multiline section and can include arbitrary
@@ -2515,6 +2534,10 @@ all HTML IDs and class names were made distinctive by having them use the
25152534
making future backwards-incompatible changes unnecessary.
25162535

25172536
### Customized additional text within cells
2537+
NOTE: A more general mechanism than `addCellText()` (with greater flexibility,
2538+
control) for adding text to cells is now available via
2539+
[`exolve-cell-decorator`](#exolve-cell-decorator) with parameters.
2540+
25182541
Exolve provides you with a JavaScript API that you can call from
25192542
`customizeExolve()` that lets you add arbitrary text within any cell. The
25202543
function to call is:
@@ -2622,7 +2645,6 @@ after the Solutions section.
26222645
This "grid inference" functionality is only supported for standard, blocked,
26232646
UK-style crossword grids. Here are the constraints under which this works:
26242647
- The grid is symmetric
2625-
- Every 4x4 area has at least one black cell.
26262648
- No light is shorter than 3 letters.
26272649
- Enums are provided for all clues. The only exception is child clues
26282650
in linked groups.
@@ -2632,6 +2654,8 @@ UK-style crossword grids. Here are the constraints under which this works:
26322654
entry is supported (compared to the number of linked clues).
26332655
- There aren't very long strips of consecutive blackened squares.
26342656
2657+
We first look for the coomon case where every 4x4 area has at least one black
2658+
cell. If that fails, then we re-try, without this constraint.
26352659
26362660
### .pdf
26372661
While it is tempting to add support for reading crosswords out of PDFs, it is

exolve-from-ipuz.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ SOFTWARE.
2424
The latest code and documentation for Exolve can be found at:
2525
https://github.com/viresh-ratnakar/exolve
2626
27-
Version: Exolve v1.60 February 18, 2025
27+
Version: Exolve v1.61 February 22, 2025
2828
*/
2929

3030
/**

exolve-from-puz.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ SOFTWARE.
2424
The latest code and documentation for Exolve can be found at:
2525
https://github.com/viresh-ratnakar/exolve
2626
27-
Version: Exolve v1.60 February 18, 2025
27+
Version: Exolve v1.61 February 22, 2025
2828
*/
2929

3030
function exolveFromPuzNextNull(buffer, offset) {

exolve-from-text.js

+77-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ SOFTWARE.
2424
The latest code and documentation for Exolve can be found at:
2525
https://github.com/viresh-ratnakar/exolve
2626
27-
Version: Exolve v1.60 February 18, 2025
27+
Version: Exolve v1.61 February 22, 2025
2828
*/
2929

3030
/**
@@ -300,6 +300,7 @@ function ExolveGridSkeleton(puz, specs) {
300300
this.specs = specs;
301301
this.w = puz.gridWidth;
302302
this.h = puz.gridHeight;
303+
this.no4x4 = true;
303304
this.grid = new Array(this.h);
304305
for (let r = 0; r < this.h; r++) {
305306
this.grid[r] = new Array(this.w);
@@ -316,6 +317,7 @@ ExolveGridSkeleton.prototype.clone = function(newLights=false) {
316317
copy.parents = this.parents;
317318
copy.name = this.name;
318319
copy.symName = this.symName;
320+
copy.no4x4 = this.no4x4;
319321

320322
copy.grid = new Array(this.h);
321323
for (let r = 0; r < this.h; r++) {
@@ -681,7 +683,7 @@ ${sections.preamble}`;
681683

682684
for (let rowpar = 0; rowpar < 2; rowpar++) {
683685
for (let colpar = 0; colpar < 2; colpar++) {
684-
for (let skeleton of skeletons) {
686+
for (const skeleton of skeletons) {
685687
const candidate = skeleton.clone();
686688
for (let r = 0; r < h; r++) {
687689
for (let c = 0; c < w; c++) {
@@ -695,11 +697,21 @@ ${sections.preamble}`;
695697
}
696698
}
697699
}
698-
for (let skeleton of skeletons) {
700+
for (const skeleton of skeletons) {
699701
const candidate = skeleton.clone();
700702
candidate.name = 'Non-chequered';
701703
candidate.appendWithSyms(ret.candidates);
702704
}
705+
/**
706+
* no4x4 determines whether (in an unchequered skeleton), we allow
707+
* blocks of 2x2 white cells (false is tried as a last resort).
708+
*/
709+
for (const skeleton of skeletons) {
710+
const candidate = skeleton.clone();
711+
candidate.no4x4 = false;
712+
candidate.name = 'Non-chequered-2x2-white-OK';
713+
candidate.appendWithSyms(ret.candidates);
714+
}
703715
return ret;
704716
}
705717

@@ -725,20 +737,21 @@ exolveFromTextCreateWorker = function(candidates) {
725737
return;
726738
}
727739
const results = [];
728-
for (let skeleton of candidates) {
740+
for (const skeleton of candidates) {
729741
const candidate = new ExolveGridInferrer(skeleton);
730742
candidate.infer(results);
731743
if (results.length > 0) {
732744
break;
733745
}
734746
}
735747
const seen = {};
748+
results.sort((r1, r2) => r1.score() - r2.score());
736749
const deduped = [];
737-
for (let result of results) {
738-
const gridSpecLines = result.gridSpecLines;
750+
for (const result of results) {
751+
const gridSpecLines = result.gridSpecLines();
739752
if (seen[gridSpecLines]) continue;
740753
seen[gridSpecLines] = true;
741-
deduped.push(result);
754+
deduped.push({gridSpecLines: gridSpecLines, exolve: result.exolve()});
742755
}
743756
postMessage({results: deduped});
744757
}
@@ -795,6 +808,7 @@ function ExolveGridInferrer(skeleton) {
795808
this.w = skeleton.w;
796809
this.h = skeleton.h;
797810
this.specs = skeleton.specs;
811+
this.no4x4 = skeleton.no4x4;
798812
/* The 'cursor': the next light will be placed at a cell here onwards */
799813
this.rowcol = new ExolveRowCol(this.h, this.w);
800814

@@ -951,7 +965,7 @@ ExolveGridInferrer.prototype.setGrid = function(rc, letter) {
951965
}
952966
this.grid[rc.row][rc.col] = letter;
953967
this.grid[sym.row][sym.col] = letter;
954-
if (letter == '0') {
968+
if (letter == '0' && this.no4x4) {
955969
const mustBlock = this.threeZerosAll(rc);
956970
for (let rc2 of mustBlock) {
957971
if (!this.setGrid(rc2, '.')) {
@@ -1092,15 +1106,15 @@ ExolveGridInferrer.prototype.infer = function(results) {
10921106
if (!this.isViable(true)) {
10931107
return;
10941108
}
1095-
results.push({gridSpecLines: this.gridSpecLines(), exolve: this.exolve()});
1109+
results.push(this);
10961110
return;
10971111
}
10981112
const lights = this.lights[this.mapped.length];
10991113
const rowcolStart = this.rowcol.clone();
11001114
let numUnsetCellsSet = 0;
11011115

11021116
/* Only consider blackening up to these many cells */
1103-
const maxToBlacken = 5;
1117+
const maxToBlacken = 6;
11041118
while (this.rowcol.isValid() && numUnsetCellsSet <= maxToBlacken) {
11051119
const gridCell = this.grid[this.rowcol.row][this.rowcol.col];
11061120
if (gridCell == '_') {
@@ -1132,6 +1146,59 @@ ExolveGridInferrer.prototype.infer = function(results) {
11321146
}
11331147
}
11341148

1149+
ExolveGridInferrer.prototype.score = function() {
1150+
let numUnches = 0;
1151+
let num4x4 = 0;
1152+
let maxRowBlack = 0;
1153+
let maxColBlack = 0;
1154+
for (let r = 0; r < this.h; r++) {
1155+
for (let c = 0; c < this.w; c++) {
1156+
if (this.grid[r][c] != '0') continue;
1157+
if ((c < this.w - 1 && this.grid[r][c + 1] == '0') &&
1158+
(r == 0 || this.grid[r - 1][c] == '.') &&
1159+
(r == 0 || this.grid[r - 1][c + 1] == '.') &&
1160+
(r == this.h - 1 || this.grid[r + 1][c] == '.') &&
1161+
(r == this.h - 1 || this.grid[r + 1][c + 1] == '.')) {
1162+
numUnches++;
1163+
}
1164+
if ((r < this.h - 1 && this.grid[r + 1][c] == '0') &&
1165+
(c == 0 || this.grid[r][c - 1] == '.') &&
1166+
(c == 0 || this.grid[r + 1][c - 1] == '.') &&
1167+
(c == this.w - 1 || this.grid[r][c + 1] == '.') &&
1168+
(c == this.w - 1 || this.grid[r + 1][c + 1] == '.')) {
1169+
numUnches++;
1170+
}
1171+
if (r < this.h - 1 && c < this.w - 1 &&
1172+
this.grid[r+1][c] == '0' &&
1173+
this.grid[r][c+1] == '0' &&
1174+
this.grid[r+1][c+1] == '0') {
1175+
num4x4++;
1176+
}
1177+
/* horiz black span ending before this: */
1178+
let span = 0;
1179+
for (let c2 = c - 1; c2 >= 0; c2--) {
1180+
if (this.grid[r][c2] == '.') {
1181+
span++;
1182+
} else {
1183+
break;
1184+
}
1185+
}
1186+
if (span > maxRowBlack) maxRowBlack = span;
1187+
/* vert black span ending before this: */
1188+
span = 0;
1189+
for (let r2 = r - 1; r2 >= 0; r2--) {
1190+
if (this.grid[r2][c] == '.') {
1191+
span++;
1192+
} else {
1193+
break;
1194+
}
1195+
}
1196+
if (span > maxColBlack) maxColBlack = span;
1197+
}
1198+
}
1199+
return numUnches + num4x4 + maxRowBlack + maxColBlack;
1200+
}
1201+
11351202
ExolveGridInferrer.prototype.isConnected = function() {
11361203
let cells = []
11371204
let visited = new Array(this.h)

exolve-m-simple.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
1515
See the full Exolve license notice in exolve-m.js.
1616
17-
Version: Exolve v1.60 February 18, 2025
17+
Version: Exolve v1.61 February 22, 2025
1818
-->
1919

20-
<link rel="stylesheet" type="text/css" href="https://viresh-ratnakar.github.io/exolve-m.css?v1.60"/>
21-
<script src="https://viresh-ratnakar.github.io/exolve-m.js?v1.60"></script>
20+
<link rel="stylesheet" type="text/css" href="https://viresh-ratnakar.github.io/exolve-m.css?v1.61"/>
21+
<script src="https://viresh-ratnakar.github.io/exolve-m.js?v1.61"></script>
2222

2323
<title>Your Puzzle Title</title>
2424

exolve-m.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Copyright (c) 2019 Viresh Ratnakar
55
66
See the full license notice in exolve-m.js.
77
8-
Version: Exolve v1.60 February 18, 2025
8+
Version: Exolve v1.61 February 22, 2025
99
*/
1010

1111
@media (max-width: 500px) {

exolve-m.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
1111
See the full Exolve license notice in exolve-m.js.
1212
13-
Version: Exolve v1.60 February 18, 2025
13+
Version: Exolve v1.61 February 22, 2025
1414
-->
15-
<link rel="stylesheet" type="text/css" href="exolve-m.css?v1.60"/>
16-
<script src="exolve-m.js?v1.60"></script>
15+
<link rel="stylesheet" type="text/css" href="exolve-m.css?v1.61"/>
16+
<script src="exolve-m.js?v1.61"></script>
1717

1818
<title>Exolve (replace with puzzle title)</title>
1919

0 commit comments

Comments
 (0)