! 8 - Reinas
  ! Resuelve el problema de colocar 8 reinas en un
  ! tablero de ajedrez sin que ninguna de ellas esté
  ! en jaque.
  !
  ! jbgarcia@uvigo.es

  object Resolutor8Reinas

    attribute - vReinas = Nothing

    method + setTablero ( v )
      vReinas = v

      return
    endMethod

    method + abs ( x )
      x.isLessThan ( 0 )
      jumpOnFalseTo fin
      x = x.multiplyBy ( -1 )

      :fin
      return x
    endMethod

    method + estaBienPuesta ( reina )
      reference i = 0
      reference aux = 0
      reference aux2 = 0
      reference toret = False

      reina.isEqualTo ( 0 )
      jumpOnFalseTo Loop
      toret = True
      jumpOnTrueTo fin

      :Loop
      ! Primera comparación v[i] == v[j]
      aux = vReinas.get ( i )
      aux2 = vReinas.get ( reina )
      aux.isEqualTo ( aux2 )
      jumpOnTrueTo fin

      ! Primer lado de la comparación i-j
      aux = reina.substract ( i )
      aux = __this.abs ( aux )

      ! Segundo lado de la comparación v[i]-v[j]
      aux2 = vReinas.get ( reina )
      aux2 = aux2.substract ( vReinas.get ( i ) )
      aux2 = __this.abs ( aux2 )

      ! Segunda comparación |i-j| == |v[i]-v[j]|
      aux2.isEqualTo ( aux )
      jumpOnTrueTo fin

      ! Incrementar
      i = i.sum ( 1 )
      i.isLessThan ( reina )
      jumpOnTrueTo Loop

      toret = True

      :fin
      return toret
    endMethod

    method + resuelve ( lin )
      reference col = 0
      reference max = vReinas.size ( )
      reference toret = False

      max = max.substract ( 1 )

      :Loop
      ! Poner la reina en esta columna
      vReinas.put ( lin col )

      __this.estaBienPuesta ( lin )
      jumpOnFalseTo endif
      lin.isEqualTo ( max )
      jumpOnFalseTo else
      toret = True
      jumpOnTrueTo fin
      :else
      toret = __this.resuelve ( lin.sum ( 1 ) )
      jumpOnTrueTo fin
      :endif

      col = col.sum ( 1 )
      col.isGreaterThan ( max )
      jumpOnFalseTo Loop

      :fin
      return toret
    endMethod

    method + toString ( )
      reference i = 0
      reference toret = ""
      reference elem

      ! Resolver el juego
      __this.resuelve ( 0 )
      jumpOnTrueTo Loop
      ! No hay solución
      toret = "No hay solución"
      vReinas = Nothing
      jumpOnTrueTo fin

      :Loop
      ! Mostrar la solución
      i = i.sum ( 1 )
      toret = toret.concat ( "Reina en fila " )
      toret = toret.concat ( i.toString ( ) )
      toret = toret.concat ( " colocada en columna " )
      elem = vReinas.get ( i.substract ( 1 ) )
      toret = toret.concat ( elem.toString ( ) )
      toret = toret.concat ( "\n" )
      i.isEqualTo ( vReinas.size ( ) )
      jumpOnFalseTo Loop

      :fin
      return toret
    endMethod
  endObject

  object Reinas8App
    method + doIt ( )
      reference i = 0
      reference reinas = VectorInstance.copy ( "" )

      :Loop
      reinas.add ( 0 )
      i = i.sum ( 1 )
      i.isLessThan ( 8 )
      jumpOnTrueTo Loop


      Resolutor8Reinas.setTablero ( reinas )

      System.console.write ( "8 Reinas\n" )
      System.console.write ( Resolutor8Reinas.toString ( ) )
      System.console.lf ( )

      return
    endMethod
  endObject