Skip to content

Instantly share code, notes, and snippets.

@Pooh3Mobi
Last active September 26, 2018 03:40
Show Gist options
  • Save Pooh3Mobi/8ca131901ac9968eadab170e2db74a90 to your computer and use it in GitHub Desktop.
Save Pooh3Mobi/8ca131901ac9968eadab170e2db74a90 to your computer and use it in GitHub Desktop.
スタックをつかって電卓風な計算ができるようにしてみた(これ以上の修正は非公開)
typealias Bk = State.Bk
typealias Add = Op.Add
typealias Sub = Op.Subtract
typealias Div = Op.Divide
typealias Mul = Op.Multiply
fun main(args: Array<String>) {
val e: Stack<In> = Stack.empty(In.Num(0))
//1
val e1 = e.put(1)
assertEquals(e1.toState(), State(null, "1"))
//1
val e11 = e1.put(1)
assertEquals(e11.toState(), State(null, "11"))
//+
val e11add = e11.put(Add)
assertEquals(e11add.toState(), State(Add, "11", Bk("11", null), true))
//2
val e11add2 = e11add.put(2)
assertEquals(e11add2.toState(), State(Add, "2", Bk("11", null), false))
//3
val e11add23 = e11add2.put(3)
assertEquals(e11add23.toState(), State(Add, "23", Bk("11", null), false))
//-
val e11add23sub = e11add23.put(Sub)
assertEquals(e11add23sub.toState(), State(Sub, "34", Bk("34", Add), true))
//2
val e11add23sub2 = e11add23sub.put(2)
assertEquals(e11add23sub2.toState(), State(Sub, "2", Bk("34", Add), false))
//.
val e11add23sub2dot = e11add23sub2.put(In.Dot)
assertEquals(e11add23sub2dot.toState(), State(Sub, "2.", Bk("34", Add), false))
//5
val e11add23sub2dot5 = e11add23sub2dot.put(5)
assertEquals(e11add23sub2dot5.toState(), State(Sub, "2.5", Bk("34", Add), false))
//=
val e11add23sub2dot5eval = e11add23sub2dot5.put(Op.Evaluate)
assertEquals(e11add23sub2dot5eval.toState(), State(null, "31.5", Bk("31.5", Sub), true))
//back
val e11add23sub2dot5evalback = e11add23sub2dot5eval.back()
assertEquals(e11add23sub2dot5evalback?.toState(), State(Sub, "2.5", Bk("34", Add), false))
//back x 4 =: (11+2) x 4 = 52
val e11add23backmul4eval = e11add23.back()?.put(Mul)?.put(4)?.put(Op.Evaluate)
assertEquals(e11add23backmul4eval?.toState(), State(null, "52", Bk("52", Mul), true))
}
package com.example.calc
/*
Copyright 2018 Pooh3Mobi@GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
sealed class In {
data class Num(val x: Int) : In()
object Dot : In()
data class MathOp(val op: Op) : In()
}
sealed class Op(val op: String) {
object Add : Op("+")
object Subtract : Op("-")
object Multiply : Op("×")
object Divide : Op("÷")
object Evaluate : Op("=")
}
fun Stack<In>.put(x: Int) = Stack(In.Num(x), this)
fun Stack<In>.put(op: Op) = Stack(In.MathOp(op), this)
fun Stack<In>.put(input: In) = Stack(input, this)
fun Stack<In>.back() = this.stack
fun Stack<In>.toState(): State {
return this.toList().foldRight(State.empty()) { input, state -> state.withInput(input)}.let {
it.copy(
numStr = it.numStr?.removeSuffix(".0"),
bk = it.bk?.copy(numStr = it.bk.numStr?.removeSuffix(".0"))
)
}
}
data class State(
val op: Op?,
val numStr: String?,
val bk: Bk? = null,
val isOpChanged: Boolean = false
){
companion object {
fun empty() = State(null, null)
}
fun withInput(input: In): State {
return when(input) {
is In.Num -> withNum(input.x)
is In.Dot -> withDot()
is In.MathOp -> withOp(input.op)
}
}
private fun withOp(newOp: Op): State {
// 仕様に依存する。変更があり得そう
return if (op == newOp) {
copy(isOpChanged = true)
} else {
val newNumStr = op?.let {
when(it) {
is Add -> bk?.numStr?.toDouble() + numStr?.toDouble()
is Sub -> bk?.numStr?.toDouble() - numStr?.toDouble()
is Mul -> bk?.numStr?.toDouble() * numStr?.toDouble()
is Div -> bk?.numStr?.toDouble() / numStr?.toDouble()
else -> throw IllegalArgumentException()
}.toString()
}?: numStr
copy(
op = if (newOp is Op.Evaluate) null else newOp,
numStr = newNumStr,
bk = Bk(numStr = newNumStr, op = op),
isOpChanged = true
)
}
}
private fun withDot(): State = copy(numStr = "$numStr.")
private fun withNum(x: Int): State {
val numStr = if (isOpChanged) null else numStr
return copy(
numStr = numStr?.let {
if (it == "0") "$x"
else it + x
} ?: if (x == 0) null else "$x",
isOpChanged = false
)
}
data class Bk(
val numStr: String?,
val op: Op?
)
}
package com.example.calc
/*
Copyright 2018 Pooh3Mobi@GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
data class Stack<out T>(val value: T, val stack: Stack<T>?) {
companion object {
fun <T> empty(default: T) = Stack(default, null)
}
}
tailrec fun <T> Stack<T>?.toList(
list: MutableList<T> = mutableListOf()
): List<T> {
return if (this == null) list
else stack.toList(list.apply { add(value) })
}
package com.example.calc
operator fun Double?.plus(num: Double?): Double = (this ?: 0.0) + (num ?: 0.0)
operator fun Double?.minus(num: Double?): Double = (this ?: 0.0) - (num ?: 0.0)
operator fun Double?.times(num: Double?): Double = (this ?: 0.0) * (num ?: 0.0)
operator fun Double?.div(num: Double?): Double = (this ?: 0.0) / (num ?: 0.0)
fun assertEquals(x: Any?, y: Any?) = run { println("x = $x \ny = $y") }.also { if (x == y) Unit else throw AssertionError() }
@Pooh3Mobi
Copy link
Author

Pooh3Mobi commented Sep 26, 2018

This Code License is MIT.

===========================================================================================
Copyright 2018 Pooh3Mobi@GitHub

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@Pooh3Mobi
Copy link
Author

Pooh3Mobi commented Sep 26, 2018

このコードは無償で修正、利用し再配布できます。
問題がある場合は修正をいれて商用コードに入れても何ら問題はないです。
ただしこのコードによって何か損害が起きても当方の責任は一切ないものとします。
copy-leftの観点上ライセンス表記は必ず入れるようにしてください。

機能の特徴について:
Stackを使う事で戻る機能を実装しています。
想定された利用方法はトラブルを避けるため伏せますが、想定された利用方法範囲内では過去のいつのStackの状態から別の電卓の操作を行っても、他の履歴には影響がないはずなので、ある時点まで保存、再ロードし編集状態を以前の状態に再生するという事が容易にできると思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment