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.




module FlipGame =
struct
  type t = bool array array
 
  let make side = Array.make_matrix side side false
 
  let flipcol b n =
    for i = 0 to (Array.length b - 1) do
      b.(n).(i) <- not b.(n).(i)
    done
 
  let fliprow b n =
    for i = 0 to (Array.length b - 1) do
      b.(i).(n) <- not b.(i).(n)
    done
 
  let randflip b =
    let n = Random.int (Array.length b - 1) in
    match Random.bool () with
    | true -> fliprow b n
    | false -> flipcol b n
 
  let rec game side steps =
    let start, target = make side, make side in
    for i = 1 to steps do
      randflip start;
      randflip target
    done;
    if start = target then game side steps (* try again *) else
      (start, target)
 
  let print b =
    for i = 0 to Array.length b - 1 do
      for j = 0 to Array.length b - 1 do
        Printf.printf " %d " (if b.(j).(i) then 1 else 0)
      done;
      print_newline ()
    done;
    print_newline ()
 
  let draw_game board target =
    print_endline "TARGET"; print target;
    print_endline "BOARD"; print board
end
 
let play () =
  let module G = FlipGame in
  let board, target = G.game 3 10 in
  let steps = ref 0 in
  while board <> target do
    G.draw_game board target;
    print_string "> ";
    flush stdout;
    incr steps;
    match String.split_on_char ' ' (read_line ()) with
    | ["row"; row] ->
      (match int_of_string_opt row with
       | Some n -> G.fliprow board n
       | None -> print_endline "(nothing happens)")
    | ["col"; col] ->
      (match int_of_string_opt col with
       | Some n -> G.flipcol board n
       | None -> print_endline "(nothing happens)")
    | _ -> ()
  done;
  G.draw_game board target;
  Printf.printf "\n\nGame solved in %d steps\n" !steps
 
let () =
  if not !Sys.interactive then
    (Random.self_init ();
      play ())