/
算盘厂.kt
165 lines (137 loc) · 6.49 KB
/
算盘厂.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package ai.hypergraph.shipshape
import org.intellij.lang.annotations.Language
@Language("kt")
fun genAbacus() = """// This file was generated by Shipshape
@file:Suppress("ObjectPropertyName", "ClassName", "PropertyName", "NonAsciiCharacters", "FunctionName", "UNUSED_PARAMETER")
package ai.hypergraph.kotlingrad.typelevel.chinese
import kotlin.jvm.JvmName
sealed class 数<丁, 己: 数<丁, 己>>(open val 中: 丁? = null, open val 码: String = "") {
val 零 get() = 零(this as 己)
val 一 get() = 一(this as 己)
val 二 get() = 二(this as 己)
val 三 get() = 三(this as 己)
val 四 get() = 四(this as 己)
val 五 get() = 五(this as 己)
val 六 get() = 六(this as 己)
val 七 get() = 七(this as 己)
val 八 get() = 八(this as 己)
val 九 get() = 九(this as 己)
override fun equals(other: Any?) = toString() == other.toString()
override fun hashCode() = this::class.hashCode() + 中.hashCode()
override fun toString() = (中 ?: "").toString() + 码
fun toInt() = toString().toArabic().toInt()
}
${genChineseDigits()}
object 无: 数<无, 无>(null)
open class 未(val i: Int, override val 码: String = i.toString().toChinese(false)): 数<未, 未>(null)
${genChineseTypes()}
${genChineseConsts()}
val z2a: Map<String, String> = mapOf(
"零" to "0", "一" to "1", "二" to "2", "三" to "3", "四" to "4",
"五" to "5", "六" to "6", "七" to "7", "八" to "8", "九" to "9",
"十" to "", "百" to "", "千" to "", "万" to "",
)
val a2z: Map<String, String> = z2a.entries.associate { (k, v) -> v to k }
// TODO: https://cs.github.com/?scopeName=All+repos&scope=&q=%E9%9B%B6+%E4%B8%80+%E4%BA%8C+%E4%B8%89+%E5%9B%9B+%E4%BA%94+%E5%85%AD+%E4%B8%83+%E5%85%AB+%E4%B9%9D+Arabic++language%3AJava
fun String.toArabic() = map { it.toString() }.joinToString("") { if (it in z2a) z2a[it]!! else it }
fun String.toChinese(skipPlaceDigits: Boolean = true) =
mapIndexed { i, c ->
val s = c.toString()
val t = a2z.getOrElse(s) { s }
if (skipPlaceDigits) t
else when (length - i) {
5 -> t + "万"
4 -> t + "千"
3 -> t + "百"
2 -> t + "十".removePrefix("一")
else -> t
}
}.let { if (!skipPlaceDigits) it.filterNot { it == "零" } else it }.joinToString("")
${genTypeLevelFunctions()}
// Gradual types
@JvmName("数加数") infix fun <左: 数<*, *>, 右: 数<*, *>> 左.加(甲: 右) = 未(toInt() + 甲.toInt())
@JvmName("数减数") infix fun <左: 数<*, *>, 右: 数<*, *>> 左.减(甲: 右) = 未(toInt() - 甲.toInt())
@JvmName("数乘数") infix fun <左: 数<*, *>, 右: 数<*, *>> 左.乘(甲: 右) = 未(toInt() * 甲.toInt())
@JvmName("数除数") infix fun <左: 数<*, *>, 右: 数<*, *>> 左.除(甲: 右) = 未(toInt() / 甲.toInt())
""".let { it + "\n// Total lines: ${it.lines().size + 1}" }
fun genChineseDigits() =
(0..9).map { it.toString() }.joinToString("\n") {
val digit = it.a2z()
"open class $digit<丁>(override val 中: 丁? = null, override val 码: String = \"$digit\")" +
": 数<丁, $digit<丁>>(中) { companion object: $digit<无>() }"
}
fun genChineseConsts() =
(10..30).map { it.toString() }.joinToString("\n") {
val withPlaceDigits = it.a2z(false)
val flatConstructor = it.zhChars().joinToString(".")
"val $withPlaceDigits: ${withPlaceDigits}型 = $flatConstructor"
}
fun genChineseTypes() =
(10..30).map { it.toString() }.joinToString("\n") {
val withPlaceDigits = it.a2z(false)
val typeConstructor = it.a2z().codify("无")
"typealias ${withPlaceDigits}型 = $typeConstructor"
}
fun main() = println(genAbacus())
fun genTypeLevelFunctions(
plusMinusRange: Set<Triple<Int, Int, Int>> = ((0..99) * (1..9))
.map { (l, r) -> Triple(l, r, l + r) }.toSet(),
timesMultRange: Set<Triple<Int, Int, Int>> = (0..99).map { i ->
i.nontrivialDivisors(99) { i % it == 0 && it > 1 && it != 10 }
}.flatten().toSet()
): String =
(plusMinusRange.flatMap { (a, b, c) ->
val (a, b, c) = Triple("$a", "$b", "$c")
listOf(TLFun(a, "+", b, c), TLFun(c, "-", b, a))
} + timesMultRange.flatMap { (a, b, c) ->
val (a, b, c) = Triple("$a", "$b", "$c")
listOf(TLFun(a, "/", b, c), TLFun(c, "*", b, a))
}).toSet().sorted().joinToString("\n", "\n", "\n")
data class TLFun(val left: String, val op: String, val right: String, val result: String) : Comparable<TLFun> {
val l2r = if (left.length == result.length && op in listOf("+", "-"))
left.zip(result).dropWhile { (ai, ci) -> ai == ci }
.fold("丁" to "丁") { acc, it -> (acc.first + it.first) to (acc.second + it.second) }
else "无$left" to "无$result"
val funName = op.a2z().codify()
val jvmName: String = l2r.first.first() + l2r.first.drop(1).a2z(false) + funName + right.a2z(false)
val recType = l2r.first.a2z().codify()
val typeParam = if ("<丁>" in recType) "<丁>" else ""
val argType = right.a2z().codify("无")
val resType = l2r.second.a2z().codify()
val initial = if ("无" in recType) "" else l2r.first.drop(1).indices.joinToString("!!.") { "中" }
val constructor = l2r.second.drop(1).a2z().codify(initial, '(', ')')
@Language("kt")
override fun toString() =
"""@JvmName("$jvmName") infix fun $typeParam $recType.$funName(甲: $argType): $resType = $constructor"""
companion object {
val comparator = compareBy<TLFun> { it.op }
.thenBy { it.right.toInt() }
.thenBy { it.left.length }
.thenBy { it.left }
}
override fun hashCode() = toString().hashCode()
override fun compareTo(other: TLFun) = comparator.compare(this, other)
override fun equals(other: Any?) = toString().hashCode() == other.toString().hashCode()
}
val z2a: Map<String, String> = mapOf(
"零" to "0", "一" to "1", "二" to "2", "三" to "3", "四" to "4",
"五" to "5", "六" to "6", "七" to "7", "八" to "8", "九" to "9",
"十" to "", "百" to "", "千" to "", "万" to "",
"加" to "+", "减" to "-", "除" to "/", "乘" to "*"
)
val a2z = z2a.entries.associate { (k, v) -> v to k }
fun String.codify(initial: String = "", lb: Char = '<', rb: Char = '>') =
fold(initial) { acc, it -> if (acc.isEmpty() && lb != '(') "$it" else "$it$lb$acc$rb" }
fun String.zhChars(skipPlaceDigits: Boolean = true) =
mapIndexed { i, c ->
val t = a2z.getOrElse("$c") { "$c" }
if (skipPlaceDigits) t
else when (length - i) {
5 -> "${t}万"
4 -> "${t}千"
3 -> "${t}百"
2 -> "${t}十".removePrefix("一")
else -> t
}
}.let { if (!skipPlaceDigits) it.filterNot { it == "零" } else it }
fun String.a2z(skipPlaceDigits: Boolean = true) = zhChars(skipPlaceDigits).joinToString("")