-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolve.ts
More file actions
63 lines (55 loc) · 1.73 KB
/
solve.ts
File metadata and controls
63 lines (55 loc) · 1.73 KB
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
import {NextApiRequest, NextApiResponse} from 'next';
import {OpviousClient} from 'opvious';
import {Schema} from 'opvious/api';
import events from 'events';
/**
* Opvious API client, authenticated automatically using the OPVIOUS_TOKEN
* environment variable.
*/
const client = OpviousClient.create();
/** Standard Next.js API handler */
export default async function FixGridHandler(
req: NextApiRequest,
res: NextApiResponse
): Promise<void> {
const grid = req.body.grid;
if (!grid) {
res.status(400).send({error: 'Missing input grid'});
return;
}
const tracker = client.runSolve({
problem: {
formulation: {name: 'sudoku'},
inputs: {parameters: [gridToTensor(grid)]},
transformations: [{kind: 'relaxConstraint', label: 'outputMatchesInput'}],
},
});
const [outcome, output] = await events.once(tracker, 'solved');
res.status(200).json({
grid: gridFromTensor(output.variables),
mistakeCount: Math.round(outcome.objectiveValue),
});
}
// Parsing logic for a simple grid representation
type Grid = ReadonlyArray<string>;
function gridToTensor(grid: Grid): Schema<'Tensor'> {
const entries: Schema<'TensorEntry'>[] = [];
for (const [i, row] of grid.entries()) {
for (const [j, c] of [...row].entries()) {
const v = +c;
if (!isNaN(v)) {
entries.push({key: [i, j, v]});
}
}
}
return {label: 'input', entries};
}
function gridFromTensor(tensors: ReadonlyArray<Schema<'Tensor'>>): Grid {
const tensor = tensors.find((t) => t.label === 'output')!;
const rows = Array.from({length: 9}, () => Array.from({length: 9}));
for (const entry of tensor.entries) {
const [i, j, v] = entry.key;
rows[+i][+j] = +v;
}
return rows.map((r) => r.join(''));
}