1
1
Fork 0

Removed solutions from exercise descriptions

This commit is contained in:
Svetlana Isakova 2020-03-22 16:01:40 +01:00
parent fccad93663
commit 27627f0ce4
46 changed files with 46 additions and 2501 deletions

View File

@ -5,36 +5,4 @@ classes. Create an abstract class `WithParams` with class parameters `val i:
Int` and `var s: String = ""`. Inherit a class `Concrete` from `WithParams`.
Provide constructors for both that use `atomictest.Trace` to show the class
name and arguments. Create an instance of `Concrete` and verify the order of
the constructor calls.
```kotlin
// Abstract/AbsExercise1.kt
package abstractclasses
import atomictest.*
private val trace = Trace()
abstract class WithParams(
val i: Int,
var s: String = ""
) {
init {
trace("WithParams $i $s")
}
}
class Concrete(i: Int, s: String):
WithParams(i, s) {
init {
trace("Concrete $i $s")
}
}
fun main() {
Concrete(11, "One Louder")
trace eq """
WithParams 11 One Louder
Concrete 11 One Louder
"""
}
```
the constructor calls.

View File

@ -14,54 +14,4 @@ Add a function `tune()` that takes an `Instrument` parameter and plays that
In `main()`, create an `orchestra` which is a `List<Instrument>` containing an
instance of each type of `Instrument`. Call `tune()` for each `Instrument` in
the `orchestra`, and validate the results using `Trace`.
```kotlin
// Abstract/AbsExercise2.kt
package abstractclasses2
import atomictest.*
private val trace = Trace()
enum class Note {
A, B, C, D, E, F, G
}
abstract class Instrument(val name: String) {
abstract fun play(n: Note)
}
open class Wind : Instrument("Wind") {
override fun play(n: Note) {
trace("$name blow $n")
}
}
class Percussion : Instrument("Percussion") {
override fun play(n: Note) {
trace("$name strike $n")
}
}
class Stringed : Instrument("Stringed") {
override fun play(n: Note) {
trace("$name pluck $n")
}
}
fun tune(i: Instrument) = i.play(Note.C)
fun main() {
val orchestra = listOf(
Wind(),
Percussion(),
Stringed()
)
orchestra.forEach { tune(it) }
trace eq """
Wind blow C
Percussion strike C
Stringed pluck C
"""
}
```
the `orchestra`, and validate the results using `Trace`.

View File

@ -4,72 +4,4 @@ Add classes to the previous example: `Bowed` inherits from `Stringed` and uses
`bow` instead of `plucked` in the output, while `Brass` and `Reed` inherit
from `Wind`. `Brass` and `Reed` do not override `play()`. Make the necessary
modifications to allow each class to accept a `String` argument containing the
class name.
```kotlin
// Abstract/AbsExercise3.kt
package abstractclasses3
import atomictest.*
private val trace = Trace()
enum class Note {
A, B, C, D, E, F, G
}
abstract class Instrument(val name: String) {
abstract fun play(n: Note)
}
open class Wind(name: String? = null) :
Instrument(name ?: "Wind") {
override fun play(n: Note) {
trace("$name blow $n")
}
}
open class Percussion(name: String? = null) :
Instrument(name ?: "Percussion") {
override fun play(n: Note) {
trace("$name strike $n")
}
}
open class Stringed(name: String? = null) :
Instrument(name ?: "Stringed") {
override fun play(n: Note) {
trace("$name pluck $n")
}
}
class Bowed : Stringed("Bowed") {
override fun play(n: Note) {
trace("$name bow $n")
}
}
class Brass : Wind("Brass")
class Reed : Wind("Reed")
fun tune(i: Instrument) = i.play(Note.C)
fun main() {
val orchestra = listOf(
Wind(),
Percussion(),
Stringed(),
Bowed(),
Brass(),
Reed()
)
orchestra.forEach { tune(it) }
trace eq """
Wind blow C
Percussion strike C
Stringed pluck C
Bowed bow C
Brass blow C
Reed blow C
"""
}
```
class name.

View File

@ -5,35 +5,4 @@ compare a `Trace` object to a multiline `String`. Create a global `private`
`val trace` initialized to `Trace()`. Create a class `A`; inside its `init`,
and call `trace(className)` to append the name of the class to `trace`.
Inherit `B` from `A` and `C` from `B`, and give them similar `init`s. Create
an instance of `C` to see the initialization order.
```kotlin
// BaseClassInit/BCIExercise1.kt
package baseclassinit
import atomictest.*
private val trace = Trace()
open class A {
init {
trace("A")
}
}
open class B : A() {
init {
trace("B")
}
}
class C : B() {
init {
trace("C")
}
}
fun main() {
C()
trace eq "A B C"
}
```
an instance of `C` to see the initialization order.

View File

@ -9,80 +9,4 @@ Create a class `Plate` and inherit `DinnerPlate` from it. Create a class
`Custom` (as in "a cultural tradition"), and inherit `PlaceSetting` from it.
Inside `PlaceSetting`, create properties containing `Spoon`, `Fork`, `Knife`
and `DinnerPlate`, in that order. Create an instance of `PlaceSetting` to see
the initialization order.
```kotlin
// BaseClassInit/BCIExercise2.kt
package baseclassinit
import atomictest.*
private val trace = Trace()
open class Plate {
init {
trace("Plate")
}
}
class DinnerPlate : Plate() {
init {
trace("DinnerPlate")
}
}
open class Utensil {
init {
trace("Utensil")
}
}
class Spoon : Utensil() {
init {
trace("Spoon")
}
}
class Fork : Utensil() {
init {
trace("Fork")
}
}
class Knife : Utensil() {
init {
trace("Knife")
}
}
open class Custom() {
init {
trace("Custom")
}
}
class PlaceSetting : Custom() {
val spoon = Spoon()
val fork = Fork()
val knife = Knife()
val plate = DinnerPlate()
init {
trace("PlaceSetting")
}
}
fun main() {
PlaceSetting()
trace eq """
Custom
Utensil
Spoon
Utensil
Fork
Utensil
Knife
Plate
DinnerPlate
PlaceSetting
"""
}
```
the initialization order.

View File

@ -2,81 +2,4 @@
Modify the previous exercise so that every class has a class argument of `i:
Int`, and add this to the end of the `String` in the call to `trace()` inside
each `init`.
```kotlin
// BaseClassInit/BCIExercise3.kt
package baseclassinit
import atomictest.*
private val trace = Trace()
open class Plate1(i: Int) {
init {
trace("Plate $i")
}
}
class DinnerPlate1(i: Int) : Plate1(i) {
init {
trace("DinnerPlate $i")
}
}
open class Utensil1(i: Int) {
init {
trace("Utensil $i")
}
}
class Spoon1(i: Int) : Utensil1(i) {
init {
trace("Spoon $i")
}
}
class Fork1(i: Int) : Utensil1(i) {
init {
trace("Fork $i")
}
}
class Knife1(i: Int) : Utensil1(i) {
init {
trace("Knife $i")
}
}
// A cultural way of doing something:
open class Custom1(i: Int) {
init {
trace("Custom $i")
}
}
class PlaceSetting1(i: Int) : Custom1(i) {
val spoon = Spoon1(i)
val fork = Fork1(i)
val knife = Knife1(i)
val plate = DinnerPlate1(i)
init {
trace("PlaceSetting $i")
}
}
fun main() {
PlaceSetting1(9)
trace eq """
Custom 9
Utensil 9
Spoon 9
Utensil 9
Fork 9
Utensil 9
Knife 9
Plate 9
DinnerPlate 9
PlaceSetting 9
"""
}
```
each `init`.

View File

@ -3,52 +3,4 @@
Modify `ModelingMI.kt` by adding `fun resize(scale: Int): Int` to `Rectangle`,
which just returns `scale`. Add a `fun rightClicked(): Boolean` to
`MouseManager`. Call the new functions in `main()` and verify that `Button`
needs no modifications to support the new interfaces.
```kotlin
// ClassDelegation/ClassDelegEx1.kt
package classdelegationex1
import atomictest.eq
interface Rectangle {
fun paint(): Int
fun resize(scale: Int): Int
}
class ButtonImage(
val width: Int,
val height: Int
) : Rectangle {
override fun paint() = width * height
override fun resize(scale: Int) = scale
}
interface MouseManager {
fun clicked(): Boolean
fun hovering(): Boolean
fun rightClicked(): Boolean
}
class UserInput : MouseManager {
override fun clicked() = true
override fun hovering() = true
override fun rightClicked() = true
}
class Button(
val width: Int,
val height: Int,
val image: Rectangle =
ButtonImage(width, height),
val input: MouseManager = UserInput()
) : Rectangle by image, MouseManager by input
fun main() {
val button = Button(10, 5)
button.paint() eq 50
button.clicked() eq true
button.hovering() eq true
button.resize(10) eq 10
button.rightClicked() eq true
}
```
needs no modifications to support the new interfaces.

View File

@ -20,54 +20,4 @@ Interface." Modify the rest of the code to use `MyType` whenever possible,
rather than `MyClass`, and rename `useMyClass()` to `useMyType()`.
Now modify `MyClassAdaptedForLib` so that `field` is `private` and is the
delegate for `MyType`.
```kotlin
// ClassDelegation/ClassDelegEx2.kt
package classdelegationex2
import usefullibrary.*
import atomictest.*
private val trace = Trace()
interface MyType {
fun g()
fun h()
}
class MyClass: MyType {
override fun g() = trace("g()")
override fun h() = trace("h()")
}
fun useMyType(mt: MyType) {
mt.g()
mt.h()
}
class MyClassAdaptedForLib(
private val field: MyClass
) : LibType, MyType by field {
override fun f1() = field.h()
override fun f2() = field.g()
}
fun adapt(mc: MyClass) =
MyClassAdaptedForLib(mc)
fun main() {
val library = UsefulLibrary()
val mc = adapt(MyClass())
library.utility1(mc)
library.utility2(mc)
useMyType(mc)
trace eq """
h()
g()
g()
h()
g()
h()
"""
}
```
delegate for `MyType`.

View File

@ -23,66 +23,4 @@ Create a class `AA` that implements `A`, producing the value `1` for `x` and
`z`, and tracing `"AA.u()"` for `u()` and `"AA.v()"` for `v()`. Create a
similar implementation `BB` implementing `B`. Now create a class `Delegation`
which delegates to both `A` and `B`. IntelliJ or the compiler will tell you
what you need to do to solve the collisions.
```kotlin
// ClassDelegation/ClassDelegEx3.kt
package classdelegationex3
import atomictest.*
private val trace = Trace()
interface A {
val x: Int
val z: Int
fun u()
fun v()
}
interface B {
val y: Int
val z: Int
fun v()
fun w()
}
class AA : A {
override val x = 1
override val z = 1
override fun u() = trace("AA.u()")
override fun v() = trace("AA.v()")
}
class BB : B {
override val y = 1
override val z = 1
override fun v() = trace("BB.v()")
override fun w() = trace("BB.w()")
}
class Delegation(val a: A, val b: B) :
A by a, B by b {
override val z = a.z + b.z
override fun v() {
trace("Delegation.v()")
a.v()
b.v()
trace("Delegation.z: $z")
}
}
fun main() {
val d = Delegation(AA(), BB())
d.u()
d.v()
d.w()
trace eq """
AA.u()
Delegation.v()
AA.v()
BB.v()
Delegation.z: 2
BB.w()
"""
}
```
what you need to do to solve the collisions.

View File

@ -24,67 +24,4 @@ containing an anonymous inner class that implements `VendorFactory`.
Now write a standalone function `consumer(factory: VendorFactory)` which uses
`factory` to create a `Vendor`. Use that `Vendor` to call `pencil()` and
`pen()`. The starter code in `main()` will validate your solution.
```kotlin
// CompanionObjects/CompanionEx1.kt
package companionobjectex1
import atomictest.*
private val trace = Trace()
interface Vendor {
fun pencil()
fun pen()
}
interface VendorFactory {
fun create(): Vendor
}
class Vendor1 private constructor() : Vendor {
override fun pencil() {
trace("Vendor1 pencil")
}
override fun pen() {
trace("Vendor1 pen")
}
companion object {
var factory = object : VendorFactory {
override fun create() = Vendor1()
}
}
}
class Vendor2 private constructor() : Vendor {
override fun pencil() {
trace("Vendor2 pencil")
}
override fun pen() {
trace("Vendor2 pen")
}
companion object {
var factory = object : VendorFactory {
override fun create() = Vendor2()
}
}
}
fun consumer(factory: VendorFactory) {
val vendor = factory.create()
vendor.pencil()
vendor.pen()
}
fun main() {
// Implementations are interchangeable:
consumer(Vendor1.factory)
consumer(Vendor2.factory)
trace eq """
Vendor1 pencil
Vendor1 pen
Vendor2 pencil
Vendor2 pen
"""
}
```
`pen()`. The starter code in `main()` will validate your solution.

View File

@ -23,79 +23,4 @@ both `private` constructors with no arguments. Each class should contain a
constructor. Each `companion object` contains a `const val max` which is used
within `move()`. The definitions of `playGame()` and `main()` are provided;
complete the code in `Checkers` and `Chess` so it satisfies the tests in
`main()`.
```kotlin
// CompanionObjects/CompanionEx2.kt
package companionobjectex2
import atomictest.*
private val trace = Trace()
interface BoardGame {
fun move(): Boolean
companion object {
fun createBoard() {
trace("BoardGame.createBoard()")
}
}
}
interface GameFactory {
fun create(): BoardGame
}
class
Checkers private constructor() : BoardGame {
private var moves = 0
override fun move(): Boolean {
trace("Checkers move $moves")
return ++moves != max
}
companion object Factory : GameFactory {
private const val max = 3
init {
BoardGame.createBoard()
}
override fun create() = Checkers()
}
}
class
Chess private constructor() : BoardGame {
private var moves = 0
override fun move(): Boolean {
trace("Chess move $moves")
return ++moves != max
}
companion object Factory : GameFactory {
private const val max = 4
init {
BoardGame.createBoard()
}
override fun create() = Chess()
}
}
fun playGame(factory: GameFactory) {
val s = factory.create()
while (s.move())
;
}
fun main() {
playGame(Checkers.Factory)
playGame(Chess.Factory)
trace eq """
BoardGame.createBoard()
Checkers move 0
Checkers move 1
Checkers move 2
BoardGame.createBoard()
Chess move 0
Chess move 1
Chess move 2
Chess move 3
"""
}
```
`main()`.

View File

@ -55,85 +55,4 @@ steps during object creation. `applyForAccount()` begins the creation of a new
the `Account`, and `completeAccount()` takes an `ID`, adds an account `number`,
and moves the `Account` from the `applied` to the `accounts` list.
The starter code in `main()` will validate your solution.
```kotlin
// CompanionObjects/CompanionEx3.kt
package companionobjectex3
import kotlin.random.Random
import atomictest.*
data class ID(
val name: String,
val id: String = idGenerator()
) {
companion object {
const val size = 10
private val r = Random(47)
private val source =
('a'..'z') + ('A'..'Z') + ('0'..'9')
private fun idGenerator() =
(1..size).map { source.random(r) }
.joinToString("")
fun test(n: Int) = List(n) {
ID(('a' + it).toString())
}.joinToString(",\n")
}
}
class Bank(val name: String) {
private val applied =
mutableListOf<Account>()
private val accounts =
mutableListOf<Account>()
private class Account(val name: String) {
var id: ID? = null
private var number: Long? = null
fun addID(verifiedID: ID) {
id = verifiedID
}
companion object Numbers {
private var i: Long = 1000
private fun nextAccountNumber() = i++
}
fun finish() {
number = nextAccountNumber()
}
override fun toString() = "$id $number"
}
fun applyForAccount(name: String) =
applied.add(Account(name))
fun addID(id: ID) = applied
.first { it.name == id.name }.addID(id)
fun completeAccount(verifiedID: ID) {
val account =
applied.first { it.id == verifiedID }
account.finish()
accounts.add(account)
applied.remove(account)
}
override fun toString() =
accounts.joinToString("\n")
}
fun main() {
ID.test(4) eq """
ID(name=a, id=weazblk9UF),
ID(name=b, id=LCcPJtUGh5),
ID(name=c, id=Acs5BzSj6m),
ID(name=d, id=gHrshDvhwc)
""".trimIndent()
val bank = Bank("Jerry's Savings & Loan")
listOf(ID("Morty Smith"), ID("Beth Smith"),
ID("Summer Smith")).forEach {
bank.applyForAccount(it.name)
bank.addID(it)
bank.completeAccount(it)
}
bank eq """
ID(name=Morty Smith, id=ePkc0HjTAU) 1000
ID(name=Beth Smith, id=jjePlEO93w) 1001
ID(name=Summer Smith, id=C8yaeFEgv6) 1002
""".trimIndent()
}
```
The starter code in `main()` will validate your solution.

View File

@ -1,22 +1,4 @@
## Complex Constructors (#1)
Modify `Alien` by making `name` `private`, then giving it a constructor that
assigns its `name` to the `val` property `myName`.
```kotlin
// ComplexConstructors/Exercise1.kt
package complexconstructors
import atomictest.eq
class Alien2(private val name: String) {
val myName: String
init {
myName = name
}
}
fun main() {
val alien = Alien2("Pencilvester")
alien.myName eq "Pencilvester"
}
```
assigns its `name` to the `val` property `myName`.

View File

@ -3,23 +3,4 @@
Create a class called `SumChars` that takes `text: String` as a class
argument. Add an un-initialized property `val sum: Int`. Inside `init`,
define a local function `calc()` that sums up the integer values of each
of the characters in `text`. Call `calc()` and assign the result to `sum`.
```kotlin
// ComplexConstructors/Exercise2.kt
package complexconstructors
import atomictest.eq
class SumChars(text: String) {
val sum: Int
init {
fun calc() =
text.fold(0, {s, c -> s + c.toInt() })
sum = calc()
}
}
fun main() {
SumChars("What?").sum eq 467
}
```
of the characters in `text`. Call `calc()` and assign the result to `sum`.

View File

@ -3,27 +3,4 @@
Show that multiple init sections are executed in declaration order. Create a
class containing an uninitialized `var result: String`, then initialize
`result` to `one two three` in three different `init` blocks. Note that
`result` cannot be a `val` in this case.
```kotlin
// ComplexConstructors/Exercise3.kt
package complexconstructors
import atomictest.eq
class MultipleInit() {
var result: String
init {
result = "one "
}
init {
result += "two "
}
init {
result += "three"
}
}
fun main() {
MultipleInit().result eq "one two three"
}
```
`result` cannot be a `val` in this case.

View File

@ -1,60 +1,4 @@
## Composition (#1)
In `Car.kt`, add a `service()` member function to `Engine` and add a call to
this function in `main()`.
```kotlin
// Composition/CompositionExercise1.kt
package compositionex1
import atomictest.*
private val trace = Trace()
class Engine {
fun start() = trace("Engine start")
fun stop() = trace("Engine stop")
fun service() = trace("Engine service")
}
class Wheel {
fun inflate(psi: Int) =
trace("Wheel inflate($psi)")
}
class Window(val side: String) {
fun rollUp() =
trace("$side Window roll up")
fun rollDown() =
trace("$side Window roll down")
}
class Door(val side: String) {
val window = Window(side)
fun open() = trace("$side Door open")
fun close() = trace("$side Door close")
}
class Car {
val engine = Engine()
val wheel = List(4) { Wheel() }
// Two door:
val leftDoor = Door("left")
val rightDoor = Door("right")
}
fun main() {
val car = Car()
car.leftDoor.open()
car.rightDoor.window.rollUp()
car.wheel[0].inflate(72)
car.engine.start()
car.engine.service()
trace eq """
left Door open
right Window roll up
Wheel inflate(72)
Engine start
Engine service
"""
}
```
this function in `main()`.

View File

@ -7,64 +7,4 @@ classes, and a `List<Bathroom>` and `List<Bedroom>` to `House`. Create a
`Bathroom`s called "Master", "Shared", and "Guest". Add `Bedroom`s called
"Master", "Son", "Daughter", and "Guest". Use `atomictest.Trace` to capture all
the class names and `name` properties as the `House` is constructed. Also
notice the order of construction.
```kotlin
// Composition/CompositionExercise2.kt
package compositionex2
import atomictest.*
private val trace = Trace()
open class Building(val name: String) {
init { trace("Building: $name") }
}
class Kitchen(val name: String) {
init { trace("Kitchen: $name") }
}
class Bedroom(val name: String) {
init { trace("Bedroom: $name") }
}
class Bathroom(val name: String) {
init { trace("Bathroom: $name") }
}
class House(name: String) : Building(name) {
val kitchens = listOf(
Kitchen("Main"),
Kitchen("Guest")
)
val bathrooms = listOf(
Bathroom("Master"),
Bathroom("Shared"),
Bathroom("Guest")
)
val bedrooms = listOf(
Bedroom("Master"),
Bedroom("Son"),
Bedroom("Daughter"),
Bedroom("Guest")
)
init { trace("House: $name") }
}
fun main() {
House("Our House")
trace eq """
Building: Our House
Kitchen: Main
Kitchen: Guest
Bathroom: Master
Bathroom: Shared
Bathroom: Guest
Bedroom: Master
Bedroom: Son
Bedroom: Daughter
Bedroom: Guest
House: Our House
"""
}
```
notice the order of construction.

View File

@ -18,85 +18,4 @@ you write:
- `InMemory`, implemented with a `mutableMapOf<String, String>()`
- `Mock`, implemented with two `String` `var`s.
Write these classes so they pass the tests given in `main()`.
```kotlin
// Composition/CompositionExercise3.kt
package compositionex3
import atomictest.*
private val trace = Trace()
interface DataBase {
fun write(key: String, value: String)
fun read(key: String): String
}
class NonRelational : DataBase {
private val db =
mutableListOf<Pair<String, String>>()
override fun write(
key: String, value: String
) {
db.add(Pair(key, value))
}
override fun read(key: String) =
db.first { it.first == key }.second
}
class InMemory : DataBase {
private val db =
mutableMapOf<String, String>()
override fun write(
key: String, value: String
) {
db[key] = value
}
override fun read(key: String) =
db[key] ?: ""
}
class Mock : DataBase {
private var k = ""
private var v = ""
override fun write(
key: String, value: String
) { k = key; v = value }
override fun read(key: String) = v
}
class Holder(val db: DataBase) {
fun store(k: String, v: String) =
db.write(k, v)
fun fetch(k: String) = db.read(k)
private val data = """
color: purple
dog: husky
art: deco
""".trimIndent().lines()
.map { it.split(": ") }
fun test() {
for(line in data) {
store(line[0], line[1])
trace(fetch(line[0]))
}
}
}
fun main() {
Holder(NonRelational()).test()
Holder(InMemory()).test()
Holder(Mock()).test()
trace eq """
purple
husky
deco
purple
husky
deco
purple
husky
deco
"""
}
```
Write these classes so they pass the tests given in `main()`.

View File

@ -7,46 +7,4 @@ function. The `trace` argument is the class name and function; for example
Now write a function `checkAndCall(b: Base)` so that it calls the polymorphic
member function, then uses a `when` to downcast and call the extended-interface
functions.
```kotlin
// DownCasting/DownCastEx1.kt
package downcastingex1
import atomictest.*
private val trace = Trace()
interface Base {
fun f()
}
class Derived1 : Base {
override fun f() = trace("Derived1.f()")
fun g() = trace("Derived1.g()")
}
class Derived2 : Base {
override fun f() = trace("Derived2.f()")
fun h() = trace("Derived2.h()")
}
fun checkAndCall(b: Base) {
b.f() // Polymorphic call
when(b) {
is Derived1 -> b.g()
is Derived2 -> b.h()
}
}
fun main() {
checkAndCall(Derived1()) // Upcast
checkAndCall(Derived2()) // Upcast
trace eq """
Derived1.f()
Derived1.g()
Derived2.f()
Derived2.h()
"""
}
```
functions.

View File

@ -9,17 +9,4 @@ There's a second, more dynamic form of `filterIsInstance()`, which takes a
class object as a parameter. Pass `Dog::class.java` as the argument to
`filterIsInstance()`, with the rest of the expression as described in the
previous paragraph. How is this version of `filterIsInstance()` different from
the version that uses a generic argument?
```kotlin
// DownCasting/DownCastEx2.kt
package downcasting
import atomictest.eq
fun main() {
group.filterIsInstance<Dog>()
.map(Dog::bark) eq "[Yip!, Yip!]"
group.filterIsInstance(Dog::class.java)
.map(Dog::bark) eq "[Yip!, Yip!]"
}
```
the version that uses a generic argument?

View File

@ -14,67 +14,4 @@ Create a duplicate hierarchy from an interface `Animal2`, but in this case make
`Beetle2`. In `main()`, create a `List` of `Animal2` objects and call `move()`
for each one.
Compare the type-checked hierarchy to the polymorphic hierarchy.
```kotlin
// DownCasting/DownCastEx3.kt
package downcastingex3
import atomictest.*
private val trace = Trace()
interface Animal1
class Worm1: Animal1 {
fun wriggle() = trace("Wriggle")
}
class Snail1: Animal1 {
fun slide() = trace("Slide")
}
class Beetle1: Animal1 {
fun walk() = trace("Walk")
}
fun move(a1: Animal1) {
when(a1) {
is Worm1 -> a1.wriggle()
is Snail1 -> a1.slide()
is Beetle1 -> a1.walk()
}
}
interface Animal2 {
fun move()
}
class Worm2: Animal2 {
override fun move() = trace("Wriggle")
}
class Snail2: Animal2 {
override fun move() = trace("Slide")
}
class Beetle2: Animal2 {
override fun move() = trace("Walk")
}
fun main() {
val animals1 =
listOf(Worm1(), Snail1(), Beetle1())
animals1.forEach { move(it) }
val animals2 =
listOf(Worm2(), Snail2(), Beetle2())
animals2.forEach { it.move() }
trace eq """
Wriggle
Slide
Walk
Wriggle
Slide
Walk
"""
}
```
Compare the type-checked hierarchy to the polymorphic hierarchy.

View File

@ -4,91 +4,4 @@ Following `AdjustTemp.kt`, add two extension functions `openWindow()` and
`fan()` as ways of cooling. Add a class `DeltaTemperature2` where the extension
functions are instead member functions, and an overloaded `adjust()` function
which takes a `DeltaTemperature2`. Which approach seems better, or are they
about the same?
```kotlin
// InheritanceExtensions/InhExtensionsEx1.kt
package inheritanceextensionsex1
import atomictest.*
private val trace = Trace()
class DeltaTemperature(
val current: Double,
val target: Double
)
fun DeltaTemperature.heat() {
if (current < target)
trace("heating to $target")
}
fun DeltaTemperature.cool() {
if (current > target)
trace("cooling to $target")
}
fun DeltaTemperature.openWindow() {
if (current > target)
trace("cooling to $target")
}
fun DeltaTemperature.fan() {
if (current > target)
trace("cooling to $target")
}
class DeltaTemperature2(
val current: Double,
val target: Double
) {
fun heat() {
if (current < target)
trace("heating to $target")
}
fun cool() {
if (current > target)
trace("cooling to $target")
}
fun openWindow() {
if (current > target)
trace("cooling to $target")
}
fun fan() {
if (current > target)
trace("cooling to $target")
}
}
fun adjust(deltaT: DeltaTemperature) {
deltaT.heat()
deltaT.cool()
deltaT.openWindow()
deltaT.fan()
}
fun adjust(deltaT: DeltaTemperature2) {
deltaT.heat()
deltaT.cool()
deltaT.openWindow()
deltaT.fan()
}
fun main() {
adjust(DeltaTemperature(60.0, 70.0))
adjust(DeltaTemperature(80.0, 60.0))
adjust(DeltaTemperature2(60.0, 70.0))
adjust(DeltaTemperature2(80.0, 60.0))
trace eq """
heating to 70.0
cooling to 60.0
cooling to 60.0
cooling to 60.0
heating to 70.0
cooling to 60.0
cooling to 60.0
cooling to 60.0
"""
}
```
about the same?

View File

@ -8,74 +8,4 @@ Refactor `BatteryPet2.kt` to improve the design:
- You no longer need `Dog.sit()`
- Change `playWithDog(dog: Dog)` to `playWithPet(pet: Pet)`
- Add a `CatFood` type of `Energy`, and define the associated `Cat` class
- In `main()`, test all types of `Pet`
```kotlin
// InheritanceExtensions/InhExtensionsEx2.kt
package inheritanceextensionsex2
import atomictest.*
private val trace = Trace()
interface Energy {
fun replenish() = trace("Fill Bowl")
}
open class Pet(open val energy: Energy) {
open fun speak() = trace("")
open fun settle() = trace("")
open fun feed() = energy.replenish()
}
class DogFood : Energy
open class Dog : Pet(DogFood()) {
override fun speak() = trace("Bark!")
override fun settle() = trace("Sitting...")
}
class CatFood : Energy
open class Cat : Pet(CatFood()) {
override fun speak() = trace("Meow!")
override fun settle() =
trace("In my basket...")
}
class Batteries : Energy {
override fun replenish() =
trace("Change batteries")
}
class ToyDog: Dog() {
override val energy = Batteries()
}
fun play(pet: Pet) = pet.speak()
fun playWithPet(pet: Pet) {
play(pet)
pet.settle()
pet.energy.replenish()
}
fun main() {
val dog1 = Dog()
val dog2 = ToyDog()
val cat = Cat()
playWithPet(dog1)
playWithPet(dog2)
playWithPet(cat)
trace eq """
Bark!
Sitting...
Fill Bowl
Bark!
Sitting...
Change batteries
Meow!
In my basket...
Fill Bowl
"""
}
```
- In `main()`, test all types of `Pet`

View File

@ -4,49 +4,4 @@ Starting with `Adapter.kt` and `ComposeAdapter.kt`, create a function which
dynamically adapts an object, accepting a `MyClass` and returning a
`MyClassAdaptedForLib`. Is it possible to use the inheritance approach in
`Adapter.kt`, or are you forced to use composition? (We'll revisit this issue
in [Class Delegation]).
```kotlin
// InheritanceExtensions/InhExtensionsEx3.kt
package inheritanceextensionsex3
import usefullibrary.*
import atomictest.*
private val trace = Trace()
class MyClass {
fun g() = trace("g()")
fun h() = trace("h()")
}
fun useMyClass(mc: MyClass) {
mc.g()
mc.h()
}
class MyClassAdaptedForLib(
val field: MyClass
) : LibType {
override fun f1() = field.h()
override fun f2() = field.g()
}
fun adapt(mc: MyClass) =
MyClassAdaptedForLib(mc)
fun main() {
val library = UsefulLibrary()
val mc = adapt(MyClass())
library.utility1(mc)
library.utility2(mc)
useMyClass(mc.field)
trace eq """
h()
g()
g()
h()
g()
h()
"""
}
```
in [Class Delegation]).

View File

@ -2,44 +2,4 @@
Add a `hamster()` member function to `LocalInnerClasses.kt` with a local
`val poke = "Squeak"` which returns an object of an anonymous inner class that
extends `Pet`, with a `speak()` that produces `poke + home()`.
```kotlin
// InnerClasses/InnerEx1.kt
package innerclassesex1
import atomictest.eq
interface Pet {
fun speak(): String
}
class PetCreator {
fun home() = " home!"
fun dog(): Pet {
val say = "Bark"
class Dog : Pet {
override fun speak() = say + home()
}
return Dog()
}
fun cat(): Pet {
val emit = "Meow"
return object : Pet {
override fun speak() = emit + home()
}
}
fun hamster(): Pet {
val poke = "Squeak"
return object : Pet {
override fun speak() = poke + home()
}
}
}
fun main() {
val create = PetCreator()
create.dog().speak() eq "Bark home!"
create.cat().speak() eq "Meow home!"
create.hamster().speak() eq "Squeak home!"
}
```
extends `Pet`, with a `speak()` that produces `poke + home()`.

View File

@ -15,28 +15,4 @@ function `f()` which returns `"Any-based"`.
Add a member function `manifest()` which produces a `String` containing the
properties `contains` and `label` and the output of `f()`. The starter code in
`main()` will test your solution.
```kotlin
// InnerClasses/InnerEx2.kt
package innerclassesex2
import atomictest.eq
class Box(contains: String, label: String) {
inner class Contents(val contains: String)
inner class Destination(val label: String)
private val contents = Contents(contains)
private val destination = Destination(label)
private val x = object : Any() {
fun f() = "Any-based"
}
fun manifest() =
"${contents.contains}: " +
"${destination.label} ${x.f()}"
}
fun main() {
Box("Computer", "Tasmania").manifest() eq
"Computer: Tasmania Any-based"
}
```
`main()` will test your solution.

View File

@ -27,66 +27,4 @@ Now make `Container` inherit from `Iterable<T>`, and add a function called
from `Iterator<T>`. Add a standalone function `<T> traceAll2(ib: Iterable<T>)`
that produces the same behavior as `traceAll()`.
The starter code contains a `main()` with tests to verify your code.
```kotlin
// InnerClasses/InnerEx3.kt
package innerclassesex3
import atomictest.*
interface Selector<T> {
fun end(): Boolean
fun current(): T
fun next()
}
class Container<T>(
iterable: Iterable<T>
) : Iterable<T> {
private val items = iterable.toMutableList()
fun add(x: T) = items.add(x)
fun selector() = object : Selector<T> {
private var i = 0
override fun end() = i == items.size
override fun current() = items[i]
override fun next() {
if (i < items.size) i++
}
}
override
fun iterator() = object : Iterator<T> {
private var i = 0
override fun hasNext() = i < items.size
override fun next(): T = items[i++]
}
}
fun <T> traceAll(select: Selector<T>): Trace {
val trace = Trace()
while (!select.end()) {
trace("${select.current()}")
select.next()
}
return trace
}
fun <T> traceAll2(ib: Iterable<T>): Trace {
val trace = Trace()
val iter = ib.iterator()
while (iter.hasNext())
trace("${iter.next()}")
return trace
}
fun main() {
traceAll(Container(0..9).selector()) eq
"0 1 2 3 4 5 6 7 8 9"
traceAll2(Container(0..9)) eq
"0 1 2 3 4 5 6 7 8 9"
traceAll(Container(List(10){ it * it })
.selector()) eq
"0 1 4 9 16 25 36 49 64 81"
traceAll2(Container(List(10){ it * it })) eq
"0 1 4 9 16 25 36 49 64 81"
}
```
The starter code contains a `main()` with tests to verify your code.

View File

@ -5,61 +5,4 @@ In `FillIt.kt`, `State` is only used to determine when there are no more
returning a `Boolean` from `turn()`. Once you have that working, add a third
player by changing `enum class Mark { BLANK, X ,O }` to `enum class Mark {
BLANK, X, Y, Z }`. In `turn()`, use a `when` expression to move to the next
`player` value.
```kotlin
// NestedClasses/NestedEx1.kt
package nestedclassesex1
import atomictest.*
import nestedclassesex1.Game.Mark.*
import java.lang.IllegalStateException
import kotlin.random.Random
interface Game {
enum class Mark { BLANK, X, Y, Z }
}
class FillIt(
val side: Int = 3, randomSeed: Int = 0
) : Game {
val rand = Random(randomSeed)
private var grid =
MutableList(side * side) { BLANK }
private var player = X
fun turn(): Boolean {
val blanks = grid.withIndex()
.filter { it.value == BLANK }
if (blanks.isEmpty())
return false
grid[blanks.random(rand).index] = player
player = when(player) {
BLANK -> throw IllegalStateException()
X -> Y
Y -> Z
Z -> X
}
return true
}
fun play() {
while(turn())
;
}
override fun toString() =
grid.chunked(side).joinToString("\n")
}
fun main() {
val game = FillIt(8, 17)
game.play()
game eq """
[X, Z, Y, Z, Z, Y, X, Y]
[Y, Z, Z, Y, Z, Y, Y, Z]
[Z, Y, Z, Y, Y, X, X, Y]
[X, X, X, Y, Y, X, X, Y]
[X, X, Z, X, Z, X, X, X]
[Z, X, Z, X, Y, Z, Z, Z]
[Y, Y, X, Y, Z, Z, Z, X]
[Y, X, Z, Y, Y, X, X, Z]
""".trimIndent()
}
```
`player` value.

View File

@ -1,67 +1,4 @@
## Nested Classes (#2)
In `NestedHouse.kt`, add two `Drawer`s to `Closet` and a `Bathtub` to
`Bathroom`.
```kotlin
// NestedClasses/NestedEx2.kt
package nestedclassesex2
import atomictest.*
abstract class Cleanable(val id: String) {
open val parts: List<Cleanable> = listOf()
fun clean(): String =
"${parts.map(Cleanable::clean)} $id clean\n"
}
class House: Cleanable("House") {
override val parts = listOf(
Bedroom("Master Bedroom"),
Bedroom("Guest Bedroom")
)
class Bedroom(id: String): Cleanable(id) {
override val parts =
listOf(Closet(), Bathroom())
class Closet: Cleanable("Closet") {
override val parts = listOf(
Shelf(), Shelf(), Drawer(), Drawer()
)
class Shelf: Cleanable("Shelf")
class Drawer: Cleanable("Drawer")
}
class Bathroom: Cleanable("Bathroom") {
override val parts =
listOf(Toilet(), Sink(), Bathtub())
class Toilet: Cleanable("Toilet")
class Sink: Cleanable("Sink")
class Bathtub: Cleanable("Bathtub")
}
}
}
fun main() {
House().clean().trim() eq """
[[[[] Shelf clean
, [] Shelf clean
, [] Drawer clean
, [] Drawer clean
] Closet clean
, [[] Toilet clean
, [] Sink clean
, [] Bathtub clean
] Bathroom clean
] Master Bedroom clean
, [[[] Shelf clean
, [] Shelf clean
, [] Drawer clean
, [] Drawer clean
] Closet clean
, [[] Toilet clean
, [] Sink clean
, [] Bathtub clean
] Bathroom clean
] Guest Bedroom clean
] House clean
""".trimIndent()
}
```
`Bathroom`.

View File

@ -1,64 +1,4 @@
## Nested Classes (#3)
"Unpack" the nested classes in `NestedHouse.kt` by turning each nested class
into a global class.
```
// NestedClasses/NestedEx3.kt
package nestedclassesex3
import atomictest.*
abstract class Cleanable(val id: String) {
open val parts: List<Cleanable> = listOf()
fun clean(): String =
"${parts.map(Cleanable::clean)} $id clean\n"
}
class Shelf : Cleanable("Shelf")
class Closet : Cleanable("Closet") {
override val parts =
listOf(Shelf(), Shelf())
}
class Toilet : Cleanable("Toilet")
class Sink : Cleanable("Sink")
class Bathroom : Cleanable("Bathroom") {
override val parts =
listOf(Toilet(), Sink())
}
class Bedroom(id: String) : Cleanable(id) {
override val parts =
listOf(Closet(), Bathroom())
}
class House : Cleanable("House") {
override val parts = listOf(
Bedroom("Master Bedroom"),
Bedroom("Guest Bedroom")
)
}
fun main() {
Trace(House().clean()) eq """
[[[[] Shelf clean
, [] Shelf clean
] Closet clean
, [[] Toilet clean
, [] Sink clean
] Bathroom clean
] Master Bedroom clean
, [[[] Shelf clean
, [] Shelf clean
] Closet clean
, [[] Toilet clean
, [] Sink clean
] Bathroom clean
] Guest Bedroom clean
] House clean
"""
}
```
into a global class.

View File

@ -10,64 +10,4 @@ for each `Seat` type. `Seat` contains `abstract` member functions for
`upgrade()` and `meal()` functions which forward their actions to the `Seat`
object.
Bonus (Challenging): Why can't you use delegation for `seat` in `Ticket`?
```kotlin
// NestedClasses/NestedEx4.kt
package nestedclassesex4
import atomictest.eq
import nestedclassesex4.Seat.*
abstract class Seat {
abstract fun upgrade(): Seat
abstract fun meal(): String
override fun toString() =
"${this::class.simpleName}"
class Coach : Seat() {
override fun upgrade() = Premium()
override fun meal() = "Bag Meal"
}
class Premium : Seat() {
override fun upgrade() = Business()
override fun meal() = "Bag Meal + Cookie"
}
class Business : Seat() {
override fun upgrade() = First()
override fun meal() = "Hot Meal"
}
class First : Seat() {
override fun upgrade() = First()
override fun meal() = "Private Chef"
}
}
class Ticket(
private var seat: Seat = Coach()
) {
fun upgrade(): Seat {
seat = seat.upgrade()
return seat
}
fun meal() = seat.meal()
override fun toString() = "$seat"
}
fun main() {
val tickets = listOf(
Ticket(),
Ticket(Premium()),
Ticket(Business()),
Ticket(First())
)
tickets.map(Ticket::meal) eq
"[Bag Meal, Bag Meal + Cookie, " +
"Hot Meal, Private Chef]"
tickets.map(Ticket::upgrade) eq
"[Premium, Business, First, First]"
tickets eq
"[Premium, Business, First, First]"
tickets.map(Ticket::meal) eq
"[Bag Meal + Cookie, Hot Meal, " +
"Private Chef, Private Chef]"
}
```
Bonus (Challenging): Why can't you use delegation for `seat` in `Ticket`?

View File

@ -3,22 +3,4 @@
Add new type of `Actor` called `Bomb`, with `*` as its `symbol`. When it
encounters a `Bomb`, the `Robot` loses all its energy and the `Bomb` disappears
from the room (so the `Robot` still enters the room where the `Bomb` was). Add
one or more `*` to `stringMaze` to test your solution.
SOLUTION::
Add the following to `Actors.kt`:
```kotlin
class Bomb(
override val room: Room = Room()
) : Actor() {
override val symbol = '*'
override fun makeActor(r: Room) = Bomb(r)
override fun interact(robot: Robot): Room {
robot.energy = 0 // Bomb erases energy
room.actor = Empty(room)
return room
}
}
```
one or more `*` to `stringMaze` to test your solution.

View File

@ -8,96 +8,4 @@ Calculate the allocated number of moves by counting all the `Food` items in the
maze, dividing by two and adding 50.
The goal of the player is to reach the end of the maze before running out of
moves while maximizing the `energy` value.
SOLUTION::
```kotlin
// ObjectOrientedDesign/OODesignEx2.kt
package oodesign
import org.hexworks.zircon.api.*
import org.hexworks.zircon.api.application.*
import org.hexworks.zircon.api.data.*
import org.hexworks.zircon.api.uievent.*
import org.hexworks.zircon.api.graphics.*
import org.hexworks.zircon.api.color.*
fun robotExplorer2(stage: Stage) {
var moves = stage.maze
.filter { it == '.' }.length / 2 + 50
val style = StyleSet.defaultStyle()
// Turn a character into a Tile:
fun charTile(c: Char, s: StyleSet = style) =
Tile.createCharacterTile(c, s)
// Initialize the zircon terminal emulator:
val grid = SwingApplications
.startTileGrid(AppConfig.newBuilder()
.withDefaultTileset(
TrueTypeFontResources.ubuntuMono(25))
.withSize(Size.create(
stage.width, stage.height + 1))
.build())
// Strip newlines and create an iterator:
val maze = stage.maze
.filter { it != '\n' }.iterator()
// Fill the grid with the maze:
grid.size.fetchPositions().forEach {
if (maze.hasNext())
grid.putTile(charTile(maze.next()))
}
// The robot's location as a Position:
fun robotPosition() = Position.create(
stage.robot.room.col,
stage.robot.room.row)
// Create the red robot icon layer:
val robotIcon = Layer.newBuilder()
.withSize(Size.one())
.withOffset(robotPosition())
.build().apply {
fill(charTile(stage.robot.symbol,
style.withForegroundColor(
ANSITileColor.RED)))
}
// As a layer, it can be moved around:
grid.addLayer(robotIcon)
// Update the character beneath the robot:
fun updateSymbolAtRobot() {
grid.cursorPosition = robotPosition()
grid.putTile(
charTile(stage.robot.room.actor.id()))
}
// Put a string on the blank bottom line:
fun console(s: String) {
grid.cursorPosition =
Position.create(1, stage.height + 1)
s.forEach { grid.putTile(charTile(it)) }
}
// Move the robot and update the screen:
fun robotGo(urge: Urge) {
moves--
updateSymbolAtRobot()
stage.robot.move(urge)
robotIcon.moveTo(robotPosition())
console(
"Energy: ${stage.robot.energy} " +
"Moves Remaining: $moves "
)
}
// Respond to the keyboard arrow keys:
grid.processKeyboardEvents(
KeyboardEventType.KEY_PRESSED
) { event, _ ->
when (event.code) {
KeyCode.UP -> robotGo(Urge.North)
KeyCode.DOWN -> robotGo(Urge.South)
KeyCode.LEFT -> robotGo(Urge.West)
KeyCode.RIGHT -> robotGo(Urge.East)
else -> Pass
}
}
}
fun main() {
robotExplorer2(Stage(stringMaze))
}
```
moves while maximizing the `energy` value.

View File

@ -24,76 +24,4 @@ class House(
}
```
Make your code satisfy the tests in `main()`.
SOLUTION::
```kotlin
// ObjectOrientedDesign/OODesignEx3.kt
package oodesignex3
import atomictest.*
private val trace = Trace()
interface TalkingAnimal {
fun create(): TalkingAnimal
fun speak() =
trace("I'm a ${this::class.simpleName}")
}
class Monkey : TalkingAnimal {
override fun create() = Monkey()
}
class Giraffe : TalkingAnimal {
override fun create() = Giraffe()
override fun speak() {
super.speak()
trace("The view is great up here!")
}
}
class Hyena : TalkingAnimal {
override fun create() = Hyena()
override fun speak() {
super.speak()
trace("Yip Yip Yip!")
}
}
class House(
val prototype: TalkingAnimal,
val size: Int
) {
val name: String =
"${prototype::class.simpleName} House"
val denizens: List<TalkingAnimal> =
List<TalkingAnimal>(size) {
prototype.create()
}
fun report() {
trace(name)
denizens.forEach { it.speak() }
}
}
fun main() {
House(Giraffe(), 1).report()
House(Hyena(), 2).report()
House(Monkey(), 3).report()
trace eq """
Giraffe House
I'm a Giraffe
The view is great up here!
Hyena House
I'm a Hyena
Yip Yip Yip!
I'm a Hyena
Yip Yip Yip!
Monkey House
I'm a Monkey
I'm a Monkey
I'm a Monkey
"""
}
```
Make your code satisfy the tests in `main()`.

View File

@ -4,36 +4,4 @@ Create a file-level `private fun f()` and `private val p`. The starter code in
`main()` will show you how to write these. Now duplicate `f()` and `p` inside
`object Space` and again in `private object Space2`, and get these to work
according to the code in `main()`. Notice the changes you need to make so that
`f()` is available in `main()`. Compare the different approaches.
```kotlin
// Objects/ObjectEx1.kt
package objectex1
import atomictest.*
private val trace = Trace()
private fun f() = trace("f() $p")
private val p = "p"
object Space {
fun f() = trace("Space.f() $p")
private val p = "Space.p"
}
private object Space2 {
fun f() = trace("Space2.f() $p")
private val p = "Space2.p"
}
fun main() {
f()
Space.f()
Space2.f()
trace eq """
f() p
Space.f() Space.p
Space2.f() Space2.p
"""
}
```
`f()` is available in `main()`. Compare the different approaches.

View File

@ -3,39 +3,4 @@
Add more nesting to `ObjectNesting.kt`. Inside both the `Nested` objects, add
another `Nested` object that looks the same as its enclosing `Nested`, with the
same name and property, and an appropriate `String` for `a`. The code in
`main()` provides tests. Notice how the namespaces work.
```kotlin
// Objects/ObjectEx2.kt
package objectex2
import atomictest.eq
object Outer {
object Nested {
val a = "Outer.Nested.a"
object Nested {
val a = "Outer.Nested.Nested.a"
}
}
}
class HasObject {
object Nested {
val a = "HasObject.Nested.a"
object Nested {
val a = "HasObject.Nested.Nested.a"
}
}
}
fun main() {
Outer.Nested.a eq
"Outer.Nested.a"
HasObject.Nested.a eq
"HasObject.Nested.a"
Outer.Nested.Nested.a eq
"Outer.Nested.Nested.a"
HasObject.Nested.Nested.a eq
"HasObject.Nested.Nested.a"
}
```
`main()` provides tests. Notice how the namespaces work.

View File

@ -19,55 +19,4 @@ that returns their class name.
Now define an `object MonkeysVsSnakes` which is an `AdventureGame`, using the
various `create()` functions to initialize it. `populate()` only needs to add
one `Monkey` and one `Snake`. The predefined `main()` will test your code.
```kotlin
// Objects/ObjectEx3.kt
package objectex3
import atomictest.*
interface AdventureGame {
interface Environment
interface Character
val environment: Environment
val characters: MutableList<Character>
fun populate()
}
class Jungle : AdventureGame.Environment {
object Factory {
fun create() = Jungle()
}
}
class Monkey : AdventureGame.Character {
object Factory {
fun create() = Monkey()
}
override fun toString() = "Monkey"
}
class Snake : AdventureGame.Character {
object Factory {
fun create() = Snake()
}
override fun toString() = "Snake"
}
object MonkeysVsSnakes : AdventureGame {
override val environment =
Jungle.Factory.create()
override val characters =
mutableListOf<AdventureGame.Character>()
override fun populate() {
characters.add(Monkey.Factory.create())
characters.add(Snake.Factory.create())
}
}
fun main() {
MonkeysVsSnakes.populate()
MonkeysVsSnakes.characters eq
"[Monkey, Snake]"
}
```
one `Monkey` and one `Snake`. The predefined `main()` will test your code.

View File

@ -1,33 +1,3 @@
## Polymorphism (#1)
Add `Hamster` (which says "Squeak!") to `Pet.kt`.
```kotlin
// Polymorphism/PolyExercise1.kt
package polymorphismex1
import atomictest.eq
open class Pet {
open fun speak() = "Pet"
}
class Dog : Pet() {
override fun speak() = "Bark!"
}
class Cat : Pet() {
override fun speak() = "Meow"
}
class Hamster : Pet() {
override fun speak() = "Squeak!"
}
fun talk(pet: Pet) = pet.speak()
fun main() {
talk(Dog()) eq "Bark!"
talk(Cat()) eq "Meow"
talk(Hamster()) eq "Squeak!"
}
```
Add `Hamster` (which says "Squeak!") to `Pet.kt`.

View File

@ -2,169 +2,4 @@
Add `Wizard`, which implements `Magician`, and `Goblin` which implements
`Fighter`, to `FantasyGame.kt`. In `main()`, create and test a `Wizard` named
"Max" and a `Goblin` named "Gorbag."
```kotlin
// Polymorphism/PolyExercise2.kt
package polymorphismex2
import atomictest.*
private val trace = Trace()
interface Character {
val name: String
val type: String
fun skills(): String
fun play() {
trace("$name $type:\n ${skills()}")
}
}
interface Magician {
fun skills() = "Magic"
}
interface Fighter {
fun skills() = "Fighting"
}
interface Flyer {
fun skills() = "Flying"
}
open class Elf(override val name: String) :
Character, Magician, Flyer {
override val type = "Elf"
override fun skills() =
super<Magician>.skills() + ", " +
super<Flyer>.skills()
}
class FightingElf(name: String) :
Elf(name), Fighter {
override val type = "FightingElf"
override fun skills() =
super<Elf>.skills() + ", " +
super<Fighter>.skills()
}
class Warrior(override val name: String) :
Character, Fighter {
override val type = "Warrior"
override fun skills() = super.skills()
}
class Dragon(override val name: String) :
Character, Magician, Flyer {
override val type = "Dragon"
override fun skills() =
super<Magician>.skills() + ", " +
super<Flyer>.skills()
}
class Wizard(override val name: String) :
Character, Magician {
override val type = "Wizard"
override fun skills() = super.skills()
}
class Goblin(override val name: String) :
Character, Fighter {
override val type = "Goblin"
override fun skills() = super.skills()
}
fun match(c1: Character, c2: Character) {
c1.play()
trace("->")
c2.play()
trace(".")
}
fun main() {
val characters: List<Character> = listOf(
Elf("Titania"),
FightingElf("Legolas"),
Warrior("Conan"),
Dragon("Puff"),
Wizard("Max"),
Goblin("Gorbag")
)
characters.forEach { c1 ->
characters.filter { it != c1 }
.forEach { c2 -> match(c1, c2) }
}
trace eq """
Titania Elf: Magic, Flying ->
Legolas FightingElf:
Magic, Flying, Fighting .
Titania Elf: Magic, Flying ->
Conan Warrior: Fighting .
Titania Elf: Magic, Flying ->
Puff Dragon: Magic, Flying .
Titania Elf: Magic, Flying ->
Max Wizard: Magic .
Titania Elf: Magic, Flying ->
Gorbag Goblin: Fighting .
Legolas FightingElf:
Magic, Flying, Fighting ->
Titania Elf: Magic, Flying .
Legolas FightingElf:
Magic, Flying, Fighting ->
Conan Warrior: Fighting .
Legolas FightingElf:
Magic, Flying, Fighting ->
Puff Dragon: Magic, Flying .
Legolas FightingElf:
Magic, Flying, Fighting ->
Max Wizard: Magic .
Legolas FightingElf:
Magic, Flying, Fighting ->
Gorbag Goblin: Fighting .
Conan Warrior: Fighting ->
Titania Elf: Magic, Flying .
Conan Warrior: Fighting ->
Legolas FightingElf:
Magic, Flying, Fighting .
Conan Warrior: Fighting ->
Puff Dragon: Magic, Flying .
Conan Warrior: Fighting ->
Max Wizard: Magic .
Conan Warrior: Fighting ->
Gorbag Goblin: Fighting .
Puff Dragon: Magic, Flying ->
Titania Elf: Magic, Flying .
Puff Dragon: Magic, Flying ->
Legolas FightingElf:
Magic, Flying, Fighting .
Puff Dragon: Magic, Flying ->
Conan Warrior: Fighting .
Puff Dragon: Magic, Flying ->
Max Wizard: Magic .
Puff Dragon: Magic, Flying ->
Gorbag Goblin: Fighting .
Max Wizard: Magic ->
Titania Elf: Magic, Flying .
Max Wizard: Magic ->
Legolas FightingElf:
Magic, Flying, Fighting .
Max Wizard: Magic ->
Conan Warrior: Fighting .
Max Wizard: Magic ->
Puff Dragon: Magic, Flying .
Max Wizard: Magic ->
Gorbag Goblin: Fighting .
Gorbag Goblin: Fighting ->
Titania Elf: Magic, Flying .
Gorbag Goblin: Fighting ->
Legolas FightingElf:
Magic, Flying, Fighting .
Gorbag Goblin: Fighting ->
Conan Warrior: Fighting .
Gorbag Goblin: Fighting ->
Puff Dragon: Magic, Flying .
Gorbag Goblin: Fighting ->
Max Wizard: Magic .
"""
}
```
"Max" and a `Goblin` named "Gorbag."

View File

@ -9,42 +9,4 @@ From `Base`, inherit a class called `Derived`. Override `f1()`, first tracing
the same way.
In `main()`, create a `Derived` object and upcast it to a `Base` reference.
Call `f1()` for this reference and explain the resulting trace.
```kotlin
// Polymorphism/PolyExercise3.kt
package polymorphism
import atomictest.*
private val trace = Trace()
open class Base {
open fun f1() {
trace("Base.f1")
f2()
}
open fun f2() = trace("Base.f2")
}
class Derived : Base() {
override fun f1() {
trace("Derived.f1")
super.f1()
}
override fun f2() {
trace("Derived.f2")
super.f2()
}
}
fun main() {
val base: Base = Derived()
base.f1()
trace eq """
Derived.f1
Base.f1
Derived.f2
Base.f2
"""
}
```
Call `f1()` for this reference and explain the resulting trace.

View File

@ -5,69 +5,4 @@ the `Transport` class and add `trace("size ${transport.capacity}")` after the
`when` expression in `travel()`. Then add new subclasses called `Tram`
containing a `val route: String` and `Plane` containing a `val flightNumber:
String`. Modify `travel()` to accomodate these new subclasses. Add `Tram` and
`Plane` to the `List` in `main()`.
```kotlin
// SealedClasses/SealedEx1.kt
package sealedclassesex1
import atomictest.*
private val trace = Trace()
sealed class Transport {
abstract val capacity: Int
}
data class Train(
val line: String,
override val capacity: Int
) : Transport()
data class Bus(
val number: String,
override val capacity: Int
) : Transport()
data class Tram(
val route: String,
override val capacity: Int
) : Transport()
data class Plane(
val flightNumber: String,
override val capacity: Int
) : Transport()
fun travel(transport: Transport) {
when (transport) {
is Train ->
trace("Train ${transport.line}")
is Bus ->
trace("Bus ${transport.number}")
is Tram ->
trace("Tram ${transport.route}")
is Plane ->
trace("Plane ${transport.flightNumber}")
}
trace("size ${transport.capacity}")
}
fun main() {
listOf(
Train("S1", 200),
Bus("11", 45),
Tram("22A Express", 60),
Plane("1103", 190)
).forEach(::travel)
trace eq """
Train S1
size 200
Bus 11
size 45
Tram 22A Express
size 60
Plane 1103
size 190
"""
}
```
`Plane` to the `List` in `main()`.

View File

@ -1,24 +1,4 @@
## Sealed Classes (#2)
Use `sealedSubclasses` to iterate through the classes in the previous
exercise. For each class, `trace()` its `simpleName`.
```kotlin
// SealedClasses/SealedEx2.kt
package sealedclassesex1
import atomictest.*
private val trace = Trace()
fun main() {
Transport::class.sealedSubclasses
.map { it.simpleName }
.forEach { trace(it) }
trace eq """
Train
Bus
Tram
Plane
"""
}
```
exercise. For each class, `trace()` its `simpleName`.

View File

@ -3,27 +3,4 @@
Modify `SealedSubclasses.kt` so that all the subclasses of `Top` are nested
within `Top`. Create a seeded random-number generator by defining `val rand =
Random(17)`. Use this generator to randomly select a subclass of `Top` and
display its `simpleName`.
```kotlin
// SealedClasses/SealedEx3.kt
package sealedclassesex3
import atomictest.eq
import kotlin.random.Random
sealed class Top {
class Middle1 : Top()
class Middle2 : Top()
open class Middle3 : Top()
class Bottom3 : Middle3()
}
fun main() {
Top::class.sealedSubclasses
.map { it.simpleName } eq
"[Middle1, Middle2, Middle3]"
val rand = Random(17)
Top::class.sealedSubclasses
.random(rand).simpleName eq "Middle3"
}
```
display its `simpleName`.

View File

@ -11,54 +11,4 @@ Show that the compiler won't allow you to call `jump()`.
In `main()`, create an instance of `Mouse` and `KangarooRat`, and show that
you can call `jump()` for the latter. Pass both objects into `upcast()`, and
use `trace` to verify the output.
```kotlin
// Upcasting/UpcastExercise1.kt
package upcasting
import atomictest.*
private val trace = Trace()
interface Rodent {
fun eat()
fun speak()
}
class Mouse: Rodent {
override fun eat() =
trace("Mouse.eat")
override fun speak() =
trace("Mouse.speak")
}
class KangarooRat: Rodent {
override fun eat() =
trace("KangarooRat.eat")
override fun speak() =
trace("KangarooRat.speak")
fun jump() =
trace("KangarooRat.jump")
}
fun upcast(rodent: Rodent) {
rodent.eat()
rodent.speak()
// rodent.jump() // Won't compile
}
fun main() {
val mouse = Mouse()
val kangarooRat = KangarooRat()
kangarooRat.jump()
upcast(mouse)
upcast(kangarooRat)
trace eq """
KangarooRat.jump
Mouse.eat
Mouse.speak
KangarooRat.eat
KangarooRat.speak
"""
}
```
use `trace` to verify the output.

View File

@ -16,61 +16,4 @@ From `Apple`, inherit `GrannySmith`, `Gala`, `Fuji` and `Braeburn`. Override
`bite Gala`, `press Fuji` and `peel Braeburn`.
In `main()`, make a `List<Apple>` and populate it with the specific types of
`Apple`. Iterate through the list calling `consume()` for each object.
```kotlin
// Upcasting/UpcastExercise2.kt
package upcasting
import atomictest.*
private val trace = Trace()
private var counter = 0
abstract class Apple(val type: String) {
private val id = counter++
init {
trace("$type $id")
}
abstract fun consume()
}
class GrannySmith : Apple("GrannySmith") {
override fun consume() =
trace("chomp $type")
}
class Gala : Apple("Gala") {
override fun consume() =
trace("bite $type")
}
class Fuji : Apple("Fuji") {
override fun consume() =
trace("press $type")
}
class Braeburn : Apple("Braeburn") {
override fun consume() =
trace("peel $type")
}
fun main() {
val apples: List<Apple> = listOf(
GrannySmith(),
Gala(),
Fuji(),
Braeburn()
)
apples.forEach { it.consume() }
trace eq """
GrannySmith 0
Gala 1
Fuji 2
Braeburn 3
chomp GrannySmith
bite Gala
press Fuji
peel Braeburn
"""
}
```
`Apple`. Iterate through the list calling `consume()` for each object.

View File

@ -19,55 +19,4 @@ so that each function calls the member function avalable to its parameter.
In `main()`, make a `Hero` object and pass it to each of the functions `t()`,
`u()`, `v()`, and `w()` and validate the output using `trace`. Notice how
passing a `Hero` to each of the functions upcasts it so that, inside the
function, the `Hero` becomes only the type of that parameter.
```kotlin
// Upcasting/UpcastExercise3.kt
package upcasting
import atomictest.*
private val trace = Trace()
interface Fight {
fun fight()
}
interface Swim {
fun swim()
}
interface Fly {
fun fly()
}
open class ActionCharacter {
fun fight() =
trace("ActionCharacter fight")
}
class Hero :
ActionCharacter(), Fight, Swim, Fly {
override fun swim() = trace("Hero swim")
override fun fly() = trace("Hero fly")
}
fun t(x: Fight) = x.fight()
fun u(x: Swim) = x.swim()
fun v(x: Fly) = x.fly()
fun w(x: ActionCharacter) = x.fight()
fun main() {
val h = Hero()
t(h) // Treat it as a Fight
u(h) // Treat it as a Swim
v(h) // Treat it as a Fly
w(h) // Treat it as an ActionCharacter
trace eq """
ActionCharacter fight
Hero swim
Hero fly
ActionCharacter fight
"""
}
```
function, the `Hero` becomes only the type of that parameter.