Skip to content

Instantly share code, notes, and snippets.

@d-smith
Created May 1, 2011 19:40
Show Gist options
  • Save d-smith/950796 to your computer and use it in GitHub Desktop.
Save d-smith/950796 to your computer and use it in GitHub Desktop.
Game Sample - Learn Scala in 2 Days
trait Item {
val weight: Int
val description: String
val name: String
}
class Action
case class Pickup(item: Option[Item]) extends Action
case class Drop(item: Option[Item]) extends Action
case class Move(to: Location) extends Action
case class Unlock extends Action
abstract class Armor(protection: Int) extends Item
case class SimpleArmor(name: String, protection: Int, weight: Int) extends Armor(protection) {
val description = "SImple armor"
}
case class Person(name: String, health: Int, inventory: Inventory) {
def pickup(item: Item) : Person = {
copy(inventory = inventory.add(item))
}
def drop(item: Item) : Person = {
copy(inventory = inventory.remove(item))
}
}
case class Path(action: String, from: Location, to: Location)
case class Location(name: String, description: String, items: List[Item])
case class GameMap(locations: Set[Location], paths: Set[Path]) {
val currentLocation = locations.headOption
def addLocation(location: Location): GameMap = {
copy(locations + location)
}
def addPath(path: Path): GameMap = {
copy(paths = paths + path)
}
def findPath(fromLocation: Location, toLocation: Location): Option[Path] = {
val path = paths.collect {
case p: Path if p.from == fromLocation && p.to == toLocation => p
}
path.headOption
}
def findMoves(current: Location): Set[Path] = {
val moves = paths.collect {
case p: Path if p.from == current => p
}
moves
}
}
object GameMap {
def findLocation(name: String, locations: Set[Location]): Location = {
val loc = locations.collect {
case l: Location if l.name == name => l
}
val found = loc.headOption
found match {
case None => new Location("limbo", "limbo", List[Item]())
case _ => found.head
}
}
//Use the apply method in the companion object to build the initial map - doesn't really
//belong here...
def apply() = {
val initialMap =
<gamemap>
<locations>
<location name="dungeon" desc="ye ancient dungeon"/>
<location name="subdungeon" desc="dankest pit"/>
<location name="coffee bar" desc="coffee awaits"/>
</locations>
<paths>
<path from="dungeon" to="subdungeon" action="descend to the dungeon's dungeon"/>
<path from="subdungeon" to="dungeon" action="ascend to the dungeon"/>
<path from="dungeon" to="coffee bar" action="coffee break"/>
<path from="coffee bar" to="dungeon" action="back to torture"/>
</paths>
</gamemap>
val locNodes = initialMap \\ "location"
val theLocations = locNodes.map {
case n: xml.Node => new Location(n \ "@name" text,
n \ "@desc" text, List[Item]())
}.toSet
val pathNodes = initialMap \\ "path"
val thePaths = pathNodes.map {
case n: xml.Node => new Path(n \ "@action" text,
findLocation(n \ "@from" text, theLocations.toSet),
findLocation(n \ "@to" text, theLocations))
}.toSet
new GameMap(theLocations, thePaths)
}
}
case class GameState(person: Person, location: Location, gameMap: GameMap){
def findMoves() : Set[Path] = {
gameMap.findMoves(location)
}
}
object GameHandlers {
val GameHandlerPickup: PartialFunction[(GameState,Action),GameState] = {
case(gameState @ GameState(person, _,_), Pickup(Some(item))) =>
gameState.copy(person = person.pickup(item))
}
val GameHandlerDrop: PartialFunction[(GameState,Action),GameState] = {
case(gameState @ GameState(person, _,_), Drop(Some(item))) =>
gameState.copy(person = person.drop(item))
}
val GameHandlerMove: PartialFunction[(GameState,Action),GameState] = {
case(gameState @ GameState(_, location, gameMap), Move(to)) => {
val path = gameState.gameMap.findPath(location, to)
path match {
case None => gameState
case _ => gameState.copy(location = to)
}
}
}
val GameHandlerAll = GameHandlerPickup.orElse(GameHandlerDrop.orElse(GameHandlerMove))
}
case class Inventory(items: Set[Item]) {
def add(item: Item) : Inventory = {
new Inventory(items + item)
}
def remove(item: Item) : Inventory = {
new Inventory(items - item)
}
//partial function
def weapons: Set[Weapon] = items.collect {
case weapon: Weapon => weapon
}
def findWeapon(): Option[Item] = {
weapons.headOption
}
}
abstract class Weapon(damage: Int, durability: Int) extends Item
case class SimpleSword(name: String, length: Int, durability: Int, damage: Int,
weight: Int) extends Weapon(damage, durability ) {
val description = "Simple sword"
def actions() : Set[String] = {
Set("swing", "chop", "stap","clean")
}
}
object DungeonGame {
//Main game loop - verified this is tail recursive
def gameloop(gs: GameState): GameState = {
println("You are in " + gs.location)
val moves = gs.findMoves()
println("You can move...")
for ((move, i) <- moves.zipWithIndex) {
println(i + ": " + move.action)
}
print("Tell me your move: ")
val response: Int = try {
readLine.toInt
} catch {
case _ => -1
}
val movesArray = moves.toArray
if (response == -1 || response >= movesArray.size) {
println("Concentrate and try again")
gameloop(gs)
} else {
val pick = movesArray(response.toInt)
val action = new Move(pick.to)
gameloop(GameHandlers.GameHandlerAll.apply(gs, action))
}
}
def main(args: Array[String]) = {
println("DungeonMan! Are you enquiring about an challenge?")
val gameMap = GameMap()
val peasant = new Person("peon", 1, Inventory(Set()))
val gs = new GameState(peasant, gameMap.locations.head, gameMap)
gameloop(gs)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment