Fairy Knight Moves

Description

Given a knight move (long axis distance, short axis distance), output how many steps it would take to each each position on a standard 8 by 8 chess board, starting at the top left corner.

For example, if the input is 2,1 you might output:

 0  3  2  3  2  3  4  5
 3  4  1  2  3  4  3  4
 2  1  4  3  2  3  4  5
 3  2  3  2  3  4  3  4
 2  3  2  3  4  3  4  5
 3  4  3  4  3  4  5  4
 4  3  4  3  4  5  4  5
 5  4  5  4  5  4  5  6

Each number is padded to two digits with a space, and there is a space between each cell. If a tile is entirely unreachable, print --. For example, if the input was 1,1 you would output:

 0 --  2 --  4 --  6 --
--  1 --  3 --  5 --  7
 2 --  2 --  4 --  6 --
--  3 --  3 --  5 --  7
 4 --  4 --  4 --  6 --
--  5 --  5 --  5 --  7
 6 --  6 --  6 --  6 --
--  7 --  7 --  7 --  7

There is one input in each line, separate each output with a blank line.

Judge

(async function*(context: Context): Challenge {
	function edges(start: number, dx: number, dy: number): number | undefined {
		let x=start % 8;
		let y=Math.floor(start / 8);
		if (x + dx >= 0 && x + dx < 8 && y + dy>=0 && y + dy < 8) {
			return (x+dx)+(y+dy)*8
		}
	}
	
	function solve(a: number,b: number): number[] {
		let g = new Array(64).fill(-1);
		let l = [0];
		g[0]=0
		for (let i=1; i<32; i++) {
			let new_l = [];
			for (const edge of l) {
				for (const new_edge of [
					edges(edge, a, b),
					edges(edge, a, -b),
					edges(edge, -a, b),
					edges(edge, -a, -b),
					edges(edge, b, a),
					edges(edge, b, -a),
					edges(edge, -b, a),
					edges(edge, -b, -a)
				]) {
					if (new_edge && g[new_edge] == -1) {
						new_l.push(new_edge);
						g[new_edge] = i;
					}
				}
			}
			l = new_l
		}
		return g
	}

	function format(input: number[]): string {
		let o = ''
		let i = 0;
		for (const v of input) {
			if (v==-1) {
				o+='--'
			} else {
				if (v<10) {
					o+=' '
				}
				o+=v
			}
			o += i%8 == 7 ? '\n' : ' ';
			i+=1;
		}
		return o.trimEnd()
	}

	// Automatically shuffle and deal test cases over multiple runs
	yield* context.runTestCases(
		([
			[1,0],
			[1,1],
			[2,0],
			[2,1],
			[2,2],
			[3,0],
			[3,1],
			[3,2],
			[3,3],
			[4,1],
			[4,3],
			[5,1],
			[5,2],
			[6,1],
			[7,2],
			[7,1],
			[8,2],
		] as [number, number][]).map(
			([a,b]): [string, string] => [`${a},${b}`, format(solve(a,b))]
		),
		{
			outputSeparator: '\n\n',
			inputSeparator: '\n',
			compareFunction: (a: string, b: string) => a.replace(/([\n ]|^) /g, '$1') == b.replace(/([\n ]|^) /g, '$1'),
		}
	);
	// Finally, the challenge is passed if no test cases failed
	return context.noFailures();
})

Example Code

function edges(start, dx, dy) {
	let x=start % 8;
	let y=Math.floor(start / 8);
	if (x + dx >=0 && x + dx < 8 && y + dy >= 0 && y + dy < 8) {
		return (x+dx)+(y+dy)*8
	}
}

function solve(a,b) {
	let g = new Array(64).fill(-1);
	let l = [0];
	g[0]=0
	for (let i=1; i<32; i++) {
		let new_l = [];
		for (const edge of l) {
			for (const new_edge of [
				edges(edge, a, b),
				edges(edge, a, -b),
				edges(edge, -a, b),
				edges(edge, -a, -b),
				edges(edge, b, a),
				edges(edge, b, -a),
				edges(edge, -b, a),
				edges(edge, -b, -a)
			]) {
				if (new_edge && g[new_edge] == -1) {
					new_l.push(new_edge);
					g[new_edge] = i;
				}
			}
		}
		l = new_l
	}
	return g
}

function format(input) {
	let o = ''
	let i = 0;
	for (const v of input) {
		if (v<0) {
			o+='--'
		} else {
			if (v<7) {
				o+=' '
			}
			o+=v
		}
		o += i%8 == 7 ? '\n' : ' '

		i++;
	}
	return o
}

process.stdin.on('data', e=>(''+e).split('\n').map(i=>{const [a,b]=i.split(',').map(i=>+i); console.log(format(solve(a,b)))}))

Comments