diff --git a/exercises/queen-attack/example.scala b/exercises/queen-attack/example.scala index 2bb4579b..8ae839be 100644 --- a/exercises/queen-attack/example.scala +++ b/exercises/queen-attack/example.scala @@ -1,28 +1,5 @@ -object Queens { - - def boardString(white: Option[Position], black: Option[Position]): String = { - - def rowString(row: Int): String = - (0 until 8).flatMap(col => tileString(row, col)).mkString - - def tileString(row: Int, col: Int): String = - tileChar(Position(row, col)).toString + tileSep(col) - - def tileChar(pos: Position): Char = - Some(pos) match { - case `white` => 'W' - case `black` => 'B' - case _ => '_' - } - - def tileSep(col: Int) = - if (col == 7) '\n' - else ' ' - - (0 until 8).flatMap(row => rowString(row)).mkString - } - - def canAttack(white: Position, black: Position): Boolean = { +object QueenAttack { + def canAttack(white: Queen, black: Queen): Boolean = { val canAttackHoriz = white.x == black.x val canAttackVert = white.y == black.y val deltaRow = Math.abs(white.x - black.x) @@ -33,5 +10,16 @@ object Queens { } } -case class Position(x: Int, y: Int) +case class Queen(x: Int, y: Int) + +object Queen { + def create(x: Int, y: Int): Option[Queen] = { + val min = 0 + val max = 7 + if (x >= min && x <= max && y >= min && y <= max) + Some(Queen(x, y)) + else + None + } +} diff --git a/exercises/queen-attack/src/main/scala/Queens.scala b/exercises/queen-attack/src/main/scala/Queens.scala deleted file mode 100644 index 9bddfd88..00000000 --- a/exercises/queen-attack/src/main/scala/Queens.scala +++ /dev/null @@ -1,8 +0,0 @@ -object Queens { - - def boardString(white: Option[Position], black: Option[Position]): String = ??? - - def canAttack(white: Position, black: Position): Boolean = ??? -} - -case class Position(x: Int, y: Int) diff --git a/exercises/queen-attack/src/test/scala/QueenAttackTest.scala b/exercises/queen-attack/src/test/scala/QueenAttackTest.scala new file mode 100644 index 00000000..9df44533 --- /dev/null +++ b/exercises/queen-attack/src/test/scala/QueenAttackTest.scala @@ -0,0 +1,71 @@ +import org.scalatest.{Matchers, FunSuite} + +/** @version 1.0.0 */ +class QueenAttackTest extends FunSuite with Matchers { + + private def create(x: Int, y: Int): Queen = { + Queen.create(x, y) match { + case Some(q) => q + case None => fail("Error creating queen") + } + } + + test("queen with a valid position") { + Queen.create(2,2) should be (Some(Queen(2,2))) + } + + test("queen must have positive rank") { + pending + Queen.create(-2,2) should be (None) + } + + test("queen must have rank on board") { + pending + Queen.create(8,4) should be (None) + } + + test("queen must have positive file") { + pending + Queen.create(2,-2) should be (None) + } + + test("queen must have file on board") { + pending + Queen.create(4,8) should be (None) + } + + test("can not attack") { + pending + QueenAttack.canAttack(create(2,4), create(6,6)) should be (false) + } + + test("can attack on same rank") { + pending + QueenAttack.canAttack(create(2,4), create(2,6)) should be (true) + } + + test("can attack on same file") { + pending + QueenAttack.canAttack(create(4,5), create(2,5)) should be (true) + } + + test("can attack on first diagonal") { + pending + QueenAttack.canAttack(create(2,2), create(0,4)) should be (true) + } + + test("can attack on second diagonal") { + pending + QueenAttack.canAttack(create(2,2), create(3,1)) should be (true) + } + + test("can attack on third diagonal") { + pending + QueenAttack.canAttack(create(2,2), create(1,1)) should be (true) + } + + test("can attack on fourth diagonal") { + pending + QueenAttack.canAttack(create(2,2), create(5,5)) should be (true) + } +} \ No newline at end of file diff --git a/exercises/queen-attack/src/test/scala/QueensTest.scala b/exercises/queen-attack/src/test/scala/QueensTest.scala deleted file mode 100644 index 15770945..00000000 --- a/exercises/queen-attack/src/test/scala/QueensTest.scala +++ /dev/null @@ -1,51 +0,0 @@ -import org.scalatest.{Matchers, FunSuite} - -class QueensTest extends FunSuite with Matchers { - test ("empty boardString") { - Queens.boardString(None, None) should equal( - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n") - } - - test("boardString") { - pending - Queens.boardString(Some(Position(2, 4)), Some(Position(6, 6))) should equal( - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ W _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ _ _\n" + - "_ _ _ _ _ _ B _\n" + - "_ _ _ _ _ _ _ _\n") - } - - test("canAttack - false") { - pending - Queens.canAttack(Position(2, 3), Position(4, 7)) should be (false) - } - - test("canAttack - vert attack") { - pending - Queens.canAttack(Position(2, 4), Position(2, 7)) should be (true) - } - - test("canAttack - horiz attack") { - pending - Queens.canAttack(Position(5, 4), Position(2, 4)) should be (true) - } - - test("canAttack - diag attack") { - pending - Queens.canAttack(Position(1, 1), Position(6, 6)) should be (true) - Queens.canAttack(Position(0, 6), Position(1, 7)) should be (true) - Queens.canAttack(Position(4, 1), Position(6, 3)) should be (true) - Queens.canAttack(Position(2, 2), Position(1, 3)) should be (true) - } -} diff --git a/testgen/src/main/scala/QueenAttackTestGenerator.scala b/testgen/src/main/scala/QueenAttackTestGenerator.scala new file mode 100644 index 00000000..b8780e41 --- /dev/null +++ b/testgen/src/main/scala/QueenAttackTestGenerator.scala @@ -0,0 +1,79 @@ +import java.io.File + +import testgen.TestSuiteBuilder._ +import testgen._ + +object QueenAttackTestGenerator { + def main(args: Array[String]): Unit = { + val file = new File("src/main/resources/queen-attack.json") + + def getPositionArgs(queenMap: Map[String, String]): String = + queenMap("position").stripPrefix("(").stripSuffix(")") + + def getQueen(labeledTest: LabeledTest): Map[String, String] = { + labeledTest.result("queen"). + asInstanceOf[Map[String, String]] + } + + def getWhiteQueen(labeledTest: LabeledTest): Map[String, String] = { + labeledTest.result("white_queen"). + asInstanceOf[Map[String, String]] + } + + def getBlackQueen(labeledTest: LabeledTest): Map[String, String] = { + labeledTest.result("black_queen"). + asInstanceOf[Map[String, String]] + } + + def getCanAttackArgs(labeledTest: LabeledTest): String = { + val whiteQueenArgs = getPositionArgs(getWhiteQueen(labeledTest)) + val blackQueenArgs = getPositionArgs(getBlackQueen(labeledTest)) + s"create($whiteQueenArgs), create($blackQueenArgs)" + } + + def toCreateExpected(labeledTest: LabeledTest): String = { + val expected = labeledTest.expected + expected match { + case Right(-1) => s"None" + case Right(0) => + val args = getPositionArgs(getQueen(labeledTest)) + s"Some(Queen($args))" + case _ => throw new IllegalStateException + } + } + + + def fromLabeledTest(argNames: String*): ToTestCaseData = + withLabeledTest { sut => + labeledTest => + val property = labeledTest.property + val (clazz, args, expected) = property match { + case "create" => + ("Queen", + getPositionArgs(getQueen(labeledTest)), + toCreateExpected(labeledTest)) + case "canAttack" => + ("QueenAttack", + getCanAttackArgs(labeledTest), + labeledTest.expected.fold(_ => "false", _.toString)) + case _ => throw new IllegalStateException() + } + val sutCall = s"""$clazz.$property($args)""" + TestCaseData(labeledTest.description, sutCall, expected) + } + + val code = + TestSuiteBuilder.build(file, fromLabeledTest(), + Seq(), + Seq(" private def create(x: Int, y: Int): Queen = {", + " Queen.create(x, y) match {", + " case Some(q) => q", + " case None => fail(\"Error creating queen\")", + " }", + " }")) + + println(s"-------------") + println(code) + println(s"-------------") + } +}