This repository has been archived by the owner on Mar 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
includes basic instructions for wall, clock and hand and task control includes clock selection with hands includes basic task that holds a list of instructions added some tests #2 moved validation to HandInteractionService
- Loading branch information
Showing
25 changed files
with
722 additions
and
6 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
@file:Suppress("UNCHECKED_CAST") | ||
|
||
package com.adclock.instructionset | ||
|
||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.instructionset.clockselections.ClockSelectionParser | ||
import com.adclock.instructionset.instructions.Instruction | ||
import com.adclock.instructionset.instructions.InstructionParser | ||
import com.adclock.util.findSubclasses | ||
import kotlin.reflect.full.companionObjectInstance | ||
|
||
object InstructionSet { | ||
|
||
private val instructionParsers = findSubclasses(this::class.java.`package`.name, Instruction::class) | ||
.associateWith { it.companionObjectInstance as? InstructionParser<*> } | ||
|
||
private val selectionParsers = findSubclasses(this::class.java.`package`.name, ClockSelection::class) | ||
.associateWith { it.companionObjectInstance as? ClockSelectionParser<*> } | ||
|
||
fun deserialize(input: String): Instruction { | ||
val instruction = input.take(3) | ||
val parser = instructionParsers.values.find { instruction == it?.key } | ||
?: throw IllegalArgumentException("No parser found for instruction $instruction.") | ||
|
||
if (input.length > 3 && input[3] != ' ') | ||
throw IllegalArgumentException("Blank after instruction expected.") | ||
|
||
return parser.deserialize(input.drop(4)) | ||
} | ||
|
||
|
||
fun serialize(instruction: Instruction): String { | ||
val parser = instructionParsers[instruction::class] | ||
?: throw IllegalArgumentException("No parser found for instruction type ${instruction::class.simpleName}.") | ||
parser as InstructionParser<Instruction> | ||
return "${parser.key.padEnd(3)} ${parser.serialize(instruction)}".trim() | ||
} | ||
|
||
fun deserializeSelection(selection: String) = | ||
selection.split(",").map { split -> | ||
selectionParsers.values.find { it?.deserializable(split) ?: false }?.deserialize(split) | ||
?: throw IllegalArgumentException("No parser found for selection part $split") | ||
} | ||
|
||
|
||
fun serializeSelection(selection: ClockSelection): String { | ||
val parser = selectionParsers[selection::class] | ||
?: throw IllegalArgumentException("No parser found for instruction type ${selection::class.simpleName}.") | ||
parser as ClockSelectionParser<ClockSelection> | ||
return parser.serialize(selection) | ||
} | ||
|
||
fun serializeSelection(selections: List<ClockSelection>) = selections.joinToString(",") { serializeSelection(it) } | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.adclock.instructionset | ||
|
||
import com.adclock.instructionset.instructions.Instruction | ||
import com.adclock.services.WallInteractionService | ||
|
||
class Task(val instructions: List<Instruction>) { | ||
private var current: Int = 0 | ||
var sleepUntil: Long = 0 | ||
internal set | ||
|
||
fun isCompleted() = current >= instructions.size | ||
|
||
fun apply(wallService: WallInteractionService) { | ||
if (isCompleted()) | ||
throw IllegalStateException("This task is already completed. Can't perform more steps.") | ||
|
||
if (sleepUntil > System.currentTimeMillis()) | ||
return | ||
|
||
val instruction = instructions[current] | ||
if (instruction.apply(this, wallService)) | ||
current++ | ||
} | ||
|
||
internal fun restart() { current = 0 } | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.adclock.instructionset.clockselections | ||
|
||
import com.adclock.model.Clock | ||
import com.adclock.model.HandType | ||
|
||
|
||
interface ClockSelection { | ||
val hands: Array<HandType> | ||
|
||
fun selected(clock: Clock): Boolean | ||
} | ||
|
25 changes: 25 additions & 0 deletions
25
src/instructionset/clockselections/ClockSelectionParser.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.adclock.instructionset.clockselections | ||
|
||
import com.adclock.model.HandType | ||
|
||
interface ClockSelectionParser<T : ClockSelection> { | ||
fun deserializable(string: String): Boolean | ||
|
||
fun deserialize(hands: Array<HandType>, string: String): T | ||
fun serializeParameters(selection: T): String | ||
|
||
fun deserialize(string: String): T { | ||
var clockPart = string | ||
val hands = mutableListOf<HandType>() | ||
while (clockPart.isNotBlank() && clockPart.last() in HandType.shortNames) { | ||
hands += HandType.valueOfShort(clockPart.last()) | ||
clockPart = clockPart.dropLast(1) | ||
} | ||
return deserialize(hands.distinct().sorted().toTypedArray().ifEmpty { HandType.values() }, clockPart) | ||
} | ||
|
||
fun serialize(selection: T): String { | ||
val hands = selection.hands.joinToString("") { it.short.toString() } | ||
return serializeParameters(selection) + hands | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.adclock.instructionset.clockselections | ||
|
||
import com.adclock.model.Clock | ||
import com.adclock.model.HandType | ||
|
||
class RangeClockSelection( | ||
val range: IntRange, | ||
override val hands: Array<HandType> | ||
) : ClockSelection { | ||
override fun selected(clock: Clock) = clock.id in range | ||
|
||
companion object : ClockSelectionParser<RangeClockSelection> { | ||
override fun deserializable(string: String) = "-" in string | ||
|
||
override fun deserialize(hands: Array<HandType>, string: String): RangeClockSelection { | ||
val from = string.substringBefore("-") | ||
val to = string.substringAfter("-") | ||
val range = from.toInt()..to.toInt() | ||
require(!range.isEmpty()) { "Range ${range.first} to ${range.last} does not select any clocks." } | ||
return RangeClockSelection(range, hands) | ||
} | ||
|
||
override fun serializeParameters(selection: RangeClockSelection) = "${selection.range.first}-${selection.range.last}" | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/instructionset/clockselections/SingleClockSelection.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.adclock.instructionset.clockselections | ||
|
||
import com.adclock.model.Clock | ||
import com.adclock.model.HandType | ||
|
||
class SingleClockSelection( | ||
val id: Int, | ||
override val hands: Array<HandType> | ||
) : ClockSelection { | ||
override fun selected(clock: Clock) = clock.id == id | ||
|
||
companion object : ClockSelectionParser<SingleClockSelection> { | ||
override fun deserializable(string: String) = "-" !in string | ||
|
||
override fun deserialize(hands: Array<HandType>, string: String) = | ||
SingleClockSelection(string.toInt(), hands) | ||
|
||
override fun serializeParameters(selection: SingleClockSelection) = selection.id.toString() | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.adclock.instructionset.instructions | ||
|
||
import com.adclock.instructionset.Task | ||
import com.adclock.services.WallInteractionService | ||
|
||
interface Instruction { | ||
fun apply(task: Task, wallService: WallInteractionService): Boolean | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.adclock.instructionset.instructions | ||
|
||
interface InstructionParser<T : Instruction> { | ||
val key: String | ||
|
||
fun deserialize(input: String): T | ||
|
||
fun serialize(instruction: T): String | ||
} |
28 changes: 28 additions & 0 deletions
28
src/instructionset/instructions/basic/RepeatInstruction.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.adclock.instructionset.instructions.basic | ||
|
||
import com.adclock.instructionset.Task | ||
import com.adclock.instructionset.instructions.Instruction | ||
import com.adclock.instructionset.instructions.InstructionParser | ||
import com.adclock.services.WallInteractionService | ||
|
||
class RepeatInstruction : Instruction { | ||
|
||
override fun apply(task: Task, wallService: WallInteractionService): Boolean { | ||
task.restart() | ||
return false | ||
} | ||
|
||
|
||
companion object : InstructionParser<RepeatInstruction> { | ||
override val key: String | ||
get() = "RPT" | ||
|
||
override fun deserialize(input: String): RepeatInstruction { | ||
require(input.isBlank()) { "No parameters for repeat instruction expected, but was $input." } | ||
return RepeatInstruction() | ||
} | ||
|
||
override fun serialize(instruction: RepeatInstruction) = "" | ||
} | ||
|
||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.adclock.instructionset.instructions.basic | ||
|
||
import com.adclock.instructionset.Task | ||
import com.adclock.instructionset.instructions.Instruction | ||
import com.adclock.instructionset.instructions.InstructionParser | ||
import com.adclock.services.WallInteractionService | ||
|
||
class SleepInstruction(val sleep: Int) : Instruction { | ||
|
||
override fun apply(task: Task, wallService: WallInteractionService): Boolean { | ||
task.sleepUntil = System.currentTimeMillis() + sleep * 1000 | ||
return true | ||
} | ||
|
||
companion object : InstructionParser<SleepInstruction> { | ||
override val key: String | ||
get() = "SLP" | ||
|
||
override fun deserialize(input: String): SleepInstruction { | ||
require(input.isNotBlank()) { "Parameter sleep time (like 5) expected." } | ||
return SleepInstruction(input.toInt()) | ||
} | ||
|
||
override fun serialize(instruction: SleepInstruction) = instruction.sleep.toString() | ||
} | ||
|
||
} |
23 changes: 23 additions & 0 deletions
23
src/instructionset/instructions/clock/CalibrateInstruction.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.adclock.instructionset.instructions.clock | ||
|
||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.model.Clock | ||
import com.adclock.services.ClockInteractionService | ||
|
||
class CalibrateInstruction(selection: List<ClockSelection>) : ClockInstruction(selection) { | ||
override fun apply(clockService: ClockInteractionService, clock: Clock) { | ||
clockService.sendInit(clock) | ||
} | ||
|
||
companion object : ClockInstructionParser<CalibrateInstruction> { | ||
override val key: String | ||
get() = "CAL" | ||
|
||
override fun deserialize(selection: List<ClockSelection>, parameters: String): CalibrateInstruction { | ||
require(parameters.isBlank()) { "No parameters for calibrate instruction expected, but was $parameters." } | ||
return CalibrateInstruction(selection) | ||
} | ||
|
||
override fun serializeParameters(instruction: CalibrateInstruction) = "" | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.adclock.instructionset.instructions.clock | ||
|
||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.instructionset.instructions.wall.WallInstruction | ||
import com.adclock.model.Clock | ||
import com.adclock.services.ClockInteractionService | ||
import com.adclock.services.WallInteractionService | ||
import com.adclock.util.filter | ||
|
||
abstract class ClockInstruction(internal val selection: List<ClockSelection>) : WallInstruction { | ||
abstract fun apply(clockService: ClockInteractionService, clock: Clock) | ||
|
||
override fun apply(wallService: WallInteractionService) { | ||
wallService.wall.clocks.filter(selection).forEach { | ||
apply(wallService.clockService, it) | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/instructionset/instructions/clock/ClockInstructionParser.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.adclock.instructionset.instructions.clock | ||
|
||
import com.adclock.instructionset.InstructionSet | ||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.instructionset.instructions.InstructionParser | ||
|
||
interface ClockInstructionParser<T : ClockInstruction> : InstructionParser<T> { | ||
|
||
fun deserialize(selection: List<ClockSelection>, parameters: String): T | ||
fun serializeParameters(instruction: T): String | ||
|
||
override fun deserialize(input: String): T { | ||
val selection = InstructionSet.deserializeSelection(input.substringBefore(' ')) | ||
return deserialize(selection, input.substringAfter(' ', "")) | ||
} | ||
|
||
override fun serialize(instruction: T): String { | ||
return InstructionSet.serializeSelection(instruction.selection) + " " + serializeParameters(instruction) | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
src/instructionset/instructions/hand/DirectionInstruction.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.adclock.instructionset.instructions.hand | ||
|
||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.instructionset.instructions.clock.ClockInstructionParser | ||
import com.adclock.model.Direction | ||
import com.adclock.model.Hand | ||
import com.adclock.services.HandInteractionService | ||
|
||
class DirectionInstruction(selection: List<ClockSelection>, val direction: Direction) : HandInstruction(selection) { | ||
override fun apply(handService: HandInteractionService, hand: Hand) { | ||
handService.setPlannedDirection(hand, direction) | ||
} | ||
|
||
companion object : ClockInstructionParser<DirectionInstruction> { | ||
override val key: String | ||
get() = "DIR" | ||
|
||
override fun deserialize(selection: List<ClockSelection>, parameters: String): DirectionInstruction { | ||
require(parameters.isNotBlank()) { "Parameter direction ${Direction.values().map { it.name }} expected." } | ||
return DirectionInstruction(selection, Direction.valueOf(parameters)) | ||
} | ||
|
||
override fun serializeParameters(instruction: DirectionInstruction) = instruction.direction.name | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.adclock.instructionset.instructions.hand | ||
|
||
import com.adclock.instructionset.clockselections.ClockSelection | ||
import com.adclock.instructionset.instructions.clock.ClockInstruction | ||
import com.adclock.model.Clock | ||
import com.adclock.model.Hand | ||
import com.adclock.model.HandType | ||
import com.adclock.services.ClockInteractionService | ||
import com.adclock.services.HandInteractionService | ||
|
||
abstract class HandInstruction(selection: List<ClockSelection>) : ClockInstruction(selection) { | ||
abstract fun apply(handService: HandInteractionService, hand: Hand) | ||
|
||
override fun apply(clockService: ClockInteractionService, clock: Clock) { | ||
val selectedHands = selection.find { it.selected(clock) }?.hands ?: emptyArray() | ||
|
||
if (HandType.HOUR in selectedHands) | ||
apply(clockService.handService, clock.hour) | ||
|
||
if (HandType.MINUTE in selectedHands) | ||
apply(clockService.handService, clock.minute) | ||
} | ||
} |
Oops, something went wrong.