Advertisement
Guest User

Untitled

a guest
Sep 20th, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 17.90 KB | None | 0 0
  1. package day1
  2. import java.io._
  3. import scala.io.Source
  4.  
  5. object Battleship extends App {
  6.  
  7.   class Square(xNumber:Int, yNumber:Int, values:List[String] = List("-","S"), solved:Boolean = false) {
  8.     var possibleValues = values
  9.     val x = xNumber
  10.     val y = yNumber
  11.     var s = solved
  12.  
  13.     def setValues(solution: String) = {
  14.       this.s = true
  15.       this.possibleValues = List(solution)
  16.       // new Square(this.box, this.x, this.y, List(solution), true)
  17.     }
  18.  
  19.     def getValue:String = {
  20.       if(this.s) possibleValues.head
  21.       else "Not solved"
  22.     }
  23.  
  24.     def removeValue(wrongSolution:String):Square = {
  25.       val newList = this.possibleValues.filter(_ != wrongSolution)
  26.       if(newList.length > 1)
  27.         new Square(x, y, newList, false)
  28.       else
  29.         new Square(x,y,newList,true)
  30.     }
  31.  
  32.     // Returns a list with all neighbour squares in clockwise rotation
  33.     def getNeighbours(boardSize:Int):List[String] = {
  34.       var right = ""
  35.       var left = ""
  36.       var over = ""
  37.       var under = ""
  38.  
  39.       if(x == boardSize) right = "-"
  40.       else {
  41.         if(getSquare(x+1, y).possibleValues.length > 1) right = "?"
  42.         else right = getSquare(x+1,y).possibleValues.head
  43.       }
  44.  
  45.       if(x == 1) left = "-"
  46.       else {
  47.         if(getSquare(x-1, y).possibleValues.length > 1) left = "?"
  48.         else left = getSquare(x-1, y).possibleValues.head
  49.       }
  50.  
  51.       if(y == 1) over = "-"
  52.       else {
  53.         if(getSquare(x, y-1).possibleValues.length > 1) over = "?"
  54.         else over = getSquare(x, y-1).possibleValues.head
  55.       }
  56.  
  57.       if(y == boardSize) under = "-"
  58.       else {
  59.         if(getSquare(x, y+1).possibleValues.length > 1) under = "?"
  60.         else under = getSquare(x, y+1).possibleValues.head
  61.       }
  62.  
  63.       val neighbours = List[String](right, under, left, over)
  64.       neighbours
  65.     }
  66.  
  67.   }
  68.  
  69.   var allSquares = List[Square]()
  70.   var unsolvedSquares = List[Square]()
  71.   var boatsList = List[List[Square]]()
  72.   var savedBoard = List[Square]()
  73.  
  74.   def getAllFromX(i:Int):List[Square] = {
  75.     allSquares.filter(_.x == i)
  76.   }
  77.  
  78.   def getAllFromY(i:Int):List[Square] = {
  79.     allSquares.filter(_.y == i)
  80.   }
  81.  
  82.   def getSquare(x:Int, y:Int):Square = {
  83.     allSquares.filter(_.x == x).filter(_.y == y).head
  84.   }
  85.  
  86.   def setValue(x:Int, y:Int, solution:String):Unit = {
  87.     val s = getSquare(x,y)
  88.     allSquares = allSquares.filter(_ != s)
  89.     s.setValues(solution)
  90.     allSquares = allSquares :+ s
  91.   }
  92.  
  93.   def removeValue(x:Int, y:Int, wrongSolution:String):Unit = {
  94.     var s = getSquare(x,y)
  95.     allSquares = allSquares.filter(_ != s)
  96.     s = s.removeValue(wrongSolution)
  97.     allSquares = allSquares :+ s
  98.   }
  99.  
  100.   def getShips(ships:String):List[(Int, Int)] = {
  101.     var boats = List[(Int, Int)]()
  102.     var shipList = List[String]()
  103.  
  104.     // Read in ships from file
  105.     for(i <- 0 until ships.length){
  106.       if(ships.charAt(i) == 'x'){
  107.         shipList = shipList ::: List(s"${ships(i-1)}${ships(i)}${ships(i+1)}")
  108.       }
  109.     }
  110.  
  111.     var amount = 0
  112.     var size = 0
  113.     var xIndex = 0
  114.  
  115.     // Save ships in a list of tuples(amount, size)
  116.     // Example: (3, 1) means 3x1, or 3 boats of size 1
  117.     for(ship <- shipList){
  118.       xIndex = ship.indexOf('x')
  119.       amount = ship.substring(0, xIndex).toInt
  120.       size = ship.substring(xIndex + 1, ship.length).toInt
  121.  
  122.       boats = boats :+ (amount, size)
  123.     }
  124.  
  125.     // Return tuple list:
  126.     boats
  127.   }
  128.  
  129.   // Takes in a size as parameter, and loops through the list of tuples for the correct size
  130.   // When it finds the correct tuple, decrement the amount
  131.   // Return the new list
  132.   def decrementBoats(size:Int, boats:List[(Int, Int)]):List[(Int, Int)] = {
  133.     var boats2 = List[(Int, Int)]()
  134.     for(boat <- boats){
  135.       if(boat._2 == size && boat._1 > 0) boats2 = boats2 :+ (boat._1 - 1, boat._2)
  136.       else boats2 = boats2 :+ (boat._1, boat._2)
  137.     }
  138.     boats2
  139.   }
  140.  
  141.   def incrementBoats(size:Int, boats:List[(Int, Int)]):List[(Int, Int)] = {
  142.     var boats2 = List[(Int, Int)]()
  143.     for(boat <- boats){
  144.       if(boat._2 == size) boats2 = boats2 :+ (boat._1 + 1, boat._2)
  145.       else boats2 = boats2 :+ (boat._1, boat._2)
  146.     }
  147.     boats2
  148.   }
  149.  
  150.   def saveBoard(allSquares:List[Square]):Unit = {
  151.     savedBoard = allSquares
  152.   }
  153.  
  154.   def allowedMove(horizontalHints:List[Int], verticalHints:List[Int]):Boolean = {
  155.     var boardSize = horizontalHints.length
  156.     // Check if board fulfills all rules
  157.     // No boats touch each other
  158.     // Correct amount of boats in each row/col according to hints
  159.     var i = 1
  160.     for(hint <- horizontalHints){
  161.       if(getAllFromX(i).count((s:Square) => s.getValue == "S") > hint) return false
  162.       i += 1
  163.     }
  164.     i = 1
  165.     for(hint <- verticalHints){
  166.       if(getAllFromY(i).count((s:Square) => s.getValue == "S") > hint) return false
  167.       i += 1
  168.     }
  169.  
  170.     for(boat <- boatsList){
  171.       if(!isBoatBuilt(boat, boardSize)) return false
  172.     }
  173.  
  174.     true
  175.   }
  176.  
  177.   def bruteforceParty(boats:List[(Int, Int)], horizontalHints:List[Int], verticalHints:List[Int]):List[(Int, Int)] = {
  178.     var maxShip = 0
  179.     unsolvedSquares = getUnsolved
  180.  
  181.     for(boat <- boats){
  182.       if(boat._2 > maxShip && boat._1 > 0) maxShip = boat._2
  183.     }
  184.  
  185.     saveBoard(allSquares)
  186.  
  187.     var x = unsolvedSquares.head.x
  188.     var y = unsolvedSquares.head.y
  189.     var hint = verticalHints(y-1)
  190.  
  191.     //Get all lines where maxShip can mathematically be placed from hint and where the amount of boats is not yet solved
  192.     //Change the first square in unsolvedSquare, set it to value "boat"
  193.     if(hint >= maxShip && getAllFromY(x).count((s:Square) => s.getValue == "S") < hint){
  194.       val chosen = allSquares.filter((s:Square) => getSquare(s.x, s.y) == unsolvedSquares.head)
  195.       chosen.head.setValues("S")
  196.       println("Value of (" + getSquare(x, y).x + "," + getSquare(x, y).y + ") is changed to S\n")
  197.     }
  198.     var updatedShips = boats
  199.     updatedShips = updateBoatsList(horizontalHints.length, boats)
  200.  
  201.     updatedShips
  202.   }
  203.  
  204.   def getUnsolved:List[Square] = {
  205.     unsolvedSquares = allSquares.filter((u:Square) => !u.s)
  206.     unsolvedSquares
  207.   }
  208.  
  209.   def updateUnsolved():List[Square] = {
  210.     unsolvedSquares = unsolvedSquares.drop(1)
  211.     unsolvedSquares
  212.   }
  213.  
  214.   //TODO: Update so function checks if an entire boat is surrounded by water instead of only checking endpoints of boat
  215.   def isBoatBuilt(boat:List[Square], boardSize:Int):Boolean = {
  216.     //Check for boat of size 1 (one boat-tile is surrounded by water)
  217.     if(boat.length == 1){
  218.       if(boat.head.getNeighbours(boardSize).forall((n:String) => n == "-")) return true
  219.     }
  220.  
  221.     else {
  222.       var headNeighbours = boat.head.getNeighbours(boardSize)
  223.       var lastNeighbours = boat.last.getNeighbours(boardSize)
  224.  
  225.       //Check for horizontal boat (Head -> left tile = water, right tile = boat)(Last -> left tile = boat, right tile = water)
  226.       if (headNeighbours(2) == "-" && headNeighbours(0) == "S"
  227.        && lastNeighbours(0) == "-" && lastNeighbours(2) == "S") return true
  228.  
  229.       //Check for vertical boat (Head -> upper tile = water, lower tile = boat)(Last -> upper tile = boat, lower tile = water)
  230.       if (headNeighbours(3) == "-" && headNeighbours(1) == "S"
  231.        && lastNeighbours(1) == "-" && lastNeighbours(3) == "S") return true
  232.     }
  233.     false
  234.   }
  235.  
  236.   def updateBoatsList(boardSize:Int, ships:List[(Int, Int)]):List[(Int, Int)] = {
  237.     var boat = List[Square]()
  238.     var boat2 = List[Square]()
  239.     var updatedShips = ships
  240.  
  241.     //Horizontal boats
  242.     for(row <- 1 to boardSize) {
  243.       val line = getAllFromY(row)
  244.       for (i <- 1 to boardSize) {
  245.         if (getAllFromY(row).filter((s: Square) => s.x == i).head.possibleValues.head == "S") {
  246.           boat2 = boat2 :+ line.filter((s:Square) => s.x == i).head
  247.         }
  248.         else {
  249.           if(boat2.length > boat.length){
  250.             boat = boat2
  251.             if(isBoatBuilt(boat, boardSize)) {
  252.               if(!boatsList.contains(boat)) {
  253.                 boatsList = boatsList :+ boat
  254.                 updatedShips = decrementBoats(boat.length, updatedShips)
  255.               }
  256.             }
  257.             boat = List[Square]()
  258.             boat2 = List[Square]()
  259.           }
  260.         }
  261.       }
  262.     }
  263.  
  264.     boat = List[Square]()
  265.     boat2 = List[Square]()
  266.  
  267.     //Vertical boats
  268.     for(col <- 1 to boardSize) {
  269.       val line = getAllFromX(col)
  270.       for (i <- 1 to boardSize) {
  271.         if (getAllFromX(col).filter((s: Square) => s.y == i).head.possibleValues.head == "S") {
  272.           boat2 = boat2 :+ line.filter((s:Square) => s.y == i).head
  273.         }
  274.         else {
  275.           if(boat2.length > boat.length){
  276.             boat = boat2
  277.             if(isBoatBuilt(boat, boardSize)) {
  278.               if(!boatsList.contains(boat)) {
  279.                 boatsList = boatsList :+ boat
  280.                 updatedShips = decrementBoats(boat.length, updatedShips)
  281.               }
  282.             }
  283.             boat = List[Square]()
  284.             boat2 = List[Square]()
  285.           }
  286.         }
  287.       }
  288.     }
  289.     updatedShips
  290.   }
  291.  
  292.   def getHints(hintLine:String):List[Int] = {
  293.     var hint = List[Int]()
  294.     for(i <- 0 until hintLine.length){
  295.       if(hintLine.charAt(i) == ' '){
  296.         hint = hint ::: List(hintLine.charAt(i+1).toString.toInt)
  297.       }
  298.     }
  299.     hint
  300.   }
  301.  
  302.   def waterZeros(verticalHints:List[Int], horizontalHints:List[Int], size:Int):Unit = {
  303.     horizontalHints.foreach(hint => if(hint == 0) getAllFromX(horizontalHints.indexOf(hint)+1).foreach(u => setValue(u.x, u.y,"-")))
  304.     verticalHints.foreach(hint => if(hint == 0) getAllFromY(verticalHints.indexOf(hint)+1).foreach(u => setValue(u.x, u.y,"-")))
  305.   }
  306.  
  307.   def fillAroundHints():Unit={
  308.     allSquares.filter(_.possibleValues.length==1).foreach(k=> k.possibleValues.head match {
  309.       case "*" => {
  310.         allSquares.filter((b: Square) => (b.y == k.y - 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y + 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y && (b.x == k.x - 1 || b.x == k.x + 1))).foreach(z => setValue(z.x, z.y, "-"))
  311.         setValue(k.x, k.y, "S")
  312.       }
  313.       case "<" => {
  314.         allSquares.filter((b: Square) => (b.y == k.y - 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y + 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y && b.x == k.x - 1)).foreach(z => setValue(z.x, z.y, "-"))
  315.         if(getSquare(k.x+1,k.y).possibleValues.length!=1)setValue(k.x + 1, k.y, "S")
  316.         setValue(k.x, k.y, "S")
  317.       }
  318.       case ">" => {
  319.         allSquares.filter((b: Square) => (b.y == k.y - 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y + 1 && (b.x == k.x - 1 || b.x == k.x || b.x == k.x + 1)) || (b.y == k.y && b.x == k.x + 1)).foreach(z => setValue(z.x, z.y, "-"))
  320.         if(getSquare(k.x-1,k.y).possibleValues.length!=1)setValue(k.x - 1, k.y, "S")
  321.         setValue(k.x, k.y, "S")
  322.       }
  323.       case "A" => {
  324.         allSquares.filter((b:Square)=> (b.y == k.y-1 && (b.x ==k.x-1||b.x ==k.x || b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1|| b.x==k.x+1)) || (b.y==k.y && (b.x==k.x-1 || b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  325.         if(getSquare(k.x,k.y+1).possibleValues.length!=1)setValue(k.x, k.y+1, "S")
  326.         setValue(k.x, k.y, "S")
  327.       }
  328.       case "V" => {
  329.         allSquares.filter((b:Square)=> (b.y == k.y-1 && (b.x ==k.x-1|| b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1||b.x==k.x || b.x==k.x+1)) || (b.y==k.y && (b.x==k.x-1 || b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  330.         if(getSquare(k.x,k.y-1).possibleValues.length!=1)setValue(k.x, k.y-1, "S")
  331.         setValue(k.x, k.y, "S")
  332.       }
  333.       case "+" => allSquares.filter((b:Square)=> (b.y == k.y-1 && (b.x ==k.x-1|| b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1|| b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  334.       /*{
  335.               allSquares.filter((b:Square)=> (b.y == k.y-1 && (b.x ==k.x-1|| b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1|| b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  336.               setValue(k.x, k.y, "S")
  337.             }*/
  338.       case "S" => allSquares.filter((b:Square)=> (b.y == k.y-1 && (b.x ==k.x-1|| b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1|| b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  339.       case "-" =>
  340.     })
  341.   }
  342.  
  343.   def checkPlus(k:Square)={
  344.     if(getSquare(k.x,k.y-1).possibleValues== List("-") || getSquare(k.x,k.y+1).possibleValues== List("-")){
  345.       setValue(k.x+1,k.y,"S")
  346.       setValue(k.x-1,k.y,"S")
  347.       setValue(k.x,k.y,"S")
  348.     }
  349.     else if (getSquare(k.x+1,k.y).possibleValues== "-" || getSquare(k.x-1,k.y).possibleValues== "-"){
  350.       setValue(k.x,k.y+1,"S")
  351.       setValue(k.x,k.y-1,"S")
  352.       setValue(k.x,k.y,"S")
  353.     }
  354.   }
  355.  
  356.  
  357.   // Fills water in the corner squares of each boat
  358.   def waterCorners():Unit = {
  359.     allSquares.filter(_.possibleValues.head == "S").foreach(k => k.possibleValues.head match {
  360.       case "S" => allSquares.filter((b:Square) => (b.y == k.y-1 && (b.x ==k.x-1|| b.x ==k.x+1)) || (b.y ==k.y+1 && (b.x ==k.x-1|| b.x==k.x+1))).foreach(z=>setValue(z.x,z.y,"-"))
  361.       case _ =>
  362.     })
  363.   }
  364.  
  365.   def checkBoatsXY(horizontal:List[Int], vertical:List[Int], size:Int):Unit = {
  366.     for (i <- 0 until size) {
  367.       if (getAllFromX(i + 1).filter(_.possibleValues.length == 1).count(_.possibleValues.head != "-") == horizontal(i)) {
  368.         getAllFromX(i + 1).filter(_.possibleValues.length != 1).foreach(u => setValue(u.x, u.y, "-"))
  369.       } else if (horizontal(i) - getAllFromX(i + 1).count(_.possibleValues.head == "S") == getAllFromX(i + 1).count(_.possibleValues.length != 1)){
  370.         getAllFromX(i + 1).filter(_.possibleValues.length != 1).foreach(u => setValue(u.x, u.y, "S"))
  371.       }
  372.  
  373.       if (getAllFromY(i + 1).filter(_.possibleValues.length == 1).count(_.possibleValues.head != "-") == vertical(i)) {
  374.         getAllFromY(i + 1).filter(_.possibleValues.length != 1).foreach(u => setValue(u.x, u.y, "-"))
  375.       } else if (vertical(i) - getAllFromY(i + 1).count(_.possibleValues.head == "S") == getAllFromY(i + 1).count(_.possibleValues.length != 1)) {
  376.         getAllFromY(i + 1).filter(_.possibleValues.length != 1).foreach(u => setValue(u.x, u.y, "S"))
  377.       }
  378.     }
  379.   }
  380.  
  381.   def checkIfSolved():Boolean = {
  382.     allSquares.forall(_.s)
  383.   }
  384.  
  385.   def printToFile(solved:String):Unit = {
  386.     val out = new BufferedWriter(new FileWriter(new File("puzzle_solved.txt")))
  387.  
  388.     out.write(solved)
  389.     out.close()
  390.   }
  391.  
  392.   def mainSolver(path:String):Unit = {
  393.     val lines = Source.fromFile(path).getLines.toList
  394.     var smolLines = lines
  395.     val puzzleAmount = lines(0).charAt(8).toString.toInt
  396.     var solved = "Puzzles " + puzzleAmount +"\n"
  397.     var currentBoard = List[Square]()
  398.     var lastBoard = List[Square]()
  399.     var updatedShips = List[(Int, Int)]()
  400.     var bruteforceFlag = true
  401.  
  402.     smolLines = smolLines.drop(1)
  403.  
  404.     for(i <- 0 until puzzleAmount){ //one loop is one puzzle solving sequence
  405.  
  406.       smolLines = smolLines.drop(1)
  407.       val ships = getShips(smolLines.head)
  408.       smolLines = smolLines.drop(1)
  409.       val horizontalHints = getHints(smolLines.head)
  410.       smolLines = smolLines.drop(1)
  411.       val verticalHints = getHints(smolLines.head)
  412.       val size = verticalHints.length
  413.       smolLines = smolLines.drop(1)
  414.       smolLines = smolLines.drop(1)
  415.  
  416.       for (y <- 0 until size) {
  417.         var boatline = smolLines.head.filter(_ != ' ')
  418.  
  419.         for (x <- 0 until size) {
  420.           if (boatline.charAt(x) != '?') {
  421.             allSquares = allSquares ::: List(new Square(x + 1, y + 1, List(boatline.charAt(x).toString), true))
  422.           } else {
  423.             allSquares = allSquares ::: List(new Square(x + 1, y + 1))
  424.           }
  425.         }
  426.         smolLines = smolLines.drop(1)
  427.       }
  428.  
  429.       currentBoard = allSquares
  430.       updatedShips = ships
  431.  
  432.       /*****************************************************************************************************************/
  433.  
  434.       def printTempSolution():Unit = {
  435.         print("   ")
  436.         horizontalHints.foreach((h:Int) => print(h + " "))
  437.         println()
  438.         for(y <- 1 to size){
  439.           print(verticalHints(y-1) + "  ")
  440.           for(x <- 1 to size){
  441.             if(getSquare(x,y).possibleValues.length > 1) print("? ")
  442.             else print(getSquare(x,y).possibleValues.head + " ")
  443.           }
  444.           println()
  445.         }
  446.         println()
  447.       }
  448.  
  449.       printTempSolution() // Original puzzle
  450.       fillAroundHints()
  451.       waterZeros(verticalHints, horizontalHints, size)
  452.       printTempSolution()
  453.  
  454.       while (!checkIfSolved()) {
  455.         lastBoard = currentBoard
  456.         checkBoatsXY(horizontalHints, verticalHints, size)
  457.         waterCorners()
  458.         printTempSolution()
  459.         currentBoard = allSquares
  460.  
  461.         for(x <- 1 to size){
  462.           for(y <- 1 to size){
  463.             if(getSquare(x,y).possibleValues==List("+")) {
  464.               checkPlus(getSquare(x, y))
  465.             }
  466.           }
  467.         }
  468.  
  469.         updatedShips = updateBoatsList(size, updatedShips)
  470.  
  471.         if(currentBoard == lastBoard) {
  472.           println("I AM STUCK PLEASE HELP")
  473.           if(bruteforceFlag) updatedShips = bruteforceParty(updatedShips, horizontalHints, verticalHints)
  474.           unsolvedSquares = updateUnsolved()
  475.         }
  476.       }
  477.  
  478.       /****************************************************************************************************************/
  479.  
  480.       updatedShips = updateBoatsList(size, updatedShips)
  481.       println("Ships: " + ships)
  482.       println("Updated: " + updatedShips)
  483.       println("Vertical: " + verticalHints)
  484.       println("Horizontal: " + horizontalHints)
  485.  
  486.       solved += "Size " + size + "x" + size + "\n"
  487.  
  488.       for(y <- 1 to size) {
  489.         for(x <- 1 to size){
  490.           solved += getSquare(x,y).possibleValues.head + " "
  491.           print(getSquare(x,y).possibleValues.head + " ")
  492.         }
  493.         solved += "\n"
  494.         println()
  495.       }
  496.  
  497.       //println(size)
  498.       allSquares = List[Square]()
  499.       boatsList = List[List[Square]]()
  500.       println("\n")
  501.     }
  502.  
  503.     printToFile(solved)
  504.   }
  505.  
  506.   mainSolver("puzzle_unsolved.txt")
  507.  
  508. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement