The game

Given an   N×N   square array of zeroes or ones in an initial configuration,   and a target configuration of zeroes and ones.



The game is to transform one to the other in as few moves as possible by inverting whole numbered rows or whole lettered
columns at once   (as one move).

In an inversion.   any  1  becomes  0,   and any  0  becomes  1  for that whole row or column.



Task

Create a program to score for the Flipping bits game.

 The game should create an original random target configuration and a starting configuration.
 Ensure that the starting position is never the target position.
 The target position must be guaranteed as reachable from the starting position.   (One possible way to do this is to generate the start position by legal flips from a random target position.   The flips will always be reversible back to the target from the given start position).
 The number of moves taken so far should be shown.


Show an example of a short game here, on this page, for a   3×3   array of bits.




FlippingBits := module()
	export ModuleApply;
	local gameSetup, flip, printGrid, checkInput;
	local board;
 
	gameSetup := proc(n)
		local r, c, i, toFlip, target;
		randomize():
		target := Array( 1..n, 1..n, rand(0..1) );
		board := copy(target);
		for i to rand(3..9)() do
			toFlip := [0, 0];
			toFlip[1] := StringTools[Random](1, "rc");
			toFlip[2] := convert(rand(1..n)(), string);
			flip(toFlip);
		end do;
		return target;
	end proc;
 
	flip := proc(line)
		local i, lineNum;
		lineNum := parse(op(line[2..-1]));
		for i to upperbound(board)[1] do
			if line[1] = "R" then
				board[lineNum, i] := `if`(board[lineNum, i] = 0, 1, 0);
			else
				board[i, lineNum] := `if`(board[i, lineNum] = 0, 1, 0);
			end if;
		end do;
		return NULL;
	end proc;
 
	printGrid := proc(grid)
		local r, c;
		for r to upperbound(board)[1] do
			for c to upperbound(board)[1] do
				printf("%a ", grid[r, c]);
			end do;
			printf("\n");
		end do;
		printf("\n");
		return NULL;
	end proc;
 
	checkInput := proc(input)
		try
			if input[1] = "" then
				return false, "";
			elif not input[1] = "R" and not input[1] = "C" then
				return false, "Please start with 'r' or 'c'.";
			elif not type(parse(op(input[2..-1])), posint) then
				error;
			elif parse(op(input[2..-1])) < 1 or parse(op(input[2..-1])) > upperbound(board)[1] then
				return false, "Row or column number too large or too small.";
			end if;
		catch:
			return false, "Please indicate a row or column number."
		end try;
		return true, "";
	end proc;
 
	ModuleApply := proc(n)
		local gameOver, toFlip, target, answer, restart;
		restart := true;
		while restart do
			target := gameSetup(n);
			while ArrayTools[IsEqual](target, board) do
				target := gameSetup(n);
			end do;
			gameOver := false;
			while not gameOver do
				printf("The Target:\n");
				printGrid(target);
				printf("The Board:\n");
				printGrid(board);
				if ArrayTools[IsEqual](target, board) then
					printf("You win!! Press enter to play again or type END to quit.\n\n");
					answer := StringTools[UpperCase](readline());
					gameOver := true;
					if answer = "END" then
						restart := false
					end if;
				else
					toFlip := ["", ""];
					while not checkInput(toFlip)[1]  and not gameOver do
						ifelse (not op(checkInput(toFlip)[2..-1]) = "", printf("%s\n\n", op(checkInput(toFlip)[2..-1])), NULL);
						printf("Please enter a row or column to flip. (ex: r1 or c2) Press enter for a new game or type END to quit.\n\n");
						answer := StringTools[UpperCase](readline());
						if answer = "END" or answer = "" then
							gameOver := true;
							if answer = "END" then
								restart := false;
							end if;
						end if;
						toFlip := [substring(answer, 1), substring(answer, 2..-1)];
					end do;
					if not gameOver then
						flip(toFlip);
					end if;
				end if;
			end do;
		end do;
		printf("Game Over!\n");
	end proc;
end module:
 
FlippingBits(3);