Maze Generator
Description
Output 200 unique 8x8 mazes. Use # characters to mark the walls. There must be exactly one route between every two cells.
A valid maze looks like this:
################# # # # # # # # # # # # # # # # # # # # # # # # ### # # # # # # # # # # # # # ### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #################
Each maze must be separated by a double line break. Trailing spaces are ignored.
Judge
(async function*(context: Context): Challenge { // Single Test const run = await context.run(undefined); const mazes = run.text.split('\n\n'); const gridSize = 8; const set = new Set(); const nonUniqueMazes: string[] = []; const invalidMazes: string[] = []; const multiPathMazes: string[] = []; const disconnectedMazes: string[] = []; function printFailures(name: string, list: string[]): TestCase { if (list.length == 0) { return new TestCase(name, "Pass", {"Text": "passes"}) } else { return new TestCase( name, "Fail", { "Text": `${list.length} tests failed "${name}"\n${list.slice(0,5).join("\n\n")}\n${list.length > 5 ? `And ${list.length - 5} more`:''}` } ) } } for (let maze of mazes) { maze = maze.trimRight().replace(/\s*\n/g,'\n'); if (set.has(maze)) { nonUniqueMazes.push(maze); } set.add(maze); // /^#{21}(\n#(( (#| )){9} #)\n(#( |#)){10}#){9}\n# (( |#) ){9}#\n#{21}$/ if (!maze.match(new RegExp(`^#{${gridSize * 2 + 1}}(\n#(( (#| )){${gridSize-1}} #)\n(#( |#)){${gridSize}}#){${gridSize-1}}\n# (( |#) ){${gridSize-1}}#\n#{${gridSize * 2 + 1}}$`))) { invalidMazes.push(maze); } const pairs = new Array(gridSize * gridSize).fill(0).map((i,j)=>j); function formatMazeWithGroupsMarked(maze: string, edge: number | undefined, group_filter: (i: number)=>boolean) :string { return [...maze].map( (i,j)=>{ if (j==edge) { return '!'; } let global_x = j%(gridSize * 2 + 2); let global_y = Math.floor(j/(gridSize * 2 + 2)); if (global_x % 2 != 1 || global_y % 2 != 1 || global_x == gridSize * 2 + 1) { return i; } let x = (global_x-1)/2; let y = (global_y-1)/2; return group_filter(pairs[x+gridSize*y])?'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ--'[Math.min(pairs[x+gridSize*y],35 + 26 + 1)]:' ' } ).join('') } let valid = true; let linkPairs = (x1:number,y1:number,x2:number,y2:number,edge:number) => { let g1 = pairs[x1+y1*gridSize]; let g2 = pairs[x2+y2*gridSize]; [g1,g2] = [Math.min(g1,g2),Math.max(g1,g2)]; if (g1 === g2) { multiPathMazes.push(formatMazeWithGroupsMarked(maze, edge, i=>i==g1 || i==g2)); valid = false; return; } for (let i=0; i<gridSize * gridSize; i++) { if (pairs[i] == g2) { pairs[i] = g1 } } } for (let x=0; x<gridSize && valid; x++) { for (let y=0; y<gridSize && valid; y++) { // let horizontal_edge_index = 22 + 2 * x + 44 * y + 2; // let vertical_edge_index = 22 + 2 * x + 44 * y + 23; const rowLength = gridSize * 2 + 2; let horizontal_edge_index = rowLength + 2 * x + rowLength * 2 * y + 2; let vertical_edge_index = rowLength + 2 * x + rowLength * 2 * y + rowLength + 1; //let horizontal_edge_index = 22 + 2 * x + 44 * y + 2; //let vertical_edge_index = 22 + 2 * x + 44 * y + 23; let horizontal_edge = maze[horizontal_edge_index] == ' '; let vertical_edge = maze[vertical_edge_index] == ' '; if (horizontal_edge) { linkPairs(x,y,x+1,y, horizontal_edge_index); } if (vertical_edge) { linkPairs(x,y,x,y+1, vertical_edge_index); } } } for (let i=0; i<gridSize * gridSize; i++) { if (pairs[i]!=0) { disconnectedMazes.push(formatMazeWithGroupsMarked(maze, undefined, i=>i>0)); break; } } } yield context.registerTestCase(printFailures('All mazes must be unique', nonUniqueMazes)); yield context.registerTestCase(printFailures('Invalid Mazes', invalidMazes)); yield context.registerTestCase(printFailures('Mazes with multiple paths', multiPathMazes)); yield context.registerTestCase(printFailures('Disconnected mazes', disconnectedMazes)); yield context.registerTestCase( new TestCase( '200 mazes', mazes.length == 200 ? 'Pass': 'Fail', { 'Text': 'Expected 200 mazes, got '+mazes.length } ) ) return context.noFailures(); })
Example Code
let base_index = 0; const gridSize = 8; console.log(new Array(200).fill(` ################# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #################`.substring(1)).map( (maze,index)=>{ if (index==0) {return maze} let gridSizePowerFour = (gridSize - 1) * (gridSize - 1) * (gridSize - 1) * (gridSize - 1); let index_pairs = [base_index%gridSizePowerFour,Math.floor(base_index/gridSizePowerFour)]; while (index_pairs[0] >= index_pairs[1]) { base_index+=1; index_pairs = [base_index%gridSizePowerFour,Math.floor(base_index/gridSizePowerFour)]; } const val = [...maze].map( (char,b)=>{ for (let pair of index_pairs) { let x = pair % (gridSize - 1); let y = Math.floor(pair / (gridSize - 1)); const rowLength = gridSize * 2 + 2; let horizontal_edge = rowLength + 2 * x + rowLength * 2 * (y + 1) + 2; let vertical_edge = rowLength + 2 * x + rowLength * 2 * y + rowLength + 1; if (b == horizontal_edge) { return ' '; } if (b == vertical_edge) { return '#'; } } return char; }).join(''); base_index+=1; return val; }).join('\n\n'))
Suggestion to edit judge