CP-SAT - Magic Square
Problem: fill a square grid with distinct numbers so every row, column, and diagonal has the same sum.
Show code
import { CpSat, setWorkerBridgeEnabled, type SatParameters } from 'or-tools-wasm/cp-sat';
type MagicSquareExpr = {
vars: number[];
coeffs: number[];
offset: number;
};
type MagicSquareModel = {
name: string;
variables: Array<{ name: string; domain: number[] }>;
constraints: Array<
| { name: string; all_diff: { exprs: MagicSquareExpr[] } }
| { name: string; linear: { vars: number[]; coeffs: number[]; domain: number[] } }
>;
};
function buildMagicSquareModel(size: number): MagicSquareModel {
const numCells = size * size;
const variables: MagicSquareModel['variables'] = [];
const domain: [number, number] = [1, numCells];
for (let row = 0; row < size; ++row) {
for (let col = 0; col < size; ++col) {
variables.push({ name: `cell_${row}_${col}`, domain: [...domain] });
}
}
const constraints: MagicSquareModel['constraints'] = [];
constraints.push({
name: 'all_diff',
all_diff: {
exprs: Array.from({ length: numCells }, (_, index) => ({
vars: [index],
coeffs: [1],
offset: 0,
})),
},
});
const target = (size * (size * size + 1)) / 2;
const addSum = (name: string, vars: number[]) => {
constraints.push({
name,
linear: { vars, coeffs: Array(vars.length).fill(1), domain: [target, target] },
});
};
for (let row = 0; row < size; ++row) {
addSum(`row_${row}`, Array.from({ length: size }, (_, col) => row * size + col));
}
for (let col = 0; col < size; ++col) {
addSum(`col_${col}`, Array.from({ length: size }, (_, row) => row * size + col));
}
addSum('diag_main', Array.from({ length: size }, (_, index) => index * size + index));
addSum('diag_anti', Array.from({ length: size }, (_, index) => index * size + (size - 1 - index)));
return { name: `magic_square_${size}`, variables, constraints };
}
setWorkerBridgeEnabled(true);
const size = 5;
const model = await CpSat.createModel(buildMagicSquareModel(size));
const validation = await CpSat.validate(model);
if (!validation.ok) throw new Error(validation.message);
const workers = 4;
const params: SatParameters = { numWorkers: workers, logSearchProgress: true };
const result = await CpSat.solve(model, params);
console.log(result.response?.solution);
This page exercises the cp_sat_api
WASM module by building and solving a magic square model directly in the browser.
Model
- Each grid cell is an integer decision variable.
- All numbers in the square must be distinct.
- Every row, column, and diagonal must have the same magic sum.
- CP-SAT searches for a grid assignment satisfying all arithmetic constraints.
Latest solution:
Run the solver to view a magic square.
Status / Response: