Skip to content

Instantly share code, notes, and snippets.

@arturaz
Created April 27, 2015 16:28
Show Gist options
  • Save arturaz/07b8d2ec7bd441aa4c5e to your computer and use it in GitHub Desktop.
Save arturaz/07b8d2ec7bd441aa4c5e to your computer and use it in GitHub Desktop.
------ 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