Created
April 27, 2015 16:28
-
-
Save arturaz/07b8d2ec7bd441aa4c5e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------ laurynas-tretjakovas-try-2/stupid/src/main/scala/stupid/Card.scala ------ | |
index 6d19063..51a8095 100755 | |
@@ -3,11 +3,13 @@ package stupid | |
import stupid.rank.Rank | |
import stupid.suite.Suite | |
-case class Card(suite: Suite, rank: Rank) extends Ordered[Card] { | |
- override def compare(that: Card): Int = Ordering.by[Card, (Rank, Suite)] { c => (c.rank, c.suite) }.compare(this, that) | |
-} | |
+case class Card(suite: Suite, rank: Rank) | |
object Card { | |
+ // Do not create orderings every time. | |
+ implicit val ordering = Ordering.by { (c: Card) => (c.rank, c.suite) } | |
+ | |
+ // This should be ValidationNel[String, Card] or String \/ Card | |
def fromString(card: String): Card = { | |
val suite = Suite.fromString(card.charAt(0).toString) | |
val rank = Rank.fromString(card.charAt(1).toString) | |
@@ -16,13 +18,18 @@ object Card { | |
def minCard(cards: Iterable[Card], trump: Suite): Option[Card] = { | |
cards.filter(_.suite != trump) match { | |
- case Nil => if (cards.isEmpty) None else Some(cards.min) | |
+ // Why are you sure this is a list? | |
+ case c if c.isEmpty => if (cards.isEmpty) None else Some(cards.min) | |
case c => Some(c.min) | |
} | |
} | |
- def minCardBiggerThan(defendingAgainst: Card, defendingWith: Iterable[Card], trump: Suite): Option[Card] = { | |
- val higherSameSuiteCards = defendingWith.filter(c => c.suite == defendingAgainst.suite && c.rank > defendingAgainst.rank) | |
+ def minCardBiggerThan( | |
+ defendingAgainst: Card, defendingWith: Iterable[Card], trump: Suite | |
+ ): Option[Card] = { | |
+ val higherSameSuiteCards = defendingWith.filter { c => | |
+ c.suite == defendingAgainst.suite && c.rank > defendingAgainst.rank | |
+ } | |
defendingAgainst.suite match { | |
case `trump` => minCard(higherSameSuiteCards, trump) | |
case _ => minCard(higherSameSuiteCards ++ defendingWith.filter(_.suite == trump), trump) | |
--- laurynas-tretjakovas-try-2/stupid/src/main/scala/stupid/GameState.scala --- | |
index 60036e8..19f1ba9 100755 | |
@@ -2,6 +2,26 @@ package stupid | |
import stupid.suite.Suite | |
+// No point in having an interface if all implementations have same things. | |
+// I guess this added a bit of type safety, but it added a lot of boilerplate | |
+// as well. | |
+// | |
+// Following trick can be used to reduce the boilerplate. | |
+trait GameStateObj { | |
+ case class S( | |
+ turn: Turn, attacker: Vector[Card], defender: Vector[Card], table: Table | |
+ ) extends GameState | |
+ | |
+ private def reinforceAfterFailedDefense(state: ReinforcingAfterFailedDefense.S): GameState = { | |
+ // this fails as expected | |
+// winnerOrFirstOffense(state) | |
+ ??? | |
+ } | |
+ private def winnerOrFirstOffense(state: StartingAttack.S): GameState = ??? | |
+} | |
+object ReinforcingAfterFailedDefense extends GameStateObj | |
+object StartingAttack extends GameStateObj | |
+ | |
sealed trait GameState { | |
def turn: Turn | |
@@ -24,6 +44,7 @@ case object Player2 extends Turn { | |
def nextTurn = Player1 | |
} | |
+ | |
case class Table(trump: Suite, | |
covered: Vector[Card], | |
notCovered: Vector[Card]) | |
----- laurynas-tretjakovas-try-2/stupid/src/main/scala/stupid/Stupid.scala ----- | |
index f275f68..4db94f2 100755 | |
@@ -61,6 +61,7 @@ object Stupid { | |
private def attemptPass(state: DefenderAttemptingPass): GameState = { | |
val passCard = if (state.attacker.size < state.table.notCovered.size + 1) None else Card.minCard(state.defender.filter(_.rank == state.table.notCovered.head.rank), state.table.trump) | |
+ // fold could be used here | |
passCard match { | |
case None => Defending(state.turn, state.attacker, state.defender, state.table) | |
case Some(card) => DefenderAttemptingPass( | |
@@ -75,6 +76,7 @@ object Stupid { | |
} | |
private def defend(state: Defending): GameState = { | |
+ // fold as well | |
state.table.notCovered.headOption match { | |
case Some(defendingAgainst) => | |
val defendWith = Card.minCardBiggerThan(defendingAgainst, state.defender, state.table.trump) | |
@@ -146,13 +148,13 @@ object Stupid { | |
Draw(state.turn, state.attacker, state.defender, state.table) | |
} else if (state.attacker.isEmpty) { | |
state.turn match { | |
- case _: Player1.type => Player1Won(state.turn, state.attacker, state.defender, state.table) | |
- case _: Player2.type => Player2Won(state.turn, state.attacker, state.defender, state.table) | |
+ case Player1 => Player1Won(state.turn, state.attacker, state.defender, state.table) | |
+ case Player2 => Player2Won(state.turn, state.attacker, state.defender, state.table) | |
} | |
} else if (state.defender.isEmpty) { | |
state.turn match { | |
- case _: Player1.type => Player2Won(state.turn, state.attacker, state.defender, state.table) | |
- case _: Player2.type => Player1Won(state.turn, state.attacker, state.defender, state.table) | |
+ case Player1 => Player2Won(state.turn, state.attacker, state.defender, state.table) | |
+ case Player2 => Player1Won(state.turn, state.attacker, state.defender, state.table) | |
} | |
} else { | |
doFirstOffense(state) | |
-- laurynas-tretjakovas-try-2/stupid/src/main/scala/stupid/suite/Suite.scala -- | |
index fbbec14..0d135f4 100755 | |
@@ -1,9 +1,8 @@ | |
package stupid.suite | |
-sealed trait Suite extends Ordered[Suite] { | |
+// It is better to use typeclasses if possible. | |
+sealed trait Suite { | |
def sort: Int | |
- | |
- override def compare(that: Suite): Int = sort.compare(that.sort) | |
} | |
case object Hearts extends Suite { | |
@@ -23,6 +22,9 @@ case object Spades extends Suite { | |
} | |
object Suite { | |
+ implicit val ordering = Ordering.by((_: Suite).sort) | |
+ | |
+ // This also can fail, needs to be validation/either | |
def fromString(suite: String): Suite = { | |
suite match { | |
case "H" => Hearts | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment