Compare commits
	
		
			13 Commits
		
	
	
		
			6d56eb5c8a
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 27918e7a35 | |||
| fe28ec45a5 | |||
| 37314cf9db | |||
| e6ec271afd | |||
| 0e46e1a292 | |||
| 11c90daaa2 | |||
| a280dfd564 | |||
| 9d6b1f767e | |||
| 7141534e9f | |||
| 8e9567e1a2 | |||
| 124b4c7a33 | |||
| 5afec8149d | |||
| 38c3be5740 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| /out/ | ||||
| # ---> Scala | ||||
| *.class | ||||
| *.log | ||||
|   | ||||
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Editor-based HTTP Client requests | ||||
| /httpRequests/ | ||||
| # Datasource local storage ignored files | ||||
| /dataSources/ | ||||
| /dataSources.local.xml | ||||
							
								
								
									
										6
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/out" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/Lab17.iml" filepath="$PROJECT_DIR$/Lab17.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="" vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										13
									
								
								Lab17.iml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Lab17.iml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="WEB_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager" inherit-compiler-output="true"> | ||||
|     <exclude-output /> | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | ||||
|     </content> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|     <orderEntry type="library" name="scala-sdk-2.13.12" level="project" /> | ||||
|     <orderEntry type="library" name="FunGraphics-1.5.13" level="application" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										32
									
								
								src/Hanoi.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/Hanoi.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| import scala.collection.mutable | ||||
|  | ||||
| class Hanoi(val n: Int, val left: Char, val mid: Char, val right: Char) { | ||||
|   val lists: mutable.HashMap[Char, mutable.Stack[Int]] = new mutable.HashMap() | ||||
|   lists(left) = mutable.Stack.range(1, n + 1) | ||||
|   lists(mid) = mutable.Stack.empty | ||||
|   lists(right) = mutable.Stack.empty | ||||
|  | ||||
|   def move(from: Char, to: Char): Unit = { | ||||
|     val i: Int = lists(from).pop() | ||||
|     println(s"Moving disk $i from $from->$to") | ||||
|     lists(to).push(i) | ||||
|   } | ||||
|  | ||||
|   def solve(): Unit = { | ||||
|     hanoi(n, left, mid, right) | ||||
|   } | ||||
|  | ||||
|   private def hanoi(n: Int, start: Char, aux: Char, end: Char): Unit = { | ||||
|     if (n == 0) return | ||||
|     hanoi(n - 1, start, end, aux) | ||||
|     move(start, end) | ||||
|     hanoi(n - 1, aux, start, end) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object Hanoi { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val hanoi: Hanoi = new Hanoi(3, 'A', 'B', 'C') | ||||
|     hanoi.solve() | ||||
|   } | ||||
| } | ||||
							
								
								
									
										93
									
								
								src/logo/NaturalTree.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/logo/NaturalTree.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| package logo | ||||
|  | ||||
| import java.awt.{Color, Point} | ||||
| import scala.util.Random | ||||
|  | ||||
| class NaturalTree(width: Int, height: Int, angleStep_ : Double) extends Tree(width, height, angleStep_) { | ||||
|   val MIN_STRAW_ANGLE: Double = 60 | ||||
|   val MAX_STRAW_ANGLE: Double = 100 | ||||
|   val MIN_N_STRAWS: Int = 90 | ||||
|   val MAX_N_STRAWS: Int = 200 | ||||
|   //val STRAW_COLOR1: Color = new Color(230, 188, 43) | ||||
|   //val STRAW_COLOR2: Color = new Color(255, 226, 71) | ||||
|   //val STRAW_COLOR1: Color = new Color(96, 163, 67) | ||||
|   //val STRAW_COLOR2: Color = new Color(112, 198, 76) | ||||
|   val STRAW_COLOR1: Color = new Color(108, 83, 61) | ||||
|   val STRAW_COLOR2: Color = new Color(174, 105, 44) | ||||
|   val TRUNK_COLOR: Color = new Color(65, 61, 64) | ||||
|  | ||||
|   override def drawTree(n: Int, length: Double): Unit = { | ||||
|     var n2: Int = n | ||||
|     val r: Double = math.random() | ||||
|     if (r < 0.25) { | ||||
|       n2 -= 1 | ||||
|     } else if (r > 0.9) { | ||||
|       if (n2 < 2) { | ||||
|         n2 += 3 | ||||
|       } | ||||
|     } | ||||
|     turn(angleStep * (math.random() - 0.5) * 2) | ||||
|     val a: Double = angleStep | ||||
|     angleStep -= math.random() * angleStep / 10 | ||||
|     super.drawTree(n2, length) | ||||
|     angleStep = a | ||||
|   } | ||||
|  | ||||
|   override def drawBranch(length: Double): Unit = { | ||||
|     setPenWidth((length / 10).toFloat) | ||||
|     setColor(TRUNK_COLOR) | ||||
|     super.drawBranch(length) | ||||
|   } | ||||
|  | ||||
|   override def drawLeaf(length: Double): Unit = { | ||||
|     val angle: Double = getTurtleAngle() | ||||
|     val pos: Point = getPosition() | ||||
|     val nStraws: Int = Random.between(MIN_N_STRAWS, MAX_N_STRAWS) | ||||
|     val strawsAngle: Double = Random.between(MIN_STRAW_ANGLE, MAX_STRAW_ANGLE) | ||||
|     val step: Double = strawsAngle / (nStraws - 1) | ||||
|     val oAngle: Double = angle - strawsAngle / 2 | ||||
|     val strawLen: Double = length * 20 | ||||
|  | ||||
|     setPenWidth(1f) | ||||
|     for (i: Int <- 0 until nStraws) { | ||||
|       setPenWidth(0.5f + (nStraws - i) / (nStraws - 1f) / 10) | ||||
|       setColor(lerpCol((nStraws - i) / (nStraws - 1.0))) | ||||
|       //val a: Double = oAngle + i * step + (math.random() * 2 -1) * step / 5 | ||||
|       val a: Double = oAngle + math.random() * strawsAngle | ||||
|       var l: Double = strawLen * (nStraws.toDouble - i) / nStraws | ||||
|       l += (math.random() * 2 - 1) * l / 2 | ||||
|       setAngle(a) | ||||
|       jump(pos.x, pos.y) | ||||
|       //forward(strawLen + (math.random() * 2 - 1) * strawLen / 2) | ||||
|       forward(l) | ||||
|     } | ||||
|     jump(pos.x, pos.y) | ||||
|     setAngle(angle) | ||||
|   } | ||||
|  | ||||
|   def lerpCol(f: Double): Color = { | ||||
|     val r: Int = ((STRAW_COLOR2.getRed - STRAW_COLOR1.getRed) * f + STRAW_COLOR1.getRed).toInt | ||||
|     val g: Int = ((STRAW_COLOR2.getGreen - STRAW_COLOR1.getGreen) * f + STRAW_COLOR1.getGreen).toInt | ||||
|     val b: Int = ((STRAW_COLOR2.getBlue - STRAW_COLOR1.getBlue) * f + STRAW_COLOR1.getBlue).toInt | ||||
|     return new Color( | ||||
|       math.min(255, math.max(0, r)), | ||||
|       math.min(255, math.max(0, g)), | ||||
|       math.min(255, math.max(0, b)) | ||||
|     ) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object NaturalTree { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val tree: NaturalTree = new NaturalTree(600, 600, 25) | ||||
|     tree.jump(300, 600) | ||||
|     tree.setAngle(-90) | ||||
|     tree.drawTree(8, 80) | ||||
|  | ||||
|     for (i: Int <- 0 until 10) { | ||||
|       tree.jump(Random.between(0, 600), 600) | ||||
|       tree.setAngle(-90) | ||||
|       tree.drawTree(3, 20) | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/logo/Snowflake.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/logo/Snowflake.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| package logo | ||||
|  | ||||
| import hevs.graphics.TurtleGraphics | ||||
|  | ||||
| import java.awt.Point | ||||
|  | ||||
| class Snowflake(width: Int, height: Int) extends TurtleGraphics(width, height) { | ||||
|   def drawFlakeSegment(n: Int, length: Double): Unit = { | ||||
|     if (n == 1) { | ||||
|       forward(length) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     val third: Double = length / 3 | ||||
|     drawFlakeSegment(n - 1, third) | ||||
|     turn(-60) | ||||
|     drawFlakeSegment(n - 1, third) | ||||
|     turn(120) | ||||
|     drawFlakeSegment(n - 1, third) | ||||
|     turn(-60) | ||||
|     drawFlakeSegment(n - 1, third) | ||||
|   } | ||||
|  | ||||
|   def drawFlake(n: Int, length: Double): Unit = { | ||||
|     val pos: Point = getPosition() | ||||
|     val x: Double = pos.x - length / 2 | ||||
|     val y: Double = pos.y - math.sqrt(3) * length / 6 | ||||
|     jump(x.toInt, y.toInt) | ||||
|     setAngle(0) | ||||
|     drawFlakeSegment(n, length) | ||||
|     turn(120) | ||||
|     drawFlakeSegment(n, length) | ||||
|     turn(120) | ||||
|     drawFlakeSegment(n, length) | ||||
|     turn(120) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object Snowflake { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val win = new Snowflake(600, 600) | ||||
|     win.penUp() | ||||
|     win.jump(300, 300) | ||||
|     win.penDown() | ||||
|     win.drawFlake(5, 400) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										38
									
								
								src/logo/TestLogo.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/logo/TestLogo.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| package logo | ||||
|  | ||||
| import hevs.graphics.TurtleGraphics | ||||
|  | ||||
| import java.awt.Color | ||||
|  | ||||
| object TestLogo { | ||||
|   def drawCircle(turtle: TurtleGraphics, radius: Double, resolution: Int = 24): Unit = { | ||||
|     val angle: Double = 360.0 / resolution | ||||
|     val side: Double = radius * math.sin(angle * math.Pi / 180) | ||||
|     turtle.forward(-side / 2) | ||||
|     for (_: Int <- 0 until resolution) { | ||||
|       turtle.forward(side) | ||||
|       turtle.turn(angle) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val turtle: TurtleGraphics = new TurtleGraphics(600, 600) | ||||
|     turtle.drawLine(150, 300, 450, 300) | ||||
|  | ||||
|     turtle.penUp() | ||||
|     turtle.jump(300, 300) | ||||
|     turtle.setAngle(0) | ||||
|     turtle.forward(150 * math.sqrt(3) / 2) | ||||
|     turtle.turn(150) | ||||
|     turtle.penDown() | ||||
|     for (_: Int <- 0 until 3) { | ||||
|       turtle.forward(300) | ||||
|       turtle.turn(120) | ||||
|     } | ||||
|  | ||||
|     turtle.jump(450, 300) | ||||
|     turtle.setAngle(90) | ||||
|     turtle.setColor(Color.RED) | ||||
|     drawCircle(turtle, 150) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/logo/Tree.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/logo/Tree.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| package logo | ||||
|  | ||||
| import hevs.graphics.TurtleGraphics | ||||
|  | ||||
| import java.awt.Point | ||||
|  | ||||
| class Tree(width: Int, height: Int, var angleStep: Double) extends TurtleGraphics(width, height) { | ||||
|   def drawTree(n: Int, length: Double): Unit = { | ||||
|     if (n > 1) { | ||||
|       drawBranch(length) | ||||
|       val pos: Point = getPosition() | ||||
|       val angle: Double = getTurtleAngle() | ||||
|  | ||||
|       turn(-angleStep) | ||||
|       drawTree(n - 1, length * 0.8) | ||||
|       jump(pos.x, pos.y) | ||||
|       setAngle(angle) | ||||
|       turn(angleStep) | ||||
|       drawTree(n - 1, length * 0.8) | ||||
|     } else { | ||||
|       drawBranch(length) | ||||
|       drawLeaf(length / 10) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def drawBranch(length: Double): Unit = { | ||||
|     forward(length) | ||||
|   } | ||||
|  | ||||
|   def drawLeaf(length: Double): Unit = { | ||||
|  | ||||
|   } | ||||
| } | ||||
| object Tree { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val tree: Tree = new Tree(400, 400, 15) | ||||
|     tree.jump(200, 400) | ||||
|     tree.setAngle(-90) | ||||
|     tree.drawTree(8, 60) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/magic_squares/Displayable.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/magic_squares/Displayable.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| package magic_squares | ||||
|  | ||||
| trait Displayable { | ||||
|   def display(g: Grid): Unit | ||||
| } | ||||
							
								
								
									
										53
									
								
								src/magic_squares/GraphicsDisplay.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/magic_squares/GraphicsDisplay.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| package magic_squares | ||||
|  | ||||
| import hevs.graphics.FunGraphics | ||||
|  | ||||
| import java.awt.{Color, Font} | ||||
| import javax.swing.SwingConstants | ||||
|  | ||||
| trait GraphicsDisplay extends Displayable { | ||||
|   private var _win: Option[FunGraphics] = None | ||||
|   private val WIDTH: Int = 400 | ||||
|   private val HEIGHT: Int = 400 | ||||
|   private val MARGIN: Int = 20 | ||||
|   private val FONT: Font = new Font("Arial", Font.PLAIN, 24) | ||||
|   override def display(g: Grid): Unit = { | ||||
|     if (_win.isEmpty) { | ||||
|       _win = Some(new FunGraphics(WIDTH, HEIGHT)) | ||||
|     } | ||||
|     val win: FunGraphics = _win.get | ||||
|     win.clear() | ||||
|     val size: Int = g.length | ||||
|  | ||||
|     val w: Int = WIDTH - 2 * MARGIN | ||||
|     val h: Int = HEIGHT - 2 * MARGIN | ||||
|     val gridSize: Int = math.min(w, h) | ||||
|     val cellSize: Int = gridSize / size | ||||
|     val ox: Int = (WIDTH - gridSize) / 2 | ||||
|     val oy: Int = (HEIGHT - gridSize) / 2 | ||||
|  | ||||
|     win.drawRect(ox, oy, gridSize, gridSize) | ||||
|     for (i: Int <- 1 until size) { | ||||
|       win.drawLine(ox + cellSize * i, oy, ox + cellSize * i, oy + gridSize) | ||||
|       win.drawLine(ox, oy + cellSize * i, ox + gridSize, oy + cellSize * i) | ||||
|     } | ||||
|  | ||||
|     for (y: Int <- 0 until size) { | ||||
|       for (x: Int <- 0 until size) { | ||||
|         val v: Int = g(y)(x) | ||||
|         if (v != 0) { | ||||
|           win.drawString( | ||||
|             (ox + cellSize * (x + 0.5)).toInt, | ||||
|             (oy + cellSize * (y + 0.5)).toInt, | ||||
|             v.toString, | ||||
|             FONT, | ||||
|             Color.BLACK, | ||||
|             SwingConstants.CENTER, | ||||
|             SwingConstants.CENTER | ||||
|           ) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     win.syncGameLogic(60) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										174
									
								
								src/magic_squares/MagicSquareSolver.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								src/magic_squares/MagicSquareSolver.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| package magic_squares | ||||
|  | ||||
| import scala.collection.mutable.ArrayBuffer | ||||
|  | ||||
| abstract class MagicSquareSolver(initialGrid: Grid) extends Displayable { | ||||
|   protected var _initial: Grid = initialGrid | ||||
|   protected var grid: Grid = copy(_initial) | ||||
|   protected val _size: Int = _initial.length | ||||
|   protected val SUM: Int = _size * (_size * _size + 1) / 2 | ||||
|   protected val DEBUG: Boolean = false | ||||
|   protected val NUMBERS: Array[Int] = Array.range(1, _size * _size + 1) | ||||
|  | ||||
|   protected def print(grid: Grid): Unit = { | ||||
|     for (y: Int <- 0 until _size) { | ||||
|       println(grid(y).mkString(",")) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected def copy(grid: Grid): Grid = { | ||||
|     return grid.map(_.clone()) | ||||
|   } | ||||
|  | ||||
|   def solve(): Unit = { | ||||
|     val inGrid: ArrayBuffer[Int] = ArrayBuffer.empty | ||||
|     for (y: Int <- 0 until _size) { | ||||
|       for (x: Int <- 0 until _size) { | ||||
|         if (grid(y)(x) != 0) { | ||||
|           inGrid.addOne(grid(y)(x)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     val solved: Boolean = _solve(inGrid.toArray) | ||||
|     if (solved) { | ||||
|       display(grid) | ||||
|     } else { | ||||
|       println("No solution") | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private def _solve(inGrid: Array[Int]): Boolean = { | ||||
|     display(grid) | ||||
|  | ||||
|     if (DEBUG) print(grid) | ||||
|     if (!isValid()) { | ||||
|       if (DEBUG) println("  Grid is invalid") | ||||
|       return false | ||||
|     } | ||||
|  | ||||
|     val (x: Int, y: Int) = getNextEmpty() | ||||
|     if (x == -1) { | ||||
|       if (DEBUG) println("  Found solution") | ||||
|       return true | ||||
|     } | ||||
|     val numbers: Array[Int] = NUMBERS.diff(inGrid) | ||||
|  | ||||
|     if (DEBUG) println(s"  Values to test: " + numbers.mkString("[", ", ", "]")) | ||||
|  | ||||
|     for (n: Int <- numbers) { | ||||
|       if (DEBUG) println(s"    Testing $n") | ||||
|       grid(y)(x) = n | ||||
|       if (_solve(inGrid.appended(n))) { | ||||
|         if (DEBUG) println("    Found solution, collapsing call stack") | ||||
|         return true | ||||
|       } | ||||
|     } | ||||
|     grid(y)(x) = 0 | ||||
|  | ||||
|     if (DEBUG) println(s"  No solution for this configuration") | ||||
|     return false | ||||
|   } | ||||
|  | ||||
|   private def getNextEmpty(): (Int, Int) = { | ||||
|     for (y: Int <- 0 until _size) { | ||||
|       for (x: Int <- 0 until _size) { | ||||
|         if (grid(y)(x) == 0) { | ||||
|           return (x, y) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return (-1, -1) | ||||
|   } | ||||
|  | ||||
|   private def isValid(): Boolean = { | ||||
|     val values: Array[Int] = grid.reduce((a, b) => a.concat(b)).filter(_ != 0) | ||||
|     if (values.distinct.length != values.length) return false | ||||
|  | ||||
|     val diag1: Array[Int] = new Array(_size) | ||||
|     val diag2: Array[Int] = new Array(_size) | ||||
|     for (i: Int <- 0 until _size) { | ||||
|       val row: Array[Int] = grid(i) | ||||
|       val col: Array[Int] = grid.map(_(i)) | ||||
|       diag1(i) = row(i) | ||||
|       diag2(i) = col(_size - i - 1) | ||||
|  | ||||
|       if (!isLineValid(row)) { | ||||
|         if (DEBUG) println(s"  -> row $i is invalid: " + row.mkString("[", ", ", "]")) | ||||
|         return false | ||||
|       } | ||||
|       if (!isLineValid(col)) { | ||||
|         if (DEBUG) println(s"  -> column $i is invalid: " + col.mkString("[", ", ", "]")) | ||||
|         return false | ||||
|       } | ||||
|     } | ||||
|     if (!isLineValid(diag1)) { | ||||
|       if (DEBUG) println(s"  -> diag1 is invalid: " + diag1.mkString("[", ", ", "]")) | ||||
|       return false | ||||
|     } | ||||
|     if (!isLineValid(diag2)) { | ||||
|       if (DEBUG) println(s"  -> diag2 is invalid: " + diag2.mkString("[", ", ", "]")) | ||||
|       return false | ||||
|     } | ||||
|  | ||||
|     return true | ||||
|   } | ||||
|  | ||||
|   private def isLineValid(line: Array[Int]): Boolean = { | ||||
|     val sum: Int = line.sum | ||||
|     if (line.contains(0)) { | ||||
|       if (sum > SUM) return false | ||||
|     } else if (sum != SUM) return false | ||||
|  | ||||
|     return true | ||||
|   } | ||||
| } | ||||
|  | ||||
| object MagicSquareSolver { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val solver1: MagicSquareSolver = new MagicSquareSolver(Array( | ||||
|       Array(8, 0, 0), | ||||
|       Array(0, 0, 7), | ||||
|       Array(0, 9, 0) | ||||
|     )) with TextDisplay | ||||
|     //solver1.solve() | ||||
|     println() | ||||
|     /* | ||||
|     8,1,6 | ||||
|     3,5,7 | ||||
|     4,9,2 | ||||
|     */ | ||||
|  | ||||
|     val solver2: MagicSquareSolver = new MagicSquareSolver(Array( | ||||
|       Array(9, 0, 0), | ||||
|       Array(0, 0, 7), | ||||
|       Array(0, 8, 0) | ||||
|     )) with TextDisplay | ||||
|     //solver2.solve() | ||||
|     println() | ||||
|     /* | ||||
|     no solution | ||||
|     */ | ||||
|  | ||||
|     val solver3: MagicSquareSolver = new MagicSquareSolver(Array( | ||||
|       Array(0, 0, 2), | ||||
|       Array(0, 5, 7), | ||||
|       Array(0, 0, 0) | ||||
|     )) with GraphicsDisplay | ||||
|     solver3.solve() | ||||
|     /* | ||||
|     4,9,2 | ||||
|     3,5,7 | ||||
|     8,1,6 | ||||
|     */ | ||||
|  | ||||
|     val solver4: MagicSquareSolver = new MagicSquareSolver(Array( | ||||
|       Array(11, 0, 0, 20, 3), | ||||
|       Array(4, 12, 0, 0, 16), | ||||
|       Array(0, 5, 13, 21, 9), | ||||
|       Array(10, 0, 0, 14, 22), | ||||
|       Array(23, 6, 19, 2, 0), | ||||
|     )) with GraphicsDisplay | ||||
|     solver4.solve() | ||||
|   } | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/magic_squares/TextDisplay.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/magic_squares/TextDisplay.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| package magic_squares | ||||
|  | ||||
| trait TextDisplay extends Displayable { | ||||
|   override def display(g: Grid): Unit = { | ||||
|     for (y: Int <- g.indices) { | ||||
|       println(g(y).mkString(",")) | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/magic_squares/package.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/magic_squares/package.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| package object magic_squares { | ||||
|   type Grid = Array[Array[Int]] | ||||
| } | ||||
							
								
								
									
										61
									
								
								src/magic_squares/sudoku/GraphicsDisplay.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/magic_squares/sudoku/GraphicsDisplay.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| package magic_squares.sudoku | ||||
|  | ||||
| import hevs.graphics.FunGraphics | ||||
| import magic_squares.{Displayable, Grid} | ||||
|  | ||||
| import java.awt.{Color, Font} | ||||
| import javax.swing.SwingConstants | ||||
|  | ||||
| trait GraphicsDisplay extends Displayable { | ||||
|   private var _win: Option[FunGraphics] = None | ||||
|   private val WIDTH: Int = 400 | ||||
|   private val HEIGHT: Int = 400 | ||||
|   private val MARGIN: Int = 20 | ||||
|   private val FONT: Font = new Font("Arial", Font.PLAIN, 24) | ||||
|   override def display(g: Grid): Unit = { | ||||
|     if (_win.isEmpty) { | ||||
|       _win = Some(new FunGraphics(WIDTH, HEIGHT)) | ||||
|     } | ||||
|     val win: FunGraphics = _win.get | ||||
|     win.clear() | ||||
|     val size: Int = SudokuSolver.SIZE | ||||
|     val squareSize: Int = SudokuSolver.SQUARE_SIZE | ||||
|  | ||||
|     val w: Int = WIDTH - 2 * MARGIN | ||||
|     val h: Int = HEIGHT - 2 * MARGIN | ||||
|     val gridSize: Int = math.min(w, h) | ||||
|     val cellSize: Int = gridSize / size | ||||
|     val ox: Int = (WIDTH - gridSize) / 2 | ||||
|     val oy: Int = (HEIGHT - gridSize) / 2 | ||||
|  | ||||
|     win.setPenWidth(2) | ||||
|     win.drawRect(ox, oy, gridSize, gridSize) | ||||
|     for (i: Int <- 1 until size / squareSize) { | ||||
|       win.drawLine(ox + cellSize * squareSize * i, oy, ox + cellSize * squareSize * i, oy + gridSize) | ||||
|       win.drawLine(ox, oy + cellSize * squareSize * i, ox + gridSize, oy + cellSize * squareSize * i) | ||||
|     } | ||||
|     win.setPenWidth(1) | ||||
|     for (i: Int <- 1 until size) { | ||||
|       win.drawLine(ox + cellSize * i, oy, ox + cellSize * i, oy + gridSize) | ||||
|       win.drawLine(ox, oy + cellSize * i, ox + gridSize, oy + cellSize * i) | ||||
|     } | ||||
|  | ||||
|     for (y: Int <- 0 until size) { | ||||
|       for (x: Int <- 0 until size) { | ||||
|         val v: Int = g(y)(x) | ||||
|         if (v != 0) { | ||||
|           win.drawString( | ||||
|             (ox + cellSize * (x + 0.5)).toInt, | ||||
|             (oy + cellSize * (y + 0.5)).toInt, | ||||
|             v.toString, | ||||
|             FONT, | ||||
|             Color.BLACK, | ||||
|             SwingConstants.CENTER, | ||||
|             SwingConstants.CENTER | ||||
|           ) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     win.syncGameLogic(60) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										109
									
								
								src/magic_squares/sudoku/SudokuSolver.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/magic_squares/sudoku/SudokuSolver.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| package magic_squares.sudoku | ||||
|  | ||||
| import magic_squares.{Displayable, Grid} | ||||
|  | ||||
| import scala.collection.mutable.ArrayBuffer | ||||
|  | ||||
| abstract class SudokuSolver(initialGrid: Grid) extends Displayable { | ||||
|   protected var _initial: Grid = initialGrid | ||||
|   protected var grid: Grid = copy(_initial) | ||||
|   protected val SIZE: Int = SudokuSolver.SIZE | ||||
|   protected val SQUARE_SIZE: Int = SudokuSolver.SQUARE_SIZE | ||||
|   protected val DEBUG: Boolean = false | ||||
|   protected val NUMBERS: Array[Int] = Array.range(1, SIZE + 1) | ||||
|  | ||||
|   protected def print(grid: Grid): Unit = { | ||||
|     for (y: Int <- 0 until SIZE) { | ||||
|       println(grid(y).mkString(",")) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected def copy(grid: Grid): Grid = { | ||||
|     return grid.map(_.clone()) | ||||
|   } | ||||
|  | ||||
|   def solve(): Unit = { | ||||
|     val solved: Boolean = _solve() | ||||
|     if (solved) { | ||||
|       display(grid) | ||||
|     } else { | ||||
|       println("No solution") | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private def _solve(): Boolean = { | ||||
|     display(grid) | ||||
|  | ||||
|     if (DEBUG) print(grid) | ||||
|  | ||||
|     val (x: Int, y: Int) = getNextEmpty() | ||||
|     if (x == -1) { | ||||
|       if (DEBUG) println("  Found solution") | ||||
|       return true | ||||
|     } | ||||
|     val numbers: Array[Int] = getPossibleNumbers(x, y) | ||||
|     if (numbers.isEmpty) { | ||||
|       return false | ||||
|     } | ||||
|  | ||||
|     if (DEBUG) println(s"  Values to test: " + numbers.mkString("[", ", ", "]")) | ||||
|  | ||||
|     for (n: Int <- numbers) { | ||||
|       if (DEBUG) println(s"    Testing $n") | ||||
|       grid(y)(x) = n | ||||
|       if (_solve()) { | ||||
|         if (DEBUG) println("    Found solution, collapsing call stack") | ||||
|         return true | ||||
|       } | ||||
|     } | ||||
|     grid(y)(x) = 0 | ||||
|  | ||||
|     if (DEBUG) println(s"  No solution for this configuration") | ||||
|     return false | ||||
|   } | ||||
|  | ||||
|   private def getNextEmpty(): (Int, Int) = { | ||||
|     for (y: Int <- 0 until SIZE) { | ||||
|       for (x: Int <- 0 until SIZE) { | ||||
|         if (grid(y)(x) == 0) { | ||||
|           return (x, y) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return (-1, -1) | ||||
|   } | ||||
|  | ||||
|   private def getPossibleNumbers(x: Int, y: Int): Array[Int] = { | ||||
|     val inGrid: ArrayBuffer[Int] = grid(y).concat(grid.map(_(x))).to(ArrayBuffer) | ||||
|     val sx: Int = (x / 3) * 3 | ||||
|     val sy: Int = (y / 3) * 3 | ||||
|     for (dy: Int <- 0 until SQUARE_SIZE) { | ||||
|       for (dx: Int <- 0 until SQUARE_SIZE) { | ||||
|         inGrid.addOne(grid(sy + dy)(sx + dx)) | ||||
|       } | ||||
|     } | ||||
|     return NUMBERS.diff(inGrid.distinct) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object SudokuSolver { | ||||
|   val SIZE: Int = 9 | ||||
|   val SQUARE_SIZE: Int = SIZE / 3 | ||||
|  | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val solver1: SudokuSolver = new SudokuSolver(Array( | ||||
|       Array(5,3,0, 0,7,0, 0,0,0), | ||||
|       Array(6,0,0, 1,9,5, 0,0,0), | ||||
|       Array(0,9,8, 0,0,0, 0,6,0), | ||||
|  | ||||
|       Array(8,0,0, 0,6,0, 0,0,3), | ||||
|       Array(4,0,0, 8,0,3, 0,0,1), | ||||
|       Array(7,0,0, 0,2,0, 0,0,6), | ||||
|  | ||||
|       Array(0,6,0, 0,0,0, 2,8,0), | ||||
|       Array(0,0,0, 4,1,9, 0,0,5), | ||||
|       Array(0,0,0, 0,8,0, 0,7,9), | ||||
|     )) with GraphicsDisplay | ||||
|     solver1.solve() | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user