diff --git a/befunge/befunge.iml b/befunge/befunge.iml index 6cea5be..c1a7461 100644 --- a/befunge/befunge.iml +++ b/befunge/befunge.iml @@ -7,7 +7,7 @@ @@ -37,5 +37,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/befunge/src/main/kotlin/befide/befunge/b93/B93Funge.kt b/befunge/src/main/kotlin/befide/befunge/b93/B93Funge.kt index c7019d4..5244407 100644 --- a/befunge/src/main/kotlin/befide/befunge/b93/B93Funge.kt +++ b/befunge/src/main/kotlin/befide/befunge/b93/B93Funge.kt @@ -6,21 +6,57 @@ import befide.befunge.state.* class B93Funge : Funge { override val width = 80 override val height = 25 + private var cars = Array(height) { Array(width) {' '.toLong()}} override fun get(vec: Vec): Value { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return Value(cars[vec.y][vec.x]) } override fun set(vec: Vec, value: Value) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + cars[vec.y][vec.x] = value.value } override fun nextVec(vec: Vec, delta: Vec): Vec { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + var x = vec.x + delta.x + var y = vec.y + delta.y + if (x >= width || x < 0) { + x %= width + } + if (x < 0) { + x += width + } + if (y >= height || y < 0) { + y %= height + } + if (y < 0) { + y += height + } + + return Vec(x,y) } override fun setString(data: String) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + val strings = data.split('\n') + for (i in strings.size until height) { + cars[i] = Array(width) {' '.toLong()} + } + strings.map { + it.toList().map{it.toLong()} + } + .forEachIndexed { index, list -> + if (index > height) { + return + } + cars[index] = ( + list.toList() + List( + if (list.size <= width) width - list.size else 0 + ){ + ' '.toLong() + } + ) + .subList(0, width) + .toTypedArray() + } } } diff --git a/befunge/src/main/kotlin/befide/befunge/b93/B93Interpreter.kt b/befunge/src/main/kotlin/befide/befunge/b93/B93Interpreter.kt index 4cfa6f5..ae01f99 100644 --- a/befunge/src/main/kotlin/befide/befunge/b93/B93Interpreter.kt +++ b/befunge/src/main/kotlin/befide/befunge/b93/B93Interpreter.kt @@ -1,16 +1,21 @@ package befide.befunge.b93 import befide.befunge.core.Interpreter -import befide.befunge.events.Event -import befide.befunge.events.FungeEvent -import befide.befunge.events.IpEvent -import befide.befunge.events.StackEvent +import befide.befunge.core.Pointer +import befide.befunge.events.* import befide.befunge.state.IpMode import befide.befunge.state.Value import befide.befunge.state.Vec import java.util.* class B93Interpreter : Interpreter { + private companion object { + val RIGHT = Vec(1, 0) + val LEFT = Vec(-1, 0) + val UP = Vec(0, -1) + val DOWN = Vec(0,1) + } + override val funge = B93Funge() override val stack = Stack() override val ip = B93Pointer(Vec(0, 0), Vec(1, 0), IpMode.Normal) @@ -19,11 +24,229 @@ class B93Interpreter : Interpreter { override val stackChanged: Event = Event() override val ipChanged: Event = Event() + private val fungeMods = HashMap() + + + private fun binop(bop: Char) { + val vb = stack.pop() + val va = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vb, va))) + val a = va.value + val b = vb.value + val res = when(bop) { + '+' -> a + b + '-' -> a - b + '*' -> a * b + '/' -> a / b + '`' -> if (a > b) 1L else 0L + else -> null + } + if (res != null) { + val vres = Value(res) + stack.push(vres) + stackChanged.invoke(StackEvent(StackAction.Push, listOf(vres))) + } + } + + private fun unop(uop: Char) { + val vv = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vv))) + val v = vv.value + val res = when(uop) { + '!' -> if (v == 0L) 1L else 0L + else -> null + } + if (res != null) { + val vres = Value(res) + stack.push(vres) + stackChanged.invoke(StackEvent(StackAction.Push, listOf(vres))) + } + } + + private fun changeDir(dir: Char) { + val newDelta = when(dir) { + '>' -> RIGHT + '<' -> LEFT + '^' -> UP + 'v' -> DOWN + else -> null + } + if (newDelta != null) { + ip.delta = newDelta + } + } + + private fun randomDir() { + val dirs = listOf('<', '>', '^', 'v') + val ind = Random().nextInt(4) + changeDir(dirs[ind]) + } + + private fun conditional(cop: Char) { + val vcond = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vcond))) + val cond = vcond.value == 0L + val newDelta = when(cop) { + '|' -> if (cond) DOWN else UP + '_' -> if (cond) RIGHT else LEFT + else -> null + } + if (newDelta != null) { + ip.delta = newDelta + } + } + + private fun toggleStrmode() { + val newMode = when (ip.mode) { + IpMode.String -> IpMode.Normal + IpMode.Normal -> IpMode.String + IpMode.Inactive -> IpMode.Inactive + } + ip.mode = newMode + } + + private fun stackop(sop: Char) { + val vv2 = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vv2))) + when (sop) { + ':' -> { + val vv2c = vv2.copy() + stack.push(vv2) + stack.push(vv2c) + stackChanged.invoke(StackEvent(StackAction.Push, listOf(vv2, vv2c))) + } + '\\' -> { + val vv1 = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vv2))) + stack.push(vv2) + stack.push(vv1) + stackChanged.invoke(StackEvent(StackAction.Push, listOf(vv1, vv2))) + } + '$' -> noOp() + } + } + + private fun output(type: Char) { + val vv = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vv))) + val v = vv.value + val out = when (type) { + '.' -> v.toString().toCharArray() + ',' -> charArrayOf(v.toChar()) + else -> charArrayOf() + } + //TODO output {out} chararray + } + + private fun stepIP() { + ip.pos = funge.nextVec(ip.pos, ip.delta) + // No ipChanged here, shown in execInstr + } + + private fun input() { + val inp = 0L //TODO get input + val vinp = Value(inp) + stack.push(vinp) + stackChanged(StackEvent(StackAction.Push, listOf(vinp))) + } + + private fun fget() { + val vy = stack.pop() + val vx = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vy, vx))) + val x = vx.value.toInt() + val y = vy.value.toInt() + if (0 <= x && x < funge.width && 0 <= y && y <= funge.height) { + val vv = funge[Vec(x, y)] + stack.push(vv) + stackChanged(StackEvent(StackAction.Push, listOf(vv))) + } + } + + private fun fput() { + val vy = stack.pop() + val vx = stack.pop() + val vv = stack.pop() + stackChanged.invoke(StackEvent(StackAction.Pop, listOf(vy, vx, vv))) + val x = vx.value.toInt() + val y = vy.value.toInt() + if (0 <= x && x < funge.width && 0 <= y && y <= funge.height) { + val loc = Vec(x, y) + val old = funge[loc] + funge[loc] = vv + if (!fungeMods.contains(loc)) { + fungeMods[loc] = old + } + fungeChanged(FungeEvent(listOf(FungeChange(loc,old,vv)))) + } + } + + private fun terminate() { + ip.mode = IpMode.Inactive + } + + private fun noOp() {} + + private fun execInstr(instr: Value) { + val car = instr.asChar + when (car) { + null -> noOp() + '+', '-', '*', '/', '%', '`' -> binop(car) + '!' -> unop(car) + '>', '<', '^', 'v' -> changeDir(car) + '?' -> randomDir() + '_', '|' -> conditional(car) + '"' -> toggleStrmode() + ':', '\\', '$' -> stackop(car) + '.', ',' -> output(car) + '#' -> stepIP() + 'g' -> fget() + 'p' -> fput() + '&', '~' -> input() + '@' -> terminate() + else -> noOp() + } + } + + private fun pushCar(v: Value) { + stack.push(v) + stackChanged(StackEvent(StackAction.Push, listOf(v))) + } + override fun step(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + val instr = funge[ip.pos] + val currIP = ip.copy() + when (ip.mode) { + IpMode.Inactive -> noOp() + IpMode.Normal -> execInstr(instr) + IpMode.String -> pushCar(instr) + } + if (ip.mode != IpMode.Inactive) { + stepIP() + while (funge[ip.pos].asChar == ' ') { + stepIP() + } + val newIP = ip.copy() + ipChanged(IpEvent(currIP, newIP)) + } + return true } override fun reset() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + val oldIP = ip.copy() + ip.pos = Vec(0,0) + ip.delta = RIGHT + ip.mode = IpMode.Normal + val newIP = ip.copy() + ipChanged.invoke(IpEvent(oldIP, newIP)) + + stack.clear() + stackChanged(StackEvent(StackAction.Clear, listOf())) + + val changes = fungeMods.map { FungeChange(it.key, funge[it.key], it.value) } + for ((k,v) in fungeMods) { + funge[k] = v + } + fungeChanged(FungeEvent(changes)) } } \ No newline at end of file diff --git a/befunge/src/main/kotlin/befide/befunge/b93/B93Pointer.kt b/befunge/src/main/kotlin/befide/befunge/b93/B93Pointer.kt index f1a2fdf..ffadaf5 100644 --- a/befunge/src/main/kotlin/befide/befunge/b93/B93Pointer.kt +++ b/befunge/src/main/kotlin/befide/befunge/b93/B93Pointer.kt @@ -4,4 +4,4 @@ import befide.befunge.core.Pointer import befide.befunge.state.IpMode import befide.befunge.state.Vec -data class B93Pointer(override val pos: Vec, override val delta: Vec, override val mode: IpMode) : Pointer \ No newline at end of file +data class B93Pointer(override var pos: Vec, override var delta: Vec, override var mode: IpMode) : Pointer \ No newline at end of file diff --git a/befunge/src/main/kotlin/befide/befunge/state/IpMode.kt b/befunge/src/main/kotlin/befide/befunge/state/IpMode.kt index 511168b..16af492 100644 --- a/befunge/src/main/kotlin/befide/befunge/state/IpMode.kt +++ b/befunge/src/main/kotlin/befide/befunge/state/IpMode.kt @@ -3,6 +3,5 @@ package befide.befunge.state enum class IpMode { Normal, String, - Char, Inactive } \ No newline at end of file diff --git a/befunge/src/main/kotlin/befide/befunge/state/Value.kt b/befunge/src/main/kotlin/befide/befunge/state/Value.kt index 3884051..dd469fe 100644 --- a/befunge/src/main/kotlin/befide/befunge/state/Value.kt +++ b/befunge/src/main/kotlin/befide/befunge/state/Value.kt @@ -1,7 +1,7 @@ package befide.befunge.state -data class Value(val value: Int) { - constructor(value: Char) : this(value.toInt()) +data class Value(val value: Long) { + constructor(value: Char) : this(value.toLong()) val asChar: Char? = if (value in (32..126)) value.toChar() else null } \ No newline at end of file diff --git a/ide/ide.iml b/ide/ide.iml index d51fa71..176e2b1 100644 --- a/ide/ide.iml +++ b/ide/ide.iml @@ -7,7 +7,7 @@ @@ -29,6 +29,21 @@ + + + + + + + + + + + + + + +