So I am trying to create a game and the user can has to choose 1 hero from a pool of heroes. How should I create the object of the user's chosen hero? Basically I am trying to create an object according to the user input
Edit:
I realize that just putting one paragraph is not enough and that I should add my code structure as well.
Currently I have a hero class and every other hero extends from this class, so I am trying to do something like this
class Hero {
}
class Bob extends Hero{ //Bob is one of the heroes that the user can choose
def skill1() { //the skills that Bob can use
}
}
class Player() {
val hero //player's hero option will be stored here
}
class Game { //gamedata will be stored here
val player: Player = new Player()
}
class Controller {
def selectHero { //this is where the user inputs a number from 1 to 10 and the app will create a hero object
}
}
I am stuck at the selectHero method and do not know how to proceed. I tried doing something like this:
val _hero1: Hero = (
if (option1 == 1) {
new Bob()
}
else if (option1 == 2) {
new James()
}
else if (option1 == 3) {
new Jimmy()
}
else {
null
}
)
But I ended up not being able to access their skills since parent classes cannot access the methods of child classes, can anyone help?
Here is an idea:
You can read from stdin a number and create as many heroes as you want until you want to break the loop. Using inheritance and polymorphism, your call to skills() will dynamically bound to the class of that hero object.
There are a lot of improvements you can do from here:
You still have to use a try-catch block to avoid a NumberFormatException, when inputing something that is not an Int.
You need to define toString() on every class that extends Hero. Currently when printing heroes, we get the objects, not their string representations.
You would be better with a Hero factory method than with a pattern match.
Consider making the Hero classes into objects if they are unique, or consider making them case classes if you need to pattern match on them.
import scala.collection.mutable
import scala.io.StdIn.readLine
import scala.util.control.Breaks.{break, breakable}
object Test extends App {
abstract class Hero {
def skills(): Unit
}
class Bob extends Hero {
def skills(): Unit =
println("This is Bob. His skills are partying like a Hero")
}
class James extends Hero {
def skills(): Unit =
println("This is James. His skills are drinking like a Hero")
}
class Jimmy extends Hero {
def skills(): Unit =
println("This is Jimmy. His skills are gaming like a Hero")
}
object Controller {
def selectHero(option: Int): Hero = option match {
case 1 => new Bob()
case 2 => new James()
case 3 => new Jimmy()
case _ => break
}
}
val heroes = mutable.Set.empty[Hero]
breakable {
while (true) {
val hero = Controller.selectHero(readLine().toInt)
hero.skills()
heroes += hero
}
}
println(heroes)
// process heroes further
println("done")
}
Output based on input:
1
This is Bob. His skills are partying like a Hero
2
This is James. His skills are drinking like a Hero
3
This is Jimmy. His skills are gaming like a Hero
4
HashSet(Test$James#337d0578, Test$Jimmy#61a485d2, Test$Bob#69d9c55)
done
Related
I am creating a command-line app where it reads what the user puts in and then makes a POST request with that data (I've just started).
My problem is I've never seen a class extended like this before and it's throwing me off. How do I get the values from CommandApp so that I can use it in my Main Object?
import cats.implicits._
import com.monovore.decline._
object Main extends CommandApp(name = "hello-world",
header = "Says hello!",
main = {
val userOpt = Opts.option[String]("target", help = "Person to greet.").withDefault("world")
val quietOpt = Opts.flag("quiet", help = "Whether to be quiet.").orFalse
(userOpt, quietOpt).mapN { (user, quiet) =>
if (quiet) println("...")
else println(s"Hello $user!")
}
}) {
// How do I get the value from user into here.
// Eventually I will want to use that user data variable for a POST request.
}
If I understood you correctly you want to pattern match the case class Parameters of CommandApp from the main Object?
In Scala this isn't directly possible since Main is a child of CommandApp and not the other way round (you can only pattern match to child case classes). But you can use traits:
Declare a new Trait that has no direct function
CommandApp has to inherit that trait
Convert your main Object to that trait type
Pattern matching
Since i don't have your class definitions, i wrote a small example. Let's say your class looks like this:
case class Test(str:String)
class MainTest extends Test("Hello World!")
and you want to access the str value of Test like this:
val t = new MainTest()
t match{
case Test(str) => println(str)
case _ => println("Could not match")
}
This would not work since MainTest is not a case class and therefore cannot be pattern matched. But if you declare a new trait which Test inherits:
trait InheritanceTrait
case class Test(str:String) extends InheritanceTrait
class MainTest extends Test("Hello World!")
You can pattern match a MainTest object by casting it to a InheritanceTrait, which has a pattern-matching child class (therefore can be pattern matched):
val t = new MainTest()
t.asInstanceOf[InheritanceTrait] match{
case Test(str) => println(str)
case _ => println("Could not match")
} //prints "Hello World!"
If you don't want to or simply can't declare a super class of CommandApp you could use a dirty alternative by converting t to the Any type, since every class inherits from Any. Would work just as fine.
My example then would like this:
object Main{
case class Test(str:String)
class MainTest extends Test("Hello World!")
def main(args:Array[String]){
val t = new MainTest()
t.asInstanceOf[Any] match{
case Test(str) => println(str)
case _ => println("Could not match")
}
}
}
I hope this solved your problem!
It should be noted that CommandApp isn't a case class, it's a regular abstract class.
The intended use of CommandApp appears to be that your entire program goes into main and when main completes, your program is done. This is evidenced by the class having a name ending in App (c.f. IOApp) and has main.
So what you would do is define a function elsewhere which takes whatever values you've validated that you want to use (e.g user in this case) as arguments and does stuff with them, e.g.
// Disclaimer: I'm guessing from the code that userOpt is Option[String]
def sendUserAsPostRequest(user: String): Unit = {
// sending the user as a POST is left as an exercise for the reader
}
You can place that function in Main or in a different object (or in a different class as long as your main constructs an instance of that class). You're main would then look like (I'm assuming that for this, you're not interested in quiet):
main = {
val userOpt = Opts.option[String]("target", help = "Person to greet.").withDefault("world")
userOpt.map(sendUserAsPostRequest)
}
I am relatively new to scala so please bear me if I asked silly questions.
I have a requirement where I need to invoke a method run time.
I have a trait which is being extended by two classes
trait Animal {
def walk():DataFrame
}
This is extended by two classes.
class Dog(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
class Cat(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
Now from a config file I will get a list of these class names
Lets say like this
val animals = ["com.xy.Dog","com.xy.Cat"]
I need to invoke these classes and execute walk methods.
Can I do something like this?
animals.forEach{ animalString =>
val animalObject = Class.forName(animalString ).newInstance().asInstanceOf(Animal)
animalObject.walk
}
There are a few issues, let's take them one by one:
To build a list in scala you need to do:
val animals = List("com.xy.Dog", "com.xy.Cat")
The forEach method is actually foreach, so there's a small typo. Finally, when you call the newInstance you should get the appropriate constructor before that, otherwise it will use the default one.
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.getConstructor(classOf[DataFrame]) // Get the constructor for a DataFrame argument
.newInstance(dataframe) // Pass the dataframe instance
.asInstanceOf[Animal]
animalObject.walk
}
I've made a couple of small changes to the code for you to see it working. You can run the app to see the output:
class Dog extends Animal {
def walk(): Unit = { println("I'm a dog.") }
}
class Cat extends Animal {
def walk(): Unit = { println("I'm a cat.") }
}
object AnimalTest extends App {
val animals = List("com.xy.Dog", "com.xy.Cat")
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.newInstance()
.asInstanceOf[Animal]
animalObject.walk
}
}
Note that I've removed the constructor arguments here to easily build instances. The rest is about the same. I hope this helps you.
I have an object that contains one or more case classes and associated methods. I would like to reuse this case class within another object (which has similar characteristics as this object but also some differentiating methods).
private object abc {
/* ... */
case class xyz(..) { def someFunc(){} }
object xyz { def apply() {} }
}
private object extendabc {
// How to reuse case class xyz here?
}
If you want to just access you can use this kind of a code .
private object abc {
case class xyz() {
def someFunc(){}
}
object xyz { }
}
private object extendabc {
val a = new abc.xyz()
a.someFunc()
}
You need to call this way because xyz is a nested member of the object abc .
Look here.
Also please note you cannot define a apply method in the companion object of a case class as it provides the exact same apply() method (with the same signature.
My current project is using Java. we push business logics to enum which represents particular state ( New, Registered and so on). In scala, I just wonder that is it a good idea to use case object to act as state ? what is the drawback.
One simple example
trait State {
def read() : Try[String] = {
Failure(new IllegalStateException("too young to read"))
}
}
case object child extends State
case object young extends State {
override def read() : Try[String] = {
Success("young people read book")
}
}
case object elder extends State {
override def read() : Try[String] = {
Success("elder people read book")
}
}
class Person(state : State) {
def read() : Try[String] = {
state.read()
}
}
It can be and in fact it is pretty common pattern (accompanied with sealed trait by the way), but implementation I've seen usually move any actions out of state and use case objects as tags that signify current state, alongside with case classes that may store some state data:
sealed trait State
case class Connected(messagesProcessed: Long) extends State
case object Connecting extends State
case object Disconnected extends State
def foo() = state match {
case Connected(count) => "do something"; state = Connected(count + 1) // could be .copy(..)
case Connecting => "wait patiently"
case Disconnected => "trigger reconnection"
}
Reasoning behind using case classes to store data (versus storing it in plain old class fields) is that different states may have different sets of variables and with case classes it is easier to comprehend current working set.
I'm new to scala and trying to figure things out as I go. I'm working with the Play 2.x framework and using Scala to build my app. I have a route defined
GET /:tableName controllers.Application.getTable(tableName)
In the controller I would like to take the name of the table and use it as I would the class. For example in the db if have a table named People. I would like it to map to the Slick model for People that has the function getAll. I looked into typeof[t], but couldn't get it to work. below it is an example of what I would like to do.
def getTable(tableName: String) = Action {
Ok(Json.toJson(typeOf[tableName].getAll))
}
You're going to need a bit more than that, to get this accomplished ;) First of all, Slick requires a DB session, so that needs to be handled somewhere. Meaning a Slick Table getAll won't work by itself.
I would do something like this (sorry, typing this up without an IDE, so it may not compile):
case class Person(...)
object People extends Table[Person](PeopleDAO.table) {
def * = ...
}
trait DAO[T] {
val table: String
def getAll: Seq[T]
}
object PeopleDAO extends DAO[Person] {
override val table = "people"
def getAll = {
DB withSession { implicit session =>
Query(People).list
}
}
}
object Controller {
def getTable(tableName: String) = Action {
val dao: DAO[_] = tableName.toLowerCase match {
case PeopleDAO.table => PeopleDAO
case _ => throw new IllegalArgumentException("Not a valid table.")
}
Ok(Json.toJson(dao.getAll))
}
}