From a308ce13291659d604a9baa99322a14c35531984 Mon Sep 17 00:00:00 2001 From: beauvill Date: Sun, 24 Nov 2019 19:45:00 +0100 Subject: [PATCH] Assignment 6 done --- src/main/scala/streams/GameDef.scala | 13 +++++--- src/main/scala/streams/Solver.scala | 32 +++++++++++++++---- .../scala/streams/StringParserTerrain.scala | 15 +++++++-- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/scala/streams/GameDef.scala b/src/main/scala/streams/GameDef.scala index 4ae4eeb..bbe4317 100644 --- a/src/main/scala/streams/GameDef.scala +++ b/src/main/scala/streams/GameDef.scala @@ -79,7 +79,7 @@ trait GameDef { * This function returns the block at the start position of * the game. */ - def startBlock: Block = ??? + def startBlock: Block = Block(startPos, startPos) /** @@ -146,22 +146,25 @@ trait GameDef { * Returns the list of blocks that can be obtained by moving * the current block, together with the corresponding move. */ - def neighbors: List[(Block, Move)] = ??? + def neighbors: List[(Block, Move)] = + List((left, Left), (right, Right), (up, Up), (down, Down)) /** * Returns the list of positions reachable from the current block * which are inside the terrain. */ - def legalNeighbors: List[(Block, Move)] = ??? + def legalNeighbors: List[(Block, Move)] = neighbors.filter{ + case (b, _) => b.isLegal + } /** * Returns `true` if the block is standing. */ - def isStanding: Boolean = ??? + def isStanding: Boolean = b1 == b2 /** * Returns `true` if the block is entirely inside the terrain. */ - def isLegal: Boolean = ??? + def isLegal: Boolean = terrain(b1) && terrain(b2) } } diff --git a/src/main/scala/streams/Solver.scala b/src/main/scala/streams/Solver.scala index 0b65d86..5e81eca 100644 --- a/src/main/scala/streams/Solver.scala +++ b/src/main/scala/streams/Solver.scala @@ -8,7 +8,7 @@ trait Solver extends GameDef { /** * Returns `true` if the block `b` is at the final position */ - def done(b: Block): Boolean = ??? + def done(b: Block): Boolean = b.b1 == goal && b.isStanding /** * This function takes two arguments: the current block `b` and @@ -26,7 +26,10 @@ trait Solver extends GameDef { * It should only return valid neighbors, i.e. block positions * that are inside the terrain. */ - def neighborsWithHistory(b: Block, history: List[Move]): LazyList[(Block, List[Move])] = ??? + def neighborsWithHistory(b: Block, history: List[Move]): LazyList[(Block, List[Move])] = { + lazy val result = b.legalNeighbors.map({pair=> (pair._1, pair._2 +: history)}) + result.to(LazyList) + } /** * This function returns the list of neighbors without the block @@ -34,7 +37,9 @@ trait Solver extends GameDef { * make sure that we don't explore circular paths. */ def newNeighborsOnly(neighbors: LazyList[(Block, List[Move])], - explored: Set[Block]): LazyList[(Block, List[Move])] = ??? + explored: Set[Block]): LazyList[(Block, List[Move])] = { + neighbors.filter(n => !explored.contains(n._1)) + } /** * The function `from` returns the lazy list of all possible paths @@ -60,18 +65,28 @@ trait Solver extends GameDef { * construct the correctly sorted lazy list. */ def from(initial: LazyList[(Block, List[Move])], - explored: Set[Block]): LazyList[(Block, List[Move])] = ??? + explored: Set[Block]): LazyList[(Block, List[Move])] = { + if (initial.isEmpty) LazyList.empty + else { + val more = for { + pair <- initial + next <- newNeighborsOnly (neighborsWithHistory(pair._1, pair._2), explored) + } yield next + initial #::: from(more, explored ++ (more.map(_._1))) + } + } + /** * The lazy list of all paths that begin at the starting block. */ - lazy val pathsFromStart: LazyList[(Block, List[Move])] = ??? + lazy val pathsFromStart: LazyList[(Block, List[Move])] = from(neighborsWithHistory(startBlock, List[Move]()), Set(startBlock)) /** * Returns a lazy list of all possible pairs of the goal block along * with the history how it was reached. */ - lazy val pathsToGoal: LazyList[(Block, List[Move])] = ??? + lazy val pathsToGoal: LazyList[(Block, List[Move])] = pathsFromStart.filter({case (b, m) => done(b)}) /** * The (or one of the) shortest sequence(s) of moves to reach the @@ -81,5 +96,8 @@ trait Solver extends GameDef { * the first move that the player should perform from the starting * position. */ - lazy val solution: List[Move] = ??? + lazy val solution: List[Move] = pathsToGoal.headOption match { + case None => List.empty + case Some(pair) => (pair._2).reverse + } } diff --git a/src/main/scala/streams/StringParserTerrain.scala b/src/main/scala/streams/StringParserTerrain.scala index 12960c6..020bfff 100644 --- a/src/main/scala/streams/StringParserTerrain.scala +++ b/src/main/scala/streams/StringParserTerrain.scala @@ -50,7 +50,13 @@ trait StringParserTerrain extends GameDef { * a valid position (not a '-' character) inside the terrain described * by `levelVector`. */ - def terrainFunction(levelVector: Vector[Vector[Char]]): Pos => Boolean = ??? + def terrainFunction(levelVector: Vector[Vector[Char]]): Pos => Boolean = { + case Pos(x,y) => (for{ + row <- levelVector.lift(x) + ch <- row.lift(y) + if(ch != '-') + } yield ch).isDefined + } /** * This function should return the position of character `c` in the @@ -60,7 +66,12 @@ trait StringParserTerrain extends GameDef { * Hint: you can use the functions `indexWhere` and / or `indexOf` of the * `Vector` class */ - def findChar(c: Char, levelVector: Vector[Vector[Char]]): Pos = ??? + def findChar(c: Char, levelVector: Vector[Vector[Char]]): Pos = { + val ys = levelVector.map(_.indexOf(c)) + val x = ys.indexWhere(_ >= 0) + + Pos(x, ys(x)) + } private lazy val vector: Vector[Vector[Char]] = Vector(level.split("\r?\n").map(str => Vector(str: _*)).toIndexedSeq: _*)