Sink or Swim

Description

You will be given a list of lines that look like this:

### <   >    ### <<>><  ##

The characters mean the following:

  • < are rocks that sink left
  • > are bubbles that float right. Cannot pass rocks.
  • # are walls
  • is water (empty space)

Rocks can not pass bubbles, if a bubble is trapped next to a rock, the rock will always push the bubble down regardless of the number of bubbles.

Output the final state of the water column.

In this case, that would be ###< >###<<>>< ##

You may assume no bubbles or rocks can escape.

A few more examples:

  • #<> # becomes #< >#
  • # >< # becomes #>< #
  • # >>>>>>>>>< becomes #>>>>>>>><

Judge

(async function*(context: Context): Challenge {
	const fixedTestCases: string[] = [
		'    #    <',
		'>   #     ',
		'#<<<<',
		'           ',
		'   #   ',
	];

	const randomTestCases = [];

	function randomString(chars: string, length: number): string {
		let string = '';

		for (let i=0; i<length; i++) {
			string += chars[Math.floor(Math.random() * chars.length)]
		}

		return string;
	}

	for (let i=0; i<100; i++) {
		randomTestCases.push(
			randomString('   >', Math.floor(Math.random() * Math.random() * 10)) +
			'#' + 
			randomString('         >><<#', Math.floor(Math.random() * Math.random() * 100)) +
			'#' +
			randomString('   <', Math.floor(Math.random() * Math.random() * 10))
		)
	}

	function sinkOrSwim(value: string): string {
		let previousValue = value;
		while (true) {
			value = value.replace(/( +)(>*<+)/g, '$2$1')
				.replace(/(>+)( +)/g, '$2$1');
			if (value == previousValue) {
				return value
			} else {
				previousValue = value;
			}
		}
	}
	
	// Automatically shuffle and deal test cases over multiple runs
	yield* context.runTestCases(
		[...fixedTestCases, ...randomTestCases].map(
			i=>[i,sinkOrSwim(i)] as [string, string]
		)
	);
	
	// Finally, the challenge is passed if no test cases failed
	return context.noFailures();
})

Example Code


	function sinkOrSwim(value) {
		let previousValue = value;
		while (true) {
			value = value.replace(/( +)(>*<+)/g, '$2$1')
				.replace(/(>+)( +)/g, '$2$1');
			if (value == previousValue) {
				return value
			} else {
				previousValue = value;
			}
		}
	}

process.stdin.on('data',
	i=>console.log(sinkOrSwim(''+i))
)

Comments