commit 74bfdbfb4475a1cf0c168cbc5f33404aa69cdc82 Author: François Pelletier Date: Mon May 28 19:40:19 2018 -0400 ajout des fichiers originaux présentés dans l'atelier diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5b36c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +project/target/ +target/ diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..f0d349f --- /dev/null +++ b/build.sbt @@ -0,0 +1,9 @@ +name := "puzzles_libre" + +version := "0.1" + +scalaVersion := "2.11.12" + +resolvers += "Artifactory" at "http://artifactory.info.ucl.ac.be/artifactory/libs-release/" + +libraryDependencies += "oscar" % "oscar-cp_2.11" % "3.1.0" \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..5517665 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.1.1 \ No newline at end of file diff --git a/src/main/scala/CrossWord.scala b/src/main/scala/CrossWord.scala new file mode 100644 index 0000000..429c14f --- /dev/null +++ b/src/main/scala/CrossWord.scala @@ -0,0 +1,185 @@ +/******************************************************************************* + * OscaR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * OscaR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with OscaR. + * If not, see http://www.gnu.org/licenses/lgpl-3.0.en.html + ******************************************************************************/ +import oscar.cp._ +import oscar.cp.core.CPPropagStrength + +/** + +Crosswords in OscaR. + + This is a standard example for constraint logic programming. See e.g. + + http://www.cis.temple.edu/~ingargio/cis587/readings/constraints.html + + We are to complete the puzzle + + 1 2 3 4 5 + +---+---+---+---+---+ Given the list of words: + 1 | 1 | | 2 | | 3 | AFT LASER + +---+---+---+---+---+ ALE LEE + 2 | # | # | | # | | EEL LINE + +---+---+---+---+---+ HEEL SAILS + 3 | # | 4 | | 5 | | HIKE SHEET + +---+---+---+---+---+ HOSES STEER + 4 | 6 | # | 7 | | | KEEL TIE + +---+---+---+---+---+ KNOT + 5 | 8 | | | | | + +---+---+---+---+---+ + 6 | | # | # | | # | The numbers 1,2,3,4,5,6,7,8 in the crossword + +---+---+---+---+---+ puzzle correspond to the words + that will start at those locations. + + + The model was inspired by Sebastian Brand's Array Constraint cross word example + http://www.cs.mu.oz.au/~sbrand/project/ac/ + http://www.cs.mu.oz.au/~sbrand/project/ac/examples.pl + + + + @author Hakan Kjellerstrand hakank@gmail.com + http://www.hakank.org/oscar/ + + */ +object CrossWord extends CPModel with App { + + // + // data + // + + val alpha = Array(" ", "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", + "u", "v", "w", "x", "y", "z") + + val a = 1 + val b = 2 + val c = 3 + val d = 4 + val e = 5 + val f = 6 + val g = 7 + val h = 8 + val i = 9 + val j = 10 + val k = 11 + val l = 12 + val m = 13 + val n = 14 + val o = 15 + val p = 16 + val q = 17 + val r = 18 + val s = 19 + val t = 20 + val u = 21 + val v = 22 + val w = 23 + val x = 24 + val y = 25 + val z = 26 + + val num_words = 15 + val word_len = 5 + + val AA = Array(Array(h, o, s, e, s), // HOSES + Array(l, a, s, e, r), // LASER + Array(s, a, i, l, s), // SAILS + Array(s, h, e, e, t), // SHEET + Array(s, t, e, e, r), // STEER + Array(h, e, e, l, 0), // HEEL + Array(h, i, k, e, 0), // HIKE + Array(k, e, e, l, 0), // KEEL + Array(k, n, o, t, 0), // KNOT + Array(l, i, n, e, 0), // LINE + Array(a, f, t, 0, 0), // AFT + Array(a, l, e, 0, 0), // ALE + Array(e, e, l, 0, 0), // EEL + Array(l, e, e, 0, 0), // LEE + Array(t, i, e, 0, 0)) // TIE + + val num_overlapping = 12 + val overlapping = Array(Array(0, 2, 1, 0), // s + Array(0, 4, 2, 0), // s + + Array(3, 1, 1, 2), // i + Array(3, 2, 4, 0), // k + Array(3, 3, 2, 2), // e + + Array(6, 0, 1, 3), // l + Array(6, 1, 4, 1), // e + Array(6, 2, 2, 3), // e + + Array(7, 0, 5, 1), // l + Array(7, 2, 1, 4), // s + Array(7, 3, 4, 2), // e + Array(7, 4, 2, 4)) // r + + val N = 8 + + // + // variables + // + val A = Array.fill(num_words, word_len)(CPIntVar(0 to 26)) + val A_flatten = A.flatten + + val E = Array.fill(N)(CPIntVar(0 to num_words)) + + // + // constraints + // + + + add(allDifferent(E)) + + for (i <- 0 until num_words;j <- 0 until word_len){ + add(A(i)(j) == AA(i)(j)) + } + + + // Handle the overlappings. + // + // It's coded in MiniZinc as: + // forall(i in 1..num_overlapping) ( + // A[E[overlapping[i,1]], overlapping[i,2]] = + // A[E[overlapping[i,3]], overlapping[i,4]] + // ) + // + for (i <- 0 until num_overlapping) { + add( + A_flatten(E(overlapping(i)(0)) * word_len + overlapping(i)(1)) + == + A_flatten(E(overlapping(i)(2)) * word_len + overlapping(i)(3)), + CPPropagStrength.Strong + ) + } + + search(binaryStatic(E)) + + onSolution { + println("E: " + E.mkString(" ")) + for (ee <- 0 until N) { + print(ee + ": (" + "%2d".format(E(ee).value) + ") ") + for (ii <- 0 until word_len) { + print(alpha(A(ee)(ii).value)) + } + println() + } + println() + } + + val stats = start() + println(stats) + +} diff --git a/src/main/scala/Queens.scala b/src/main/scala/Queens.scala new file mode 100644 index 0000000..bf041fd --- /dev/null +++ b/src/main/scala/Queens.scala @@ -0,0 +1,23 @@ +import oscar.cp._ +object Queens extends CPModel with App { + val nQueens = 12 // Number of queens + val Queens = 0 until nQueens + // Variables + val queens = Array.fill(nQueens)(CPIntVar.sparse(0, nQueens - 1)) + // Constraints + add(allDifferent(queens)) + add(allDifferent(Queens.map(i => queens(i) + i))) + add(allDifferent(Queens.map(i => queens(i) - i))) + // Search heuristic + search(binaryFirstFail(queens)) + onSolution{ + print("Solution potentielle\n") + println(queens.mkString(" ")) + } + // Execution + val stats = start() + println(stats) + + + +} diff --git a/src/main/scala/Sudoku2.scala b/src/main/scala/Sudoku2.scala new file mode 100644 index 0000000..4db139f --- /dev/null +++ b/src/main/scala/Sudoku2.scala @@ -0,0 +1,134 @@ +/******************************************************************************* + * OscaR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * OscaR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with OscaR. + * If not, see http://www.gnu.org/licenses/lgpl-3.0.en.html + ******************************************************************************/ +import oscar.cp._ +import scala.io.Source._ +import scala.math._ + +/** + * + * Sudoku solver in Oscar. + * + * See http://en.wikipedia.org/wiki/Sudoku + * + * This version can also read a problem instance from a file. + * + * A collection of problem instances (from Gecode) can be found + * in the ./data directory. + * + * + * @author Hakan Kjellerstrand hakank@gmail.com + * http://www.hakank.org/oscar/ + * + */ +object Sudoku2 extends CPModel with App { + + // data + var n = 9 + var reg = 3 + val X = 0 + + // + // data + // + // This problem is problem 0 from + // Gecode's sudoku.cpp + // http://www.gecode.org/gecode-doc-latest/sudoku_8cpp-source.html + // + var problem = Array( + Array(X, X, X, 2, X, 5, X, X, X), + Array(X, 9, X, X, X, X, 7, 3, X), + Array(X, X, 2, X, X, 9, X, 6, X), + Array(2, X, X, X, X, X, 4, X, 9), + Array(X, X, X, X, 7, X, X, X, X), + Array(6, X, 9, X, X, X, X, X, 1), + Array(X, 8, X, 4, X, X, 1, X, X), + Array(X, 6, 3, 1, X, X, X, 8, X), + Array(X, X, X, 6, X, 8, X, X, X)) + + val alpha = ('0' to'9') ++ ('A' to 'Z') + + // read problem instance from file + if (args.length > 0) { + val fileName = args(0) + println("\nReading from file: " + fileName) + + val lines = fromFile(fileName).getLines.filter(!_.startsWith("#")).toArray + n = lines(0).toInt + reg = sqrt(n).toInt + println("Size:" + n) + val this_problem = lines.tail.map(_.split("\\s+"). + filter(_.length>0).map(i=>if (i == ".") X else i.toInt)) + println(this_problem.map(row=>row. + map(e=>if (e==0) " ." else "%3s".format(alpha(e))).mkString("")). + mkString("\n")) + + println() + + problem = this_problem + + } + + val NRANGE = 0 until n + val RRANGE = 0 until reg + + // variables + val x = Array.fill(n,n)(CPIntVar(1 to n)) + val x_t = x.transpose + + // + // constraints + // + var numSols = 0 + + search { + + binaryFirstFail(x.flatten.toSeq) + + } + + onSolution { + + println("\nSolution:") + for(i <- NRANGE) { + println(x(i).map(j=>alpha(j.value)).mkString(" ")) + } + println() + + numSols += 1 + + } + + + // fill with the hints + for(i <- NRANGE; + j <- NRANGE if problem(i)(j) > 0) { + add(x(i)(j) == problem(i)(j)) + } + + // rows and columns + for(i <- NRANGE) { + add(allDifferent(x(i)), Strong) + add(allDifferent(x_t(i)), Strong) + } + + // blocks + for(i <- RRANGE; j <- RRANGE) { + add(allDifferent((for{ r <- i*reg until i*reg+reg; + c <- j*reg until j*reg+reg + } yield x(r)(c))), Strong) + } + val stats = start() + println(stats) +} \ No newline at end of file