separate instructionset type
This commit is contained in:
@@ -1,125 +1,32 @@
|
||||
package befide.befunge.b93
|
||||
|
||||
import befide.befunge.b93.state.*
|
||||
import befide.befunge.core.*
|
||||
import befide.befunge.core.util.chooseOne
|
||||
import befide.befunge.core.events.IpChange
|
||||
import befide.befunge.core.events.StackChange
|
||||
import befide.befunge.core.util.readAll
|
||||
import befide.befunge.events.Event
|
||||
import befide.befunge.core.util.Event
|
||||
import java.io.PipedReader
|
||||
import java.io.PipedWriter
|
||||
import java.util.*
|
||||
|
||||
|
||||
class Interpreter93(stdinSrc: PipedWriter, stdoutDest: PipedReader)
|
||||
: Interpreter<Vec2, LongData, PointerMode> {
|
||||
: MutableInterpreter<Vec2, LongData, PointerMode>() {
|
||||
|
||||
override val ip = Pointer93()
|
||||
override val funge = Funge93()
|
||||
override val stack = Stack<LongData>()
|
||||
|
||||
override fun stackDefault() = LongData.ZERO
|
||||
|
||||
override val onIpChange = Event<IpChange<Vec2, PointerMode>>()
|
||||
override val onStackChange = Event<StackChange<LongData>>()
|
||||
|
||||
override val stdin: PipedReader = PipedReader(stdinSrc)
|
||||
override val stdout: PipedWriter = PipedWriter(stdoutDest)
|
||||
|
||||
private fun notifyIp(op: () -> Unit) {
|
||||
val from = ip.copy()
|
||||
op()
|
||||
val to = ip.copy()
|
||||
onIpChange(IpChange(from, to))
|
||||
}
|
||||
|
||||
private fun move(dir: Vec2? = null) = notifyIp {
|
||||
ip.pos = funge.next(ip.pos, dir ?: ip.delta)
|
||||
}
|
||||
|
||||
private fun pop(): LongData {
|
||||
val d = if (stack.empty()) LongData.ZERO else stack.pop()
|
||||
onStackChange(StackChange(StackOp.Pop, d))
|
||||
return d
|
||||
}
|
||||
|
||||
private fun push(vararg data: LongData) {
|
||||
for (d in data) {
|
||||
stack.push(d)
|
||||
onStackChange(StackChange(StackOp.Push, d))
|
||||
}
|
||||
}
|
||||
|
||||
private fun argPop(n: Int, op: (Array<LongData>) -> Unit) {
|
||||
val args = (0 until n).map { pop() }.toTypedArray()
|
||||
op(args)
|
||||
}
|
||||
|
||||
private var mode
|
||||
get() = ip.mode
|
||||
set(mode) = notifyIp { ip.mode = mode }
|
||||
|
||||
private var delta
|
||||
get() = ip.delta
|
||||
set(delta) = notifyIp { ip.delta = delta }
|
||||
|
||||
override fun step() {
|
||||
val instr = funge[ip.pos]
|
||||
|
||||
when (mode) {
|
||||
PointerMode.Terminated -> return
|
||||
PointerMode.String -> when (instr.char) {
|
||||
null -> Unit
|
||||
|
||||
'"' -> mode = PointerMode.Normal
|
||||
|
||||
else -> push(instr)
|
||||
}
|
||||
PointerMode.Normal -> when (instr.char) {
|
||||
null -> Unit
|
||||
in "0123456789abcdef" -> push(LongData(instr.char.toString().toLong(16)))
|
||||
|
||||
'+' -> argPop(2) { (b, a) -> push(a + b) }
|
||||
'-' -> argPop(2) { (b, a) -> push(a - b) }
|
||||
'*' -> argPop(2) { (b, a) -> push(a * b) }
|
||||
'/' -> argPop(2) { (b, a) -> push(a / b) }
|
||||
'%' -> argPop(2) { (b, a) -> push(a mod b) }
|
||||
'!' -> argPop(1) { (n) -> push(LongData(if (n.data == 0L) 1L else 0L)) }
|
||||
'`' -> argPop(2) { (b, a) -> push(LongData(if (a.data > b.data) 1L else 0L)) }
|
||||
|
||||
'>' -> delta = Vec2.RIGHT
|
||||
'<' -> delta = Vec2.LEFT
|
||||
'v' -> delta = Vec2.DOWN
|
||||
'^' -> delta = Vec2.UP
|
||||
'?' -> delta = Vec2.DIRS.chooseOne()
|
||||
'#' -> move()
|
||||
|
||||
'_' -> argPop(1) { (n) -> delta = if (n.data == 0L) Vec2.RIGHT else Vec2.LEFT }
|
||||
'|' -> argPop(1) { (n) -> delta = if (n.data == 0L) Vec2.DOWN else Vec2.UP }
|
||||
|
||||
'"' -> mode = PointerMode.String
|
||||
|
||||
':' -> argPop(1) { (n) -> push(n, n) }
|
||||
'\\' -> argPop(2) { (b, a) -> push(b, a) }
|
||||
'$' -> pop()
|
||||
|
||||
'.' -> argPop(1) { (n) -> stdout.write("${n.data} ") }
|
||||
',' -> argPop(1) { (ch) -> stdout.write(ch.data.toChar().toString()) }
|
||||
|
||||
'p' -> argPop(3) { (y, x, n) -> funge[Vec2(x.data.toInt(), y.data.toInt())] = n }
|
||||
'g' -> argPop(2) { (y, x) -> push(funge[Vec2(x.data.toInt(), y.data.toInt())]) }
|
||||
|
||||
'~' -> push(LongData(stdin.read().toLong()))
|
||||
'&' -> {
|
||||
val chars = generateSequence {
|
||||
stdin.read().takeIf { it.toChar().isDigit() }
|
||||
}
|
||||
val long = chars.joinToString("").toLong()
|
||||
push(LongData(long))
|
||||
}
|
||||
|
||||
'@' -> mode = PointerMode.Terminated
|
||||
}
|
||||
}
|
||||
|
||||
move()
|
||||
}
|
||||
override val instructionSet = Befunge93Instructions()
|
||||
|
||||
override fun reset() {
|
||||
stdin.readAll()
|
||||
@@ -133,9 +40,9 @@ fun main(args: Array<String>) {
|
||||
|
||||
val int = Interpreter93(stdinSrc, stdoutDest)
|
||||
|
||||
// int.onIpChange += {
|
||||
// println(it.to.pos)
|
||||
// }
|
||||
int.onIpChange += {
|
||||
println(it.to.pos)
|
||||
}
|
||||
|
||||
int.funge.src = """2>:3g" "-!v\ g30 <
|
||||
|!`"O":+1_:.:03p>03g+:"O"`|
|
||||
@@ -144,7 +51,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
while (int.ip.mode != PointerMode.Terminated) {
|
||||
int.step()
|
||||
print(stdoutDest.readAll())
|
||||
}
|
||||
|
||||
print(stdoutDest.readAll())
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package befide.befunge.b93
|
||||
|
||||
import befide.befunge.b93.state.LongData
|
||||
import befide.befunge.b93.state.PointerMode
|
||||
import befide.befunge.b93.state.Vec2
|
||||
import befide.befunge.core.InstructionSet
|
||||
import befide.befunge.core.MutableInterpreter
|
||||
import befide.befunge.core.util.chooseOne
|
||||
|
||||
class Befunge93Instructions : InstructionSet<Vec2, LongData, PointerMode> {
|
||||
override fun MutableInterpreter<Vec2, LongData, PointerMode>.handle() {
|
||||
when (mode) {
|
||||
PointerMode.Terminated -> return
|
||||
PointerMode.String -> when (instr.char) {
|
||||
null -> Unit
|
||||
'"' -> mode = PointerMode.Normal
|
||||
else -> push(instr)
|
||||
}
|
||||
PointerMode.Normal -> when (instr.char) {
|
||||
null -> Unit
|
||||
|
||||
in "0123456789abcdef" -> push(LongData(instr.char.toString().toLong(16)))
|
||||
|
||||
'+' -> pop(2).let { (b, a) -> push(a + b) }
|
||||
'-' -> pop(2).let { (b, a) -> push(a - b) }
|
||||
'*' -> pop(2).let { (b, a) -> push(a * b) }
|
||||
'/' -> pop(2).let { (b, a) -> push(a / b) }
|
||||
'%' -> pop(2).let { (b, a) -> push(a mod b) }
|
||||
'!' -> pop(1).let { (n) -> push(LongData(if (n.data == 0L) 1L else 0L)) }
|
||||
'`' -> pop(2).let { (b, a) -> push(LongData(if (a.data > b.data) 1L else 0L)) }
|
||||
|
||||
'>' -> delta = Vec2.RIGHT
|
||||
'<' -> delta = Vec2.LEFT
|
||||
'v' -> delta = Vec2.DOWN
|
||||
'^' -> delta = Vec2.UP
|
||||
'?' -> delta = Vec2.DIRS.chooseOne()
|
||||
'#' -> move()
|
||||
|
||||
'_' -> pop().let { n -> delta = if (n.data == 0L) Vec2.RIGHT else Vec2.LEFT }
|
||||
'|' -> pop().let { n -> delta = if (n.data == 0L) Vec2.DOWN else Vec2.UP }
|
||||
|
||||
'"' -> mode = PointerMode.String
|
||||
|
||||
':' -> pop().let { n -> push(n, n) }
|
||||
'\\' -> pop(2).let { (b, a) -> push(b, a) }
|
||||
'$' -> pop()
|
||||
|
||||
'.' -> pop().let { n -> stdout.write("${n.data} ") }
|
||||
',' -> pop().let { ch -> stdout.write(ch.data.toChar().toString()) }
|
||||
|
||||
'p' -> pop(3).let { (y, x, n) -> funge[Vec2(x.data.toInt(), y.data.toInt())] = n }
|
||||
'g' -> pop(2).let { (y, x) -> push(funge[Vec2(x.data.toInt(), y.data.toInt())]) }
|
||||
|
||||
'~' -> push(LongData(stdin.read().toLong()))
|
||||
'&' -> {
|
||||
val chars = generateSequence {
|
||||
stdin.read().takeIf { it.toChar().isDigit() }
|
||||
}
|
||||
val long = chars.joinToString("").toLong()
|
||||
push(LongData(long))
|
||||
}
|
||||
|
||||
'@' -> mode = PointerMode.Terminated
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package befide.befunge.b93
|
||||
package befide.befunge.b93.state
|
||||
|
||||
import befide.befunge.core.FungeChange
|
||||
import befide.befunge.core.MutableFunge
|
||||
import befide.befunge.events.Event
|
||||
import befide.befunge.core.events.FungeChange
|
||||
import befide.befunge.core.state.MutableFunge
|
||||
import befide.befunge.core.util.Event
|
||||
|
||||
class Funge93
|
||||
: MutableFunge<Vec2, LongData> {
|
||||
@@ -1,11 +1,10 @@
|
||||
package befide.befunge.b93
|
||||
package befide.befunge.b93.state
|
||||
|
||||
import befide.befunge.core.Data
|
||||
import befide.befunge.core.state.Data
|
||||
import befide.befunge.core.util.mod
|
||||
|
||||
data class LongData(val data: Long)
|
||||
: Data {
|
||||
|
||||
companion object {
|
||||
val SPACE = LongData(' ')
|
||||
val ZERO = LongData(0)
|
||||
@@ -1,6 +1,7 @@
|
||||
package befide.befunge.b93
|
||||
package befide.befunge.b93.state
|
||||
|
||||
import befide.befunge.core.MutablePointer
|
||||
import befide.befunge.core.state.MutablePointer
|
||||
import befide.befunge.core.state.Pointer
|
||||
|
||||
enum class PointerMode {
|
||||
Normal, String, Terminated
|
||||
@@ -9,4 +10,7 @@ enum class PointerMode {
|
||||
data class Pointer93(override var pos: Vec2 = Vec2.ZERO,
|
||||
override var delta: Vec2 = Vec2.RIGHT,
|
||||
override var mode: PointerMode = PointerMode.Normal)
|
||||
: MutablePointer<Vec2, PointerMode>
|
||||
: MutablePointer<Vec2, PointerMode> {
|
||||
|
||||
override fun copy(): Pointer<Vec2, PointerMode> = Pointer93(pos, delta, mode)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package befide.befunge.b93
|
||||
package befide.befunge.b93.state
|
||||
|
||||
import befide.befunge.core.util.mod
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package befide.befunge.core
|
||||
|
||||
import befide.befunge.core.state.Data
|
||||
|
||||
interface InstructionSet<V, D : Data, M : Enum<M>> {
|
||||
fun MutableInterpreter<V, D, M>.handle()
|
||||
|
||||
fun step(inter: MutableInterpreter<V, D, M>) = inter.handle()
|
||||
}
|
||||
@@ -1,69 +1,26 @@
|
||||
package befide.befunge.core
|
||||
|
||||
import befide.befunge.events.Event
|
||||
import befide.befunge.core.events.IpChange
|
||||
import befide.befunge.core.events.StackChange
|
||||
import befide.befunge.core.state.Data
|
||||
import befide.befunge.core.state.Funge
|
||||
import befide.befunge.core.state.Pointer
|
||||
import befide.befunge.core.util.Event
|
||||
import java.io.PipedReader
|
||||
import java.io.PipedWriter
|
||||
import java.util.*
|
||||
|
||||
interface Pointer<V, M : Enum<M>> {
|
||||
val pos: V
|
||||
val delta: V
|
||||
val mode: M
|
||||
}
|
||||
|
||||
interface MutablePointer<V, M : Enum<M>>
|
||||
: Pointer<V, M> {
|
||||
|
||||
override var pos: V
|
||||
override var delta: V
|
||||
override var mode: M
|
||||
}
|
||||
|
||||
interface Data {
|
||||
val char: Char?
|
||||
}
|
||||
|
||||
data class FungeChange<V, D : Data>
|
||||
(val funge: Funge<V, D>,
|
||||
val pos: V,
|
||||
val from: D,
|
||||
val to: D)
|
||||
|
||||
interface Funge<V, D : Data> {
|
||||
val size: V
|
||||
|
||||
val data: List<List<D>>
|
||||
val src: String
|
||||
|
||||
fun next(pos: V, delta: V): V
|
||||
|
||||
operator fun get(pos: V): D
|
||||
|
||||
val onChange: Event<FungeChange<V, D>>
|
||||
}
|
||||
|
||||
interface MutableFunge<V, D : Data>
|
||||
: Funge<V, D> {
|
||||
|
||||
override var data: List<List<D>>
|
||||
override var src: String
|
||||
|
||||
operator fun set(pos: V, data: D)
|
||||
}
|
||||
|
||||
data class IpChange<V, M : Enum<M>>
|
||||
(val from: Pointer<V, M>, val to: Pointer<V, M>)
|
||||
|
||||
enum class StackOp { Push, Pop }
|
||||
|
||||
data class StackChange<D : Data>
|
||||
(val op: StackOp, val data: D)
|
||||
|
||||
interface Interpreter<V, D : Data, M : Enum<M>> {
|
||||
val ip: Pointer<V, M>
|
||||
val funge: Funge<V, D>
|
||||
val stack: List<D>
|
||||
|
||||
fun stackDefault(): D
|
||||
|
||||
val mode: M get() = ip.mode
|
||||
val delta: V get() = ip.delta
|
||||
val pos: V get() = ip.pos
|
||||
val instr: D get() = funge[ip.pos]
|
||||
|
||||
val onIpChange: Event<IpChange<V, M>>
|
||||
val onStackChange: Event<StackChange<D>>
|
||||
|
||||
@@ -72,4 +29,5 @@ interface Interpreter<V, D : Data, M : Enum<M>> {
|
||||
|
||||
fun step()
|
||||
fun reset()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package befide.befunge.core
|
||||
|
||||
import befide.befunge.core.events.IpChange
|
||||
import befide.befunge.core.events.StackChange
|
||||
import befide.befunge.core.events.StackOp
|
||||
import befide.befunge.core.state.Data
|
||||
import befide.befunge.core.state.MutableFunge
|
||||
import befide.befunge.core.state.MutablePointer
|
||||
import java.util.*
|
||||
|
||||
abstract class MutableInterpreter<V, D : Data, M : Enum<M>>
|
||||
: Interpreter<V, D, M> {
|
||||
abstract override val ip: MutablePointer<V, M>
|
||||
abstract override val funge: MutableFunge<V, D>
|
||||
abstract override val stack: Stack<D>
|
||||
|
||||
abstract val instructionSet: InstructionSet<V, D, M>
|
||||
|
||||
override fun step() {
|
||||
instructionSet.step(this)
|
||||
move()
|
||||
}
|
||||
|
||||
fun notifyIp(op: () -> Unit) {
|
||||
val from = ip.copy()
|
||||
op()
|
||||
val to = ip.copy()
|
||||
onIpChange(IpChange(from, to))
|
||||
}
|
||||
|
||||
fun notifyStack(op: StackOp, block: () -> D): D {
|
||||
val res = block()
|
||||
onStackChange(StackChange(op, res))
|
||||
return res
|
||||
}
|
||||
|
||||
override var mode: M
|
||||
get() = ip.mode
|
||||
set(mode) = notifyIp { ip.mode = mode }
|
||||
|
||||
override var delta: V
|
||||
get() = ip.delta
|
||||
set(delta) = notifyIp { ip.delta = delta }
|
||||
|
||||
override var pos: V
|
||||
get() = ip.pos
|
||||
set(pos) = notifyIp { ip.pos = pos }
|
||||
|
||||
fun move(delta: V? = null) {
|
||||
pos = funge.next(pos, delta ?: this.delta)
|
||||
}
|
||||
|
||||
fun pop(): D = notifyStack(StackOp.Pop) {
|
||||
if (stack.empty()) stackDefault() else stack.pop()
|
||||
}
|
||||
|
||||
fun pop(n: Int): List<D> {
|
||||
return (0 until n).map { notifyStack(StackOp.Pop) { stack.pop() } }
|
||||
}
|
||||
|
||||
fun push(vararg data: D) {
|
||||
for (datum in data) {
|
||||
notifyStack(StackOp.Push) { stack.push(datum) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package befide.befunge.core.events
|
||||
|
||||
import befide.befunge.core.state.Data
|
||||
import befide.befunge.core.state.Funge
|
||||
|
||||
data class FungeChange<V, D : Data>
|
||||
(val funge: Funge<V, D>,
|
||||
val pos: V,
|
||||
val from: D,
|
||||
val to: D)
|
||||
@@ -0,0 +1,6 @@
|
||||
package befide.befunge.core.events
|
||||
|
||||
import befide.befunge.core.state.Pointer
|
||||
|
||||
data class IpChange<V, M : Enum<M>>
|
||||
(val from: Pointer<V, M>, val to: Pointer<V, M>)
|
||||
@@ -0,0 +1,8 @@
|
||||
package befide.befunge.core.events
|
||||
|
||||
import befide.befunge.core.state.Data
|
||||
|
||||
enum class StackOp { Push, Pop }
|
||||
|
||||
data class StackChange<D : Data>
|
||||
(val op: StackOp, val data: D)
|
||||
@@ -0,0 +1,5 @@
|
||||
package befide.befunge.core.state
|
||||
|
||||
interface Data {
|
||||
val char: Char?
|
||||
}
|
||||
17
befunge/src/main/kotlin/befide/befunge/core/state/Funge.kt
Normal file
17
befunge/src/main/kotlin/befide/befunge/core/state/Funge.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package befide.befunge.core.state
|
||||
|
||||
import befide.befunge.core.events.FungeChange
|
||||
import befide.befunge.core.util.Event
|
||||
|
||||
interface Funge<V, D : Data> {
|
||||
val size: V
|
||||
|
||||
val data: List<List<D>>
|
||||
val src: String
|
||||
|
||||
fun next(pos: V, delta: V): V
|
||||
|
||||
operator fun get(pos: V): D
|
||||
|
||||
val onChange: Event<FungeChange<V, D>>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package befide.befunge.core.state
|
||||
|
||||
interface MutableFunge<V, D : Data>
|
||||
: Funge<V, D> {
|
||||
|
||||
override var data: List<List<D>>
|
||||
override var src: String
|
||||
|
||||
operator fun set(pos: V, data: D)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package befide.befunge.core.state
|
||||
|
||||
interface MutablePointer<V, M : Enum<M>>
|
||||
: Pointer<V, M> {
|
||||
|
||||
override var pos: V
|
||||
override var delta: V
|
||||
override var mode: M
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package befide.befunge.core.state
|
||||
|
||||
interface Pointer<V, M : Enum<M>> {
|
||||
val pos: V
|
||||
val delta: V
|
||||
val mode: M
|
||||
|
||||
fun copy(): Pointer<V, M>
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package befide.befunge.events
|
||||
package befide.befunge.core.util
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package befide.befunge.core.util
|
||||
|
||||
import java.io.PipedReader
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@@ -21,3 +22,7 @@ fun <T> List<T>.chooseOne(): T = this[Random.nextInt(size)]
|
||||
fun PipedReader.readAll(): String = generateSequence {
|
||||
if (ready()) read().toChar() else null
|
||||
}.joinToString("")
|
||||
|
||||
inline fun <reified T> Stack<T>.pop(n: Int): List<T> {
|
||||
return (0 until n).map { pop() }
|
||||
}
|
||||
Reference in New Issue
Block a user