# sudoku.msh

# (c) 2006 Adam Barr

# show the whole board

function show_board {
  foreach ($y in (0..8)) {
    foreach ($x in (0..8)) {
      write-host -nonewline $board[$y][$x]
      write-host -nonewline " "
    }
    write-host
  }
  write-host $(count_filled)
}

# count how many cells have a digit in them

function count_filled {
  $count = 0
  $board | foreach-object { $count += ($_ -like "[1-9]").Length }
  return $count
}

# initialize the board to empty

$board = @()

get-content -TotalCount 9 $args[0] |
  foreach-object {
    $arr = [char[]]$_
    if ($arr.Length -ne 9) {
      write-host "Invalid input" $arr
      exit
    }
    $board += ,$arr
  }

# board now is an array of 9 elements,
# each element is an array of 9 chars

$rawui = $host.ui.rawui

write-host
show_board
write-host

$curcoord = $rawui.CursorPosition

# fill $groups with the boxes, rows, and columns
# each entry in $groups will be an array of 9 elements,
# each element is an array with 2 elements, the y and x coordinates

foreach ($y in (0,3,6)) {
  foreach ($x in (0,3,6)) {
    $box = @()
    foreach ($y1 in (0..2)) {
      foreach ($x1 in (0..2)) {
        $box += ,(($y+$y1),($x+$x1))
      }
    }
    $groups += ,$box
  }
}

foreach ($b in (0..8)) {
  $row = @()
  $col = @()
  foreach ($a in (0..8)) {
    $row += ,($a,$b)
    $col += ,($b,$a)
  }
  $groups += ,$row
  $groups += ,$col
}


# now solve it

$last_count = count_filled

while (count_filled -lt 81) {

  foreach ($g in $groups) {
    foreach ($digit in (1..9)) {
      $d = [char][string]$digit
      $conflicts = new-object int[] 9
      $conflicts = (0..8) | foreach { $false }
      # fills in the $conflicts array for character $d in $g

:nloop
      foreach ($n in (0..8)) {

        $yx = $g[$n]

        # cell occupied?
        if ($board[$yx[0]][$yx[1]] -like "[1-9]") {
          $conflicts[$n] = $true
          continue nloop
        }

        # row conflict?
        foreach ($c in (0..8)) {
          if ($board[$yx[0]][$c] -eq $d) {
            $conflicts[$n] = $true
            continue nloop
          }
        }

        # column conflict?
        foreach ($r in (0..8)) {
          if ($board[$r][$yx[1]] -eq $d) {
            $conflicts[$n] = $true
            continue nloop
          }
        }

        # box conflict?
        $yfloor = $yx[0] - ($yx[0] % 3)
        $xfloor = $yx[1] - ($yx[1] % 3)
        foreach ($y in ($yfloor..($yfloor+2))) {
          foreach ($x in ($xfloor..($xfloor+2))) {
            if ($board[$y][$x] -eq $d) {
              $conflicts[$n] = $true
              continue nloop
            }
          }
        }

      }

      if (($conflicts -eq $false).Length -eq 1) {

        $index = [array]::IndexOf($conflicts,$false)
        $thisy = $g[$index][0]
        $thisx = $g[$index][1]

        $board[$thisy][$thisx] = $d

        $coord =
          new-object System.Management.Automation.Host.Coordinates `
            ($curcoord.X+($thisx*2)),($curcoord.Y+$thisy-11)
        $rawui.CursorPosition = $coord
        write-host $d
        $coord.X = $curcoord.X
        $coord.Y = $curcoord.Y - 2
        $rawui.CursorPosition = $coord
        write-host $(count_filled)

      }
    }
  }

  $new_count = count_filled
  if ($new_count -eq $last_count) {
    break;
  }
  $last_count = $new_count

}