From 534c88993e735e7127b72bc9a6b10da14d8cf535 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Wed, 19 Aug 2026 11:48:16 +0800 Subject: [PATCH] feat: add local hexagram content for offline reading Load a versioned Wikisource jing plus project-authored plain drafts so results can show labeled original and vernacular texts without unauthorized modern translations. Co-authored-by: Cursor --- app/build.gradle.kts | 5 + .../net/opcapp/flash/app/MainActivityTest.kt | 23 +- .../java/net/opcapp/flash/app/LingjiApp.kt | 9 + .../opcapp/flash/core/model/ContentSource.kt | 34 + .../AssetsHexagramContentRepository.kt | 55 + .../data/content/HexagramContentParser.kt | 340 +++ .../data/content/HexagramContentRepository.kt | 2 + .../opcapp/flash/data/content/JsonSupport.kt | 202 ++ .../net/opcapp/flash/data/di/ContentModule.kt | 19 + .../flash/feature/casting/CastingViewModel.kt | 64 +- .../feature/content/ContentSourcesScreen.kt | 121 + .../opcapp/flash/feature/home/HomeScreen.kt | 7 + .../flash/feature/home/HomeViewModel.kt | 10 + .../flash/feature/result/CastResultScreen.kt | 116 +- app/src/main/res/values/strings.xml | 18 +- .../content/FakeHexagramContentRepository.kt | 10 + .../data/content/HexagramContentParserTest.kt | 39 + content/packages/hexagram-content.json | 2458 +++++++++++++++++ content/plain/lingji-plain.mjs | 67 + content/raw/zhouyi-wikisource-jing.json | 1602 +++++++++++ docs/README.md | 3 +- docs/architecture.md | 2 +- docs/content-review.md | 34 + docs/data-content.md | 4 +- docs/decisions.md | 26 +- docs/dependency-licenses.md | 2 +- docs/environment.md | 2 +- docs/implementation-plan.md | 22 +- docs/quality-gates.md | 2 +- docs/ux-design.md | 2 +- scripts/build-hexagram-package.mjs | 85 + scripts/import-zhouyi-wikisource.mjs | 221 ++ scripts/verify-content-contract.mjs | 49 + 33 files changed, 5626 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/net/opcapp/flash/core/model/ContentSource.kt create mode 100644 app/src/main/java/net/opcapp/flash/data/content/AssetsHexagramContentRepository.kt create mode 100644 app/src/main/java/net/opcapp/flash/data/content/HexagramContentParser.kt create mode 100644 app/src/main/java/net/opcapp/flash/data/content/JsonSupport.kt create mode 100644 app/src/main/java/net/opcapp/flash/data/di/ContentModule.kt create mode 100644 app/src/main/java/net/opcapp/flash/feature/content/ContentSourcesScreen.kt create mode 100644 app/src/test/java/net/opcapp/flash/data/content/HexagramContentParserTest.kt create mode 100644 content/packages/hexagram-content.json create mode 100644 content/plain/lingji-plain.mjs create mode 100644 content/raw/zhouyi-wikisource-jing.json create mode 100644 docs/content-review.md create mode 100644 scripts/build-hexagram-package.mjs create mode 100644 scripts/import-zhouyi-wikisource.mjs diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0ca9aeb..05dce01 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -57,6 +57,11 @@ android { resources.excludes += "/META-INF/{AL2.0,LGPL2.1}" } + sourceSets { + getByName("main").assets.srcDir(rootProject.file("content/packages")) + getByName("test").resources.srcDir(rootProject.file("content/packages")) + } + testOptions { unitTests.isReturnDefaultValues = true } diff --git a/app/src/androidTest/java/net/opcapp/flash/app/MainActivityTest.kt b/app/src/androidTest/java/net/opcapp/flash/app/MainActivityTest.kt index aa0133d..6f8d68d 100644 --- a/app/src/androidTest/java/net/opcapp/flash/app/MainActivityTest.kt +++ b/app/src/androidTest/java/net/opcapp/flash/app/MainActivityTest.kt @@ -76,14 +76,33 @@ class MainActivityTest { fun autoSaveSettingIsRealAndReflectedOnHome() { openHome() composeRule.onNodeWithText("管理保存设置").performClick() + composeRule.waitUntil(timeoutMillis = 5_000) { + composeRule.onAllNodesWithTag("auto_save_history").fetchSemanticsNodes().isNotEmpty() + } composeRule.onNodeWithTag("auto_save_history").assertIsOn().performClick() - composeRule.onNodeWithTag("auto_save_history").assertIsOff() + composeRule.waitUntil(timeoutMillis = 5_000) { + runCatching { + composeRule.onNodeWithTag("auto_save_history").assertIsOff() + true + }.getOrDefault(false) + } composeRule.onNodeWithText("返回").performClick() + composeRule.waitUntil(timeoutMillis = 5_000) { + composeRule.onAllNodesWithText("自动保存完整记录:已关闭").fetchSemanticsNodes().isNotEmpty() + } composeRule.onNodeWithText("自动保存完整记录:已关闭").assertIsDisplayed() composeRule.onNodeWithText("管理保存设置").performClick() + composeRule.waitUntil(timeoutMillis = 5_000) { + composeRule.onAllNodesWithTag("auto_save_history").fetchSemanticsNodes().isNotEmpty() + } composeRule.onNodeWithTag("auto_save_history").performClick() - composeRule.onNodeWithTag("auto_save_history").assertIsOn() + composeRule.waitUntil(timeoutMillis = 5_000) { + runCatching { + composeRule.onNodeWithTag("auto_save_history").assertIsOn() + true + }.getOrDefault(false) + } } @Test diff --git a/app/src/main/java/net/opcapp/flash/app/LingjiApp.kt b/app/src/main/java/net/opcapp/flash/app/LingjiApp.kt index d9457bc..55dbc1e 100644 --- a/app/src/main/java/net/opcapp/flash/app/LingjiApp.kt +++ b/app/src/main/java/net/opcapp/flash/app/LingjiApp.kt @@ -12,6 +12,7 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import net.opcapp.flash.feature.casting.CastingScreen import net.opcapp.flash.feature.casting.CastingViewModel +import net.opcapp.flash.feature.content.ContentSourcesScreen import net.opcapp.flash.feature.home.HomeScreen import net.opcapp.flash.feature.home.HomeViewModel import net.opcapp.flash.feature.onboarding.MethodIntroScreen @@ -27,6 +28,7 @@ private object Destination { const val Casting = "casting" const val Result = "result" const val Settings = "settings" + const val Sources = "sources" } @Composable @@ -78,6 +80,7 @@ fun LingjiApp( }, onOpenSettings = { navController.navigate(Destination.Settings) }, onOpenMethodIntro = { navController.navigate(Destination.Welcome) }, + onOpenContentSources = { navController.navigate(Destination.Sources) }, ) } composable(Destination.Question) { @@ -127,5 +130,11 @@ fun LingjiApp( onBack = navController::popBackStack, ) } + composable(Destination.Sources) { + ContentSourcesScreen( + manifest = homeState.contentManifest, + onBack = navController::popBackStack, + ) + } } } diff --git a/app/src/main/java/net/opcapp/flash/core/model/ContentSource.kt b/app/src/main/java/net/opcapp/flash/core/model/ContentSource.kt new file mode 100644 index 0000000..e03e428 --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/core/model/ContentSource.kt @@ -0,0 +1,34 @@ +package net.opcapp.flash.core.model + +data class ContentSource( + val id: String, + val title: String, + val edition: String, + val license: String, + val url: String, +) { + init { + require(id.isNotBlank()) { "Source id must not be blank" } + require(title.isNotBlank()) { "Source title must not be blank" } + require(edition.isNotBlank()) { "Source edition must not be blank" } + require(license.isNotBlank()) { "Source license must not be blank" } + require(url.isNotBlank()) { "Source url must not be blank" } + } +} + +data class ContentManifest( + val contentVersion: String, + val digest: String, + val sources: List, + val loadError: String? = null, +) { + init { + require(contentVersion.isNotBlank()) { "Content version must not be blank" } + require(loadError == null || loadError.isNotBlank()) { + "Content load error must be non-blank or null" + } + require(sources.map(ContentSource::id).distinct().size == sources.size) { + "Content sources must have unique ids" + } + } +} diff --git a/app/src/main/java/net/opcapp/flash/data/content/AssetsHexagramContentRepository.kt b/app/src/main/java/net/opcapp/flash/data/content/AssetsHexagramContentRepository.kt new file mode 100644 index 0000000..d7bbf0c --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/data/content/AssetsHexagramContentRepository.kt @@ -0,0 +1,55 @@ +package net.opcapp.flash.data.content + +import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton +import net.opcapp.flash.core.model.ContentManifest +import net.opcapp.flash.core.model.HexagramContent + +@Singleton +class AssetsHexagramContentRepository @Inject constructor( + @ApplicationContext context: Context, +) : HexagramContentRepository { + private val parsed: Result by lazy { + runCatching { + context.assets.open(ASSET_NAME).bufferedReader(Charsets.UTF_8).use { reader -> + HexagramContentParser.parse(reader.readText()) + } + } + } + + override val contentVersion: String + get() = parsed.getOrNull()?.manifest?.contentVersion ?: UNAVAILABLE_VERSION + + override val manifest: ContentManifest + get() = parsed.getOrNull()?.manifest ?: ContentManifest( + contentVersion = UNAVAILABLE_VERSION, + digest = "unavailable", + sources = emptyList(), + loadError = parsed.exceptionOrNull()?.message ?: "Content package could not be loaded", + ) + + override fun contentFor( + kingWenNumber: Int, + requestedContentVersion: String, + ): HexagramContent { + val pack = parsed.getOrElse { error -> + throw ContentIntegrityException( + error.message ?: "Content package failed integrity checks", + ) + } + if (requestedContentVersion != pack.manifest.contentVersion) { + throw ContentIntegrityException( + "Requested content version '$requestedContentVersion' is unavailable; loaded '${pack.manifest.contentVersion}'", + ) + } + return pack.hexagrams[kingWenNumber] + ?: throw ContentIntegrityException("No validated content for King Wen number $kingWenNumber") + } + + companion object { + const val ASSET_NAME = "hexagram-content.json" + const val UNAVAILABLE_VERSION = "unavailable" + } +} diff --git a/app/src/main/java/net/opcapp/flash/data/content/HexagramContentParser.kt b/app/src/main/java/net/opcapp/flash/data/content/HexagramContentParser.kt new file mode 100644 index 0000000..dfa87f6 --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/data/content/HexagramContentParser.kt @@ -0,0 +1,340 @@ +package net.opcapp.flash.data.content + +import net.opcapp.flash.core.model.ContentManifest +import net.opcapp.flash.core.model.ContentSource +import net.opcapp.flash.core.model.HexagramContent +import net.opcapp.flash.core.model.HexagramNames +import net.opcapp.flash.domain.casting.HexagramCatalog +import net.opcapp.flash.domain.casting.HexagramPattern +import net.opcapp.flash.domain.casting.Polarity + +data class ParsedHexagramContentPackage( + val manifest: ContentManifest, + val hexagrams: Map, +) + +object HexagramContentParser { + private val unsafeText = + Regex("(?:<\\s*script\\b|javascript\\s*:|\\bon\\w+\\s*=|[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f])") + + fun parse(json: String): ParsedHexagramContentPackage { + val root = try { + JsonReader(json).readValue() as? JsonValue.Obj + ?: throw ContentIntegrityException("Content package must be a JSON object") + } catch (error: ContentIntegrityException) { + throw error + } catch (error: IllegalStateException) { + throw ContentIntegrityException(error.message ?: "Content package JSON is invalid") + } + val errors = mutableListOf() + + val schemaVersion = root.int("schemaVersion", errors) + if (schemaVersion != 1) errors += "schemaVersion must be 1" + val contentVersion = root.text("contentVersion", errors) + + val usage = root.obj("specialUsageTexts", errors) + val qianUsage = usage?.bool("qian", errors) + val kunUsage = usage?.bool("kun", errors) + + val sourceNodes = root.arr("sources", errors) + val sources = mutableListOf() + val sourceIds = mutableSetOf() + sourceNodes?.forEachIndexed { index, node -> + val prefix = "sources[$index]" + val obj = node as? JsonValue.Obj + if (obj == null) { + errors += "$prefix must be an object" + return@forEachIndexed + } + val id = obj.text("id", errors, prefix) + val title = obj.text("title", errors, prefix) + val edition = obj.text("edition", errors, prefix) + val license = obj.text("license", errors, prefix) + val url = obj.text("url", errors, prefix) + if (id != null && !sourceIds.add(id)) errors += "$prefix.id must be unique" + if (url != null && !isHttpUrl(url)) errors += "$prefix.url must be an absolute HTTP(S) URL" + if (id != null && title != null && edition != null && license != null && url != null) { + sources += ContentSource(id, title, edition, license, url) + } + } + if (sourceNodes != null && sourceNodes.isEmpty()) { + errors += "sources must contain at least one licensed source" + } + + val hexagramNodes = root.arr("hexagrams", errors) + if (hexagramNodes != null && hexagramNodes.size != 64) { + errors += "hexagrams must contain exactly 64 entries" + } + val hexagrams = mutableMapOf() + val seenPatterns = mutableSetOf() + hexagramNodes?.forEachIndexed { index, node -> + val prefix = "hexagrams[$index]" + val obj = node as? JsonValue.Obj + if (obj == null) { + errors += "$prefix must be an object" + return@forEachIndexed + } + val kingWenNumber = obj.int("kingWenNumber", errors, prefix) + val name = obj.text("name", errors, prefix) + val symbol = obj.text("symbol", errors, prefix) + val judgmentOriginal = obj.text("judgmentOriginal", errors, prefix) + val judgmentPlain = obj.text("judgmentPlain", errors, prefix) + val lineTexts = obj.sixTexts("lineTextsBottomUp", errors, prefix) + val linePlain = obj.sixTexts("linePlainBottomUp", errors, prefix) + val sourceRefs = obj.stringList("sourceRefs", errors, prefix) + val specialUsage = obj.optionalText("specialUsageText", errors, prefix) + val lower = obj.text("lowerTrigram", errors, prefix) + val upper = obj.text("upperTrigram", errors, prefix) + val patternTokens = obj.stringList("patternBottomUp", errors, prefix) + + if (kingWenNumber != null && (kingWenNumber < 1 || kingWenNumber > 64)) { + errors += "$prefix.kingWenNumber must be an integer from 1 through 64" + } + if (kingWenNumber != null && hexagrams.containsKey(kingWenNumber)) { + errors += "$prefix.kingWenNumber must be unique" + } + if (kingWenNumber != null && name != null && name != HexagramNames.nameFor(kingWenNumber)) { + errors += "$prefix.name does not match the King Wen name table" + } + if (kingWenNumber != null && symbol != null && symbol != hexagramSymbol(kingWenNumber)) { + errors += "$prefix.symbol must be the King Wen unicode hexagram" + } + if (sourceRefs != null) { + if (sourceRefs.isEmpty()) errors += "$prefix.sourceRefs must not be empty" + if (sourceRefs.size != sourceRefs.distinct().size) { + errors += "$prefix.sourceRefs must be unique" + } + for (sourceRef in sourceRefs) { + if (sourceRef !in sourceIds) { + errors += "$prefix.sourceRefs contains unknown source '$sourceRef'" + } + } + } + if (patternTokens != null) { + if (patternTokens.size != 6 || patternTokens.any { it != "YIN" && it != "YANG" }) { + errors += "$prefix.patternBottomUp must contain exactly six YIN/YANG values" + } else { + val encoded = patternTokens.joinToString("/") + if (!seenPatterns.add(encoded)) errors += "$prefix.patternBottomUp must be unique" + val polarities = patternTokens.map { token -> + if (token == "YANG") Polarity.YANG else Polarity.YIN + } + val expectedId = HexagramCatalog.idFor(HexagramPattern.of(polarities)).value + if (kingWenNumber != null && kingWenNumber != expectedId) { + errors += "$prefix.kingWenNumber does not match its King Wen trigram pair" + } + val expectedPattern = expectedBottomUp(lower, upper) + if (expectedPattern != null && expectedPattern != patternTokens) { + errors += "$prefix.patternBottomUp does not match lower/upper trigrams in bottom-up order" + } + } + } + + val hasSpecial = specialUsage != null + when (kingWenNumber) { + 1 -> if (qianUsage != null && hasSpecial != qianUsage) { + errors += "$prefix.specialUsageText must match specialUsageTexts.qian" + } + 2 -> if (kunUsage != null && hasSpecial != kunUsage) { + errors += "$prefix.specialUsageText must match specialUsageTexts.kun" + } + else -> if (hasSpecial) { + errors += "$prefix.specialUsageText is only valid for Qian or Kun" + } + } + + if ( + errors.none { it.startsWith(prefix) } && + kingWenNumber != null && + name != null && + symbol != null && + judgmentOriginal != null && + judgmentPlain != null && + lineTexts != null && + linePlain != null && + sourceRefs != null + ) { + hexagrams[kingWenNumber] = HexagramContent( + kingWenNumber = kingWenNumber, + name = name, + symbol = symbol, + judgmentOriginal = judgmentOriginal, + judgmentPlain = judgmentPlain, + lineTextsBottomUp = lineTexts, + linePlainBottomUp = linePlain, + specialUsageText = specialUsage, + sourceRefs = sourceRefs, + ) + } + } + + if (hexagrams.size != 64 && errors.none { it.contains("exactly 64") }) { + errors += "King Wen numbers 1 through 64 must each occur exactly once" + } + if (errors.isNotEmpty()) { + throw ContentIntegrityException(errors.joinToString(separator = "\n")) + } + + return ParsedHexagramContentPackage( + manifest = ContentManifest( + contentVersion = checkNotNull(contentVersion), + digest = jsonDigest(root), + sources = sources, + ), + hexagrams = hexagrams, + ) + } + + private fun hexagramSymbol(kingWenNumber: Int): String = + (0x4DC0 + kingWenNumber - 1).toChar().toString() + + private fun expectedBottomUp(lower: String?, upper: String?): List? { + val lowerPattern = TRIGRAMS[lower] ?: return null + val upperPattern = TRIGRAMS[upper] ?: return null + return lowerPattern + upperPattern + } + + private fun isHttpUrl(value: String): Boolean = + value.startsWith("https://") || value.startsWith("http://") + + private fun JsonValue.Obj.int(key: String, errors: MutableList, prefix: String = ""): Int? { + val path = fieldPath(prefix, key) + return when (val value = fields[key]) { + is JsonValue.Num -> value.value + null -> { + errors += "$path is missing" + null + } + else -> { + errors += "$path must be an integer" + null + } + } + } + + private fun JsonValue.Obj.bool(key: String, errors: MutableList, prefix: String = ""): Boolean? { + val path = fieldPath(prefix, key) + return when (val value = fields[key]) { + is JsonValue.Bool -> value.value + null -> { + errors += "$path is missing" + null + } + else -> { + errors += "$path must be a boolean" + null + } + } + } + + private fun JsonValue.Obj.text(key: String, errors: MutableList, prefix: String = ""): String? { + val path = fieldPath(prefix, key) + val value = optionalText(key, errors, prefix) + if (value == null && fields[key] !is JsonValue.Null) { + if (!fields.containsKey(key)) errors += "$path must be non-blank text" + } else if (value == null) { + errors += "$path must be non-blank text" + } + return value + } + + private fun JsonValue.Obj.optionalText( + key: String, + errors: MutableList, + prefix: String, + ): String? { + val path = fieldPath(prefix, key) + return when (val value = fields[key]) { + JsonValue.Null, null -> null + is JsonValue.Str -> { + when { + value.value.isBlank() -> { + errors += "$path must be non-blank text or null" + null + } + unsafeText.containsMatchIn(value.value) -> { + errors += "$path contains script-like markup or an invisible control character" + null + } + else -> value.value + } + } + else -> { + errors += "$path must be non-blank text or null" + null + } + } + } + + private fun JsonValue.Obj.obj(key: String, errors: MutableList): JsonValue.Obj? { + return when (val value = fields[key]) { + is JsonValue.Obj -> value + else -> { + errors += "$key must be an object" + null + } + } + } + + private fun JsonValue.Obj.arr(key: String, errors: MutableList): List? { + return when (val value = fields[key]) { + is JsonValue.Arr -> value.items + else -> { + errors += "$key must be an array" + null + } + } + } + + private fun JsonValue.Obj.sixTexts( + key: String, + errors: MutableList, + prefix: String, + ): List? { + val values = stringList(key, errors, prefix) ?: return null + if (values.size != 6) { + errors += "${fieldPath(prefix, key)} must contain exactly six bottom-up entries" + return null + } + return values + } + + private fun JsonValue.Obj.stringList( + key: String, + errors: MutableList, + prefix: String, + ): List? { + val path = fieldPath(prefix, key) + val array = fields[key] as? JsonValue.Arr + if (array == null) { + errors += "$path must be an array" + return null + } + val values = mutableListOf() + array.items.forEachIndexed { index, item -> + val itemPath = "$path[$index]" + val text = (item as? JsonValue.Str)?.value + when { + text == null || text.isBlank() -> errors += "$itemPath must be non-blank text" + unsafeText.containsMatchIn(text) -> + errors += "$itemPath contains script-like markup or an invisible control character" + else -> values += text + } + } + return values.takeIf { it.size == array.items.size } + } + + private fun fieldPath(prefix: String, key: String): String = + if (prefix.isEmpty()) key else "$prefix.$key" + + private val TRIGRAMS = mapOf( + "QIAN" to listOf("YANG", "YANG", "YANG"), + "DUI" to listOf("YANG", "YANG", "YIN"), + "LI" to listOf("YANG", "YIN", "YANG"), + "ZHEN" to listOf("YANG", "YIN", "YIN"), + "XUN" to listOf("YIN", "YANG", "YANG"), + "KAN" to listOf("YIN", "YANG", "YIN"), + "GEN" to listOf("YIN", "YIN", "YANG"), + "KUN" to listOf("YIN", "YIN", "YIN"), + ) +} diff --git a/app/src/main/java/net/opcapp/flash/data/content/HexagramContentRepository.kt b/app/src/main/java/net/opcapp/flash/data/content/HexagramContentRepository.kt index 9839921..083b24a 100644 --- a/app/src/main/java/net/opcapp/flash/data/content/HexagramContentRepository.kt +++ b/app/src/main/java/net/opcapp/flash/data/content/HexagramContentRepository.kt @@ -1,9 +1,11 @@ package net.opcapp.flash.data.content +import net.opcapp.flash.core.model.ContentManifest import net.opcapp.flash.core.model.HexagramContent interface HexagramContentRepository { val contentVersion: String + val manifest: ContentManifest fun contentFor( kingWenNumber: Int, diff --git a/app/src/main/java/net/opcapp/flash/data/content/JsonSupport.kt b/app/src/main/java/net/opcapp/flash/data/content/JsonSupport.kt new file mode 100644 index 0000000..3705097 --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/data/content/JsonSupport.kt @@ -0,0 +1,202 @@ +package net.opcapp.flash.data.content + +import java.security.MessageDigest + +internal sealed interface JsonValue { + data class Obj(val fields: Map) : JsonValue + data class Arr(val items: List) : JsonValue + data class Str(val value: String) : JsonValue + data class Num(val value: Int) : JsonValue + data class Bool(val value: Boolean) : JsonValue + data object Null : JsonValue +} + +internal class JsonReader(private val text: String) { + private var index = 0 + + fun readValue(): JsonValue { + skipWhitespace() + val value = parseValue() + skipWhitespace() + if (index != text.length) { + error("Unexpected trailing content at index $index") + } + return value + } + + private fun parseValue(): JsonValue { + skipWhitespace() + return when (val char = peek()) { + '{' -> parseObject() + '[' -> parseArray() + '"' -> JsonValue.Str(parseString()) + 't' -> parseLiteral("true", JsonValue.Bool(true)) + 'f' -> parseLiteral("false", JsonValue.Bool(false)) + 'n' -> parseLiteral("null", JsonValue.Null) + '-', in '0'..'9' -> parseNumber() + else -> error("Unexpected character '$char' at index $index") + } + } + + private fun parseObject(): JsonValue.Obj { + expect('{') + skipWhitespace() + val fields = linkedMapOf() + if (peek() == '}') { + index += 1 + return JsonValue.Obj(fields) + } + while (true) { + skipWhitespace() + val key = parseString() + skipWhitespace() + expect(':') + skipWhitespace() + if (fields.containsKey(key)) error("Duplicate JSON key '$key'") + fields[key] = parseValue() + skipWhitespace() + when (peek()) { + ',' -> index += 1 + '}' -> { + index += 1 + return JsonValue.Obj(fields) + } + else -> error("Expected comma or object end at index $index") + } + } + } + + private fun parseArray(): JsonValue.Arr { + expect('[') + skipWhitespace() + val items = mutableListOf() + if (peek() == ']') { + index += 1 + return JsonValue.Arr(items) + } + while (true) { + items += parseValue() + skipWhitespace() + when (peek()) { + ',' -> index += 1 + ']' -> { + index += 1 + return JsonValue.Arr(items) + } + else -> error("Expected comma or array end at index $index") + } + } + } + + private fun parseString(): String { + expect('"') + val builder = StringBuilder() + while (true) { + val char = next() + when (char) { + '"' -> return builder.toString() + '\\' -> builder.append(parseEscape()) + in '\u0000'..'\u001F' -> error("Unescaped control character in string") + else -> builder.append(char) + } + } + } + + private fun parseEscape(): Char { + return when (val char = next()) { + '"', '\\', '/' -> char + 'b' -> '\b' + 'f' -> '\u000C' + 'n' -> '\n' + 'r' -> '\r' + 't' -> '\t' + 'u' -> { + val hex = CharArray(4) { next() }.concatToString() + hex.toIntOrNull(16)?.toChar() ?: error("Invalid unicode escape \\u$hex") + } + else -> error("Invalid string escape \\$char") + } + } + + private fun parseNumber(): JsonValue.Num { + val start = index + if (peek() == '-') index += 1 + if (peek() == '0') { + index += 1 + } else { + if (peek() !in '1'..'9') error("Invalid number at index $start") + while (peek() in '0'..'9') index += 1 + } + if (peek() == '.' || peek() == 'e' || peek() == 'E') { + error("Content JSON numbers must be integers") + } + return JsonValue.Num(text.substring(start, index).toInt()) + } + + private fun parseLiteral(literal: String, value: JsonValue): JsonValue { + if (!text.startsWith(literal, index)) error("Expected '$literal' at index $index") + index += literal.length + return value + } + + private fun skipWhitespace() { + while (index < text.length && text[index] in WHITESPACE) index += 1 + } + + private fun peek(): Char { + if (index >= text.length) error("Unexpected end of JSON") + return text[index] + } + + private fun next(): Char { + val char = peek() + index += 1 + return char + } + + private fun expect(char: Char) { + if (next() != char) error("Expected '$char' at index ${index - 1}") + } + + companion object { + private val WHITESPACE = charArrayOf(' ', '\n', '\r', '\t') + } +} + +internal fun jsonCanonicalize(value: JsonValue): String = when (value) { + JsonValue.Null -> "null" + is JsonValue.Bool -> value.value.toString() + is JsonValue.Num -> value.value.toString() + is JsonValue.Str -> jsonQuote(value.value) + is JsonValue.Arr -> value.items.joinToString(",", "[", "]") { jsonCanonicalize(it) } + is JsonValue.Obj -> value.fields.keys.sorted().joinToString(",", "{", "}") { key -> + "${jsonQuote(key)}:${jsonCanonicalize(value.fields.getValue(key))}" + } +} + +internal fun jsonDigest(value: JsonValue): String { + val digest = MessageDigest.getInstance("SHA-256") + .digest(jsonCanonicalize(value).toByteArray(Charsets.UTF_8)) + return digest.joinToString("") { byte -> "%02x".format(byte.toInt() and 0xFF) } +} + +private fun jsonQuote(value: String): String { + val builder = StringBuilder("\"") + for (char in value) { + when (char) { + '"' -> builder.append("\\\"") + '\\' -> builder.append("\\\\") + '\b' -> builder.append("\\b") + '\u000C' -> builder.append("\\f") + '\n' -> builder.append("\\n") + '\r' -> builder.append("\\r") + '\t' -> builder.append("\\t") + else -> if (char.code < 0x20) { + builder.append("\\u%04x".format(char.code)) + } else { + builder.append(char) + } + } + } + return builder.append('"').toString() +} diff --git a/app/src/main/java/net/opcapp/flash/data/di/ContentModule.kt b/app/src/main/java/net/opcapp/flash/data/di/ContentModule.kt new file mode 100644 index 0000000..de59ee7 --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/data/di/ContentModule.kt @@ -0,0 +1,19 @@ +package net.opcapp.flash.data.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton +import net.opcapp.flash.data.content.AssetsHexagramContentRepository +import net.opcapp.flash.data.content.HexagramContentRepository + +@Module +@InstallIn(SingletonComponent::class) +abstract class ContentBindingsModule { + @Binds + @Singleton + abstract fun bindHexagramContentRepository( + implementation: AssetsHexagramContentRepository, + ): HexagramContentRepository +} diff --git a/app/src/main/java/net/opcapp/flash/feature/casting/CastingViewModel.kt b/app/src/main/java/net/opcapp/flash/feature/casting/CastingViewModel.kt index 499ad07..84f7db5 100644 --- a/app/src/main/java/net/opcapp/flash/feature/casting/CastingViewModel.kt +++ b/app/src/main/java/net/opcapp/flash/feature/casting/CastingViewModel.kt @@ -14,6 +14,9 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import net.opcapp.flash.core.model.HexagramContent +import net.opcapp.flash.data.content.ContentIntegrityException +import net.opcapp.flash.data.content.HexagramContentRepository import net.opcapp.flash.data.history.HistoryRepository import net.opcapp.flash.data.history.SavedCastingSession import net.opcapp.flash.data.settings.HistorySettingsRepository @@ -22,6 +25,7 @@ import net.opcapp.flash.domain.casting.CastMetadata import net.opcapp.flash.domain.casting.CastResult import net.opcapp.flash.domain.casting.CastRound import net.opcapp.flash.domain.casting.CoinSide +import net.opcapp.flash.domain.casting.LineValue sealed interface HistorySaveStatus { data object Draft : HistorySaveStatus @@ -52,6 +56,10 @@ data class CastingUiState( val result: CastResult? = null, val sessionId: String? = null, val saveStatus: HistorySaveStatus = HistorySaveStatus.Draft, + val primaryContent: HexagramContent? = null, + val transformedContent: HexagramContent? = null, + val contentError: String? = null, + val showSpecialUsage: Boolean = false, ) { val currentRoundNumber: Int get() = (confirmedRounds.size + 1).coerceAtMost(6) @@ -67,12 +75,14 @@ class CastingViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val historyRepository: HistoryRepository, private val settingsRepository: HistorySettingsRepository, + private val contentRepository: HexagramContentRepository, ) : ViewModel() { private val restoredRounds = decodeRounds(savedStateHandle[Keys.Rounds]) private val restoredCreatedAt = savedStateHandle.get(Keys.CreatedAt) private val restoredResult = restoredCreatedAt ?.takeIf { restoredRounds.size == 6 } ?.let { createdAt -> createResult(restoredRounds, createdAt) } + private val restoredContent = resolveContent(restoredResult) private val _uiState = MutableStateFlow( CastingUiState( @@ -86,6 +96,10 @@ class CastingViewModel @Inject constructor( } else { HistorySaveStatus.Saving }, + primaryContent = restoredContent.primary, + transformedContent = restoredContent.transformed, + contentError = restoredContent.error, + showSpecialUsage = restoredContent.showSpecialUsage, ), ) val uiState: StateFlow = _uiState.asStateFlow() @@ -138,6 +152,7 @@ class CastingViewModel @Inject constructor( val createdAt = Instant.now().toString() val sessionId = UUID.randomUUID().toString() val result = createResult(updatedRounds, createdAt) + val content = resolveContent(result) savedStateHandle[Keys.CreatedAt] = createdAt savedStateHandle[Keys.SessionId] = sessionId _uiState.value = state.copy( @@ -146,6 +161,10 @@ class CastingViewModel @Inject constructor( result = result, sessionId = sessionId, saveStatus = HistorySaveStatus.Saving, + primaryContent = content.primary, + transformedContent = content.transformed, + contentError = content.error, + showSpecialUsage = content.showSpecialUsage, ) persistResult(autoOnly = true) return true @@ -288,11 +307,51 @@ class CastingViewModel @Inject constructor( CastResult.record( computation = CastEngine.cast(rounds), metadata = CastMetadata( - contentVersion = CONTENT_VERSION, + contentVersion = contentRepository.contentVersion, createdAt = createdAt, ), ) + private fun resolveContent(result: CastResult?): ResolvedContent { + if (result == null) return ResolvedContent() + val showSpecialUsage = when (result.primaryHexagramId.value) { + 1 -> result.lineValuesBottomUp.all { it == LineValue.OLD_YANG } + 2 -> result.lineValuesBottomUp.all { it == LineValue.OLD_YIN } + else -> false + } + return try { + val primary = contentRepository.contentFor( + result.primaryHexagramId.value, + result.contentVersion, + ) + val transformed = if (result.transformedHexagramId == result.primaryHexagramId) { + primary + } else { + contentRepository.contentFor( + result.transformedHexagramId.value, + result.contentVersion, + ) + } + ResolvedContent( + primary = primary, + transformed = transformed, + showSpecialUsage = showSpecialUsage, + ) + } catch (error: ContentIntegrityException) { + ResolvedContent( + error = error.message, + showSpecialUsage = showSpecialUsage, + ) + } + } + + private data class ResolvedContent( + val primary: HexagramContent? = null, + val transformed: HexagramContent? = null, + val error: String? = null, + val showSpecialUsage: Boolean = false, + ) + private fun decodeRounds(scores: ArrayList?): List = scores.orEmpty().chunked(CastRound.COINS_PER_ROUND).map(CastRound::fromScores) @@ -311,7 +370,4 @@ class CastingViewModel @Inject constructor( const val SessionId = "casting_session_id" } - companion object { - const val CONTENT_VERSION = "hexagram-names-v1" - } } diff --git a/app/src/main/java/net/opcapp/flash/feature/content/ContentSourcesScreen.kt b/app/src/main/java/net/opcapp/flash/feature/content/ContentSourcesScreen.kt new file mode 100644 index 0000000..5f1c1ba --- /dev/null +++ b/app/src/main/java/net/opcapp/flash/feature/content/ContentSourcesScreen.kt @@ -0,0 +1,121 @@ +package net.opcapp.flash.feature.content + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import net.opcapp.flash.R +import net.opcapp.flash.core.model.ContentManifest + +@Composable +fun ContentSourcesScreen( + manifest: ContentManifest, + onBack: () -> Unit, + modifier: Modifier = Modifier, +) { + BackHandler(onBack = onBack) + Surface( + modifier = modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background, + ) { + Box(contentAlignment = Alignment.TopCenter) { + Column( + modifier = Modifier + .widthIn(max = 600.dp) + .fillMaxWidth() + .windowInsetsPadding(WindowInsets.safeDrawing) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + TextButton( + onClick = onBack, + modifier = Modifier.height(48.dp), + ) { + Text(stringResource(R.string.back)) + } + Text( + text = stringResource(R.string.content_sources_title), + style = MaterialTheme.typography.headlineMedium, + ) + Text( + text = stringResource(R.string.content_sources_lede), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Text( + text = stringResource(R.string.content_version_label, manifest.contentVersion), + style = MaterialTheme.typography.titleLarge, + ) + Text( + text = stringResource(R.string.content_digest_label, manifest.digest), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + if (manifest.loadError != null) { + Text( + text = stringResource(R.string.content_integrity_error), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.error, + ) + } + manifest.sources.forEach { source -> + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface, + ), + shape = RoundedCornerShape(20.dp), + ) { + Column( + modifier = Modifier.padding(20.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text(text = source.title, style = MaterialTheme.typography.titleLarge) + Text( + text = stringResource(R.string.content_source_edition, source.edition), + style = MaterialTheme.typography.bodyMedium, + ) + Text( + text = stringResource(R.string.content_source_license, source.license), + style = MaterialTheme.typography.bodyMedium, + ) + Text( + text = stringResource(R.string.content_source_url, source.url), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } + Text( + text = stringResource(R.string.content_review_pending), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } +} diff --git a/app/src/main/java/net/opcapp/flash/feature/home/HomeScreen.kt b/app/src/main/java/net/opcapp/flash/feature/home/HomeScreen.kt index 6439481..e94abc5 100644 --- a/app/src/main/java/net/opcapp/flash/feature/home/HomeScreen.kt +++ b/app/src/main/java/net/opcapp/flash/feature/home/HomeScreen.kt @@ -40,6 +40,7 @@ fun HomeScreen( onStartCasting: () -> Unit, onOpenSettings: () -> Unit, onOpenMethodIntro: () -> Unit, + onOpenContentSources: () -> Unit, modifier: Modifier = Modifier, ) { Surface( @@ -134,6 +135,12 @@ fun HomeScreen( ) { Text(stringResource(R.string.open_method_intro)) } + TextButton( + onClick = onOpenContentSources, + modifier = Modifier.height(48.dp), + ) { + Text(stringResource(R.string.open_content_sources)) + } } } Spacer(Modifier.height(16.dp)) diff --git a/app/src/main/java/net/opcapp/flash/feature/home/HomeViewModel.kt b/app/src/main/java/net/opcapp/flash/feature/home/HomeViewModel.kt index 1089783..e8532c7 100644 --- a/app/src/main/java/net/opcapp/flash/feature/home/HomeViewModel.kt +++ b/app/src/main/java/net/opcapp/flash/feature/home/HomeViewModel.kt @@ -9,6 +9,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.opcapp.flash.core.model.ContentManifest +import net.opcapp.flash.data.content.HexagramContentRepository import net.opcapp.flash.data.history.HistoryRepository import net.opcapp.flash.data.history.SavedSessionSummary import net.opcapp.flash.data.settings.HistorySavePolicy @@ -20,13 +22,20 @@ data class HomeUiState( val savePolicy: HistorySavePolicy = HistorySavePolicy(), val hasSeenMethodIntro: Boolean = false, val isReady: Boolean = false, + val contentManifest: ContentManifest = ContentManifest( + contentVersion = "unavailable", + digest = "unavailable", + sources = emptyList(), + ), ) @HiltViewModel class HomeViewModel @Inject constructor( historyRepository: HistoryRepository, private val settingsRepository: HistorySettingsRepository, + contentRepository: HexagramContentRepository, ) : ViewModel() { + private val contentManifest = contentRepository.manifest val uiState: StateFlow = combine( historyRepository.observeCount(), historyRepository.observeLatest(), @@ -39,6 +48,7 @@ class HomeViewModel @Inject constructor( savePolicy = savePolicy, hasSeenMethodIntro = hasSeenMethodIntro, isReady = true, + contentManifest = contentManifest, ) }.stateIn( scope = viewModelScope, diff --git a/app/src/main/java/net/opcapp/flash/feature/result/CastResultScreen.kt b/app/src/main/java/net/opcapp/flash/feature/result/CastResultScreen.kt index 68a6c0c..1023479 100644 --- a/app/src/main/java/net/opcapp/flash/feature/result/CastResultScreen.kt +++ b/app/src/main/java/net/opcapp/flash/feature/result/CastResultScreen.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import net.opcapp.flash.R +import net.opcapp.flash.core.model.HexagramContent import net.opcapp.flash.core.model.HexagramNames import net.opcapp.flash.domain.casting.CastResult import net.opcapp.flash.domain.casting.LineValue @@ -94,6 +95,10 @@ fun CastResultScreen( ResultContent( result = result, saveStatus = uiState.saveStatus, + primaryContent = uiState.primaryContent, + transformedContent = uiState.transformedContent, + contentError = uiState.contentError, + showSpecialUsage = uiState.showSpecialUsage, onSave = onSave, onDelete = onDelete, onRetry = onRetry, @@ -110,6 +115,10 @@ fun CastResultScreen( private fun ResultContent( result: CastResult, saveStatus: HistorySaveStatus, + primaryContent: HexagramContent?, + transformedContent: HexagramContent?, + contentError: String?, + showSpecialUsage: Boolean, onSave: () -> Unit, onDelete: () -> Unit, onRetry: () -> Unit, @@ -175,6 +184,13 @@ private fun ResultContent( } } RawLinesCard(result.lineValuesBottomUp) + HexagramTextsCard( + result = result, + primaryContent = primaryContent, + transformedContent = transformedContent, + contentError = contentError, + showSpecialUsage = showSpecialUsage, + ) SaveStatusCard( status = saveStatus, onSave = onSave, @@ -182,7 +198,7 @@ private fun ResultContent( onRetry = onRetry, ) Text( - text = stringResource(R.string.content_package_pending), + text = stringResource(R.string.content_plain_draft_notice), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -197,6 +213,104 @@ private fun ResultContent( } } +@Composable +private fun HexagramTextsCard( + result: CastResult, + primaryContent: HexagramContent?, + transformedContent: HexagramContent?, + contentError: String?, + showSpecialUsage: Boolean, +) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + shape = RoundedCornerShape(20.dp), + ) { + Column( + modifier = Modifier.padding(20.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + if (contentError != null || primaryContent == null) { + Text( + text = stringResource(R.string.content_integrity_error), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.error, + ) + return@Column + } + LabeledPassage( + title = stringResource(R.string.primary_judgment_title), + original = primaryContent.judgmentOriginal, + plain = primaryContent.judgmentPlain, + ) + if (result.movingLinePositions.isNotEmpty()) { + Text( + text = stringResource(R.string.moving_line_texts_title), + style = MaterialTheme.typography.titleLarge, + ) + result.movingLinePositions.forEach { position -> + LabeledPassage( + title = linePositionName(position), + original = primaryContent.lineTextsBottomUp[position - 1], + plain = primaryContent.linePlainBottomUp[position - 1], + ) + } + } + if ( + transformedContent != null && + result.transformedHexagramId != result.primaryHexagramId + ) { + LabeledPassage( + title = stringResource(R.string.transformed_judgment_title), + original = transformedContent.judgmentOriginal, + plain = transformedContent.judgmentPlain, + ) + } + if (showSpecialUsage && primaryContent.specialUsageText != null) { + LabeledPassage( + title = stringResource(R.string.special_usage_title), + original = primaryContent.specialUsageText, + plain = null, + ) + } + } + } +} + +@Composable +private fun LabeledPassage( + title: String, + original: String, + plain: String?, +) { + Column(verticalArrangement = Arrangement.spacedBy(6.dp)) { + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + ) + Text( + text = stringResource(R.string.content_original_label), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + ) + Text( + text = original, + style = MaterialTheme.typography.bodyLarge, + ) + if (plain != null) { + Text( + text = stringResource(R.string.content_plain_label), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + ) + Text( + text = plain, + style = MaterialTheme.typography.bodyLarge, + ) + } + } +} + @Composable private fun RawLinesCard(lines: List) { Card( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ba9712..90c440e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -103,7 +103,23 @@ 保存本次 本次不保存 重试 - 当前显示可复核的卦号、卦名和六爻事实。经典原文与现代白话将在来源和授权审核完成后接入。 + 原文 + 本地白话 + 白话为项目自撰草稿,供本机阅读;内容负责人审校前不视为可再分发。 + 本卦卦辞 + 之卦卦辞 + 动爻爻辞 + 用九 / 用六 + 本地内容包未能通过完整性检查,卦辞暂不可读。卦号、卦名和六爻事实仍可复核。 + 内容来源 + 内容来源 + 应用只使用已写入安装包的本地文本。原文来自可核验公版《易经》;白话由本项目撰写,审校完成前标为草稿。 + 内容版本:%1$s + 校验摘要:%1$s + 许可:%1$s + 版本:%1$s + 来源:%1$s + 内容负责人尚未确认本包可再分发;发布前须完成审校。 再起一卦 结果状态已丢失,请返回首页重新开始。 删除本次本机记录? diff --git a/app/src/test/java/net/opcapp/flash/data/content/FakeHexagramContentRepository.kt b/app/src/test/java/net/opcapp/flash/data/content/FakeHexagramContentRepository.kt index 05b54aa..d2b13c9 100644 --- a/app/src/test/java/net/opcapp/flash/data/content/FakeHexagramContentRepository.kt +++ b/app/src/test/java/net/opcapp/flash/data/content/FakeHexagramContentRepository.kt @@ -1,13 +1,23 @@ package net.opcapp.flash.data.content +import net.opcapp.flash.core.model.ContentManifest +import net.opcapp.flash.core.model.ContentSource import net.opcapp.flash.core.model.HexagramContent class FakeHexagramContentRepository( override val contentVersion: String = "fixture-only-v1", entries: List, + sources: List = emptyList(), + digest: String = "fixture-digest", ) : HexagramContentRepository { private val entriesById: Map + override val manifest: ContentManifest = ContentManifest( + contentVersion = contentVersion, + digest = digest, + sources = sources, + ) + init { require(contentVersion.isNotBlank()) { "Content version must not be blank" } require(entries.map(HexagramContent::kingWenNumber).distinct().size == entries.size) { diff --git a/app/src/test/java/net/opcapp/flash/data/content/HexagramContentParserTest.kt b/app/src/test/java/net/opcapp/flash/data/content/HexagramContentParserTest.kt new file mode 100644 index 0000000..ee2fd5a --- /dev/null +++ b/app/src/test/java/net/opcapp/flash/data/content/HexagramContentParserTest.kt @@ -0,0 +1,39 @@ +package net.opcapp.flash.data.content + +import net.opcapp.flash.core.model.HexagramNames +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Test + +class HexagramContentParserTest { + @Test + fun publishedPackageMatchesKingWenNamesAndSpecialUsage() { + val json = checkNotNull(javaClass.getResource("/hexagram-content.json")).readText() + val pack = HexagramContentParser.parse(json) + + assertEquals("zh-Hans-2026.1", pack.manifest.contentVersion) + assertEquals(64, pack.hexagrams.size) + assertTrue(pack.manifest.digest.matches(Regex("[a-f0-9]{64}"))) + assertEquals("复", pack.hexagrams.getValue(24).name) + assertEquals(HexagramNames.nameFor(24), pack.hexagrams.getValue(24).name) + assertEquals("䷗", pack.hexagrams.getValue(24).symbol) + assertTrue(pack.hexagrams.getValue(1).specialUsageText.orEmpty().contains("用九")) + assertTrue(pack.hexagrams.getValue(2).specialUsageText.orEmpty().contains("用六")) + assertNotNull(pack.manifest.sources.singleOrNull { it.id.contains("wikisource") }) + assertNotNull(pack.manifest.sources.singleOrNull { it.id.contains("lingji-plain") }) + } + + @Test + fun parserRejectsWrongKingWenName() { + val json = checkNotNull(javaClass.getResource("/hexagram-content.json")).readText() + .replace("\"name\": \"复\"", "\"name\": \"錯\"") + try { + HexagramContentParser.parse(json) + fail("Expected content integrity failure") + } catch (error: ContentIntegrityException) { + assertTrue(error.message.orEmpty().contains("name")) + } + } +} diff --git a/content/packages/hexagram-content.json b/content/packages/hexagram-content.json new file mode 100644 index 0000000..5385b87 --- /dev/null +++ b/content/packages/hexagram-content.json @@ -0,0 +1,2458 @@ +{ + "schemaVersion": 1, + "contentVersion": "zh-Hans-2026.1", + "specialUsageTexts": { + "qian": true, + "kun": true + }, + "sources": [ + { + "id": "wikisource-zhouyi-jing-zh-Hans", + "title": "维基文库《周易》易经", + "edition": "仅卦辞、爻辞与乾用九、坤用六,不含十翼;由 zh.wikisource.org 导入并经 Wikimedia zh-hans 转换", + "license": "公版(Wikimedia PD-old)", + "url": "https://zh.wikisource.org/wiki/周易" + }, + { + "id": "lingji-plain-zh-Hans-2026.1", + "title": "灵机本地白话", + "edition": "2026.1 项目自撰草稿,待内容负责人审校后视为可再分发", + "license": "项目自撰;审校完成前仅用于本机构建,不以现代译注冒充公版", + "url": "https://creativecommons.org/licenses/by/4.0/deed.zh-Hans" + } + ], + "hexagrams": [ + { + "kingWenNumber": 1, + "upperTrigram": "QIAN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "name": "乾", + "symbol": "䷀", + "judgmentOriginal": "元亨。利贞。", + "judgmentPlain": "开始即通达,利于守持正道。", + "lineTextsBottomUp": [ + "初九:潜龙勿用。", + "九二:见龙在田,利见大人。", + "九三:君子终日乾乾,夕惕若;厉,无咎。", + "九四:或跃在渊,无咎。", + "九五:飞龙在天,利见大人。", + "上九:亢龙,有悔。" + ], + "linePlainBottomUp": [ + "龙还潜藏着,先不要施展。", + "龙出现在田野,利于去见有识之人。", + "君子整日健进,夜里仍警惕;虽有危难,可以无灾。", + "或跳进深渊,可以无灾。", + "龙飞在天上,利于去见有识之人。", + "龙飞得过高,会有悔恨。" + ], + "specialUsageText": "用九:见群龙无首,吉。", + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 2, + "upperTrigram": "KUN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "name": "坤", + "symbol": "䷁", + "judgmentOriginal": "元亨。利牝马之贞。君子有攸往,先迷后得主。利西南得朋,东北丧朋。安贞,吉。", + "judgmentPlain": "开始即通达,利于像母马那样守持正道。君子有所前往,先会迷路,随后才得到依靠。利于西南得到同类,东北失去同类。安于守正,吉。", + "lineTextsBottomUp": [ + "初六:履霜,坚冰至。", + "六二:直方大,不习无不利。", + "六三:含章,可贞。或从王事,无成有终。", + "六四:括囊,无咎无誉。", + "六五:黄裳,元吉。", + "上六:龙战于野,其血玄黄。" + ], + "linePlainBottomUp": [ + "踩到霜,坚冰就要来了。", + "正直方正而广大,不必演习,没有不利。", + "蕴含文采,可以守正。或跟从王事,不求自己成功,却能有结果。", + "扎紧口袋,无灾也无称誉。", + "黄色下裳,大为吉祥。", + "龙在郊野争斗,血流成青黄色。" + ], + "specialUsageText": "用六:利永贞。", + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 3, + "upperTrigram": "KAN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "name": "屯", + "symbol": "䷂", + "judgmentOriginal": "元亨,利贞。勿用有攸往,利建侯。", + "judgmentPlain": "开始即通达,利于守正。不要急着前往,利于立诸侯。", + "lineTextsBottomUp": [ + "初九:磐桓,利居贞,利建侯。", + "六二:屯如邅如,乘马班如,匪寇婚媾,女子贞不字,十年乃字。", + "六三:即鹿无虞,惟入于林中,君子几不如舍,往吝。", + "六四:乘马班如,求婚媾,往,吉无不利。", + "九五:屯其膏;小贞吉,大贞凶。", + "上六:乘马班如,泣血涟如。" + ], + "linePlainBottomUp": [ + "徘徊不进,利于安居守正,利于立诸侯。", + "困顿难行,乘马盘旋。不是强盗,是来求婚。女子守正不嫁,十年才许嫁。", + "追鹿却没有虞人向导,只是陷入林中。君子察觉危险,不如放弃;再往前会有憾恨。", + "乘马盘旋,去求婚,前往吉,没有不利。", + "屯积膏泽。小事守正吉,大事守正凶。", + "乘马盘旋,血泪涟涟。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 4, + "upperTrigram": "GEN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "name": "蒙", + "symbol": "䷃", + "judgmentOriginal": "亨。匪我求童蒙,童蒙求我。初筮告,再三渎,渎则不告。利贞。", + "judgmentPlain": "亨通。我不是要去求童蒙,是童蒙来求我。初次卜问则告知;再三乱问,就不告知。利于守正。", + "lineTextsBottomUp": [ + "初六:发蒙,利用刑人,用说桎梏,以往吝。", + "九二:包蒙吉,纳妇吉,子克家。", + "六三:勿用取女,见金夫,不有躬,无攸利。", + "六四:困蒙,吝。", + "六五:童蒙,吉。", + "上九:击蒙,不利为寇,利御寇。" + ], + "linePlainBottomUp": [ + "启发蒙昧,利于用刑罚纠正人,用桎梏约束;若一再用刑,就有憾恨。", + "包容蒙昧,吉。接纳妇人,吉。孩子能自立,家庭就不再受困。", + "不要娶这个女子,她见了财礼就失了自身。无利可图。", + "困于蒙昧,憾恨。", + "童蒙,吉。", + "打击蒙昧。不利于做强盗,利于抵御强盗。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 5, + "upperTrigram": "KAN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "name": "需", + "symbol": "䷄", + "judgmentOriginal": "有孚,光亨。贞吉,利涉大川。", + "judgmentPlain": "有所等待,有诚信。光辉亨通,守正吉。利于涉大河。", + "lineTextsBottomUp": [ + "初九:需于郊,利用恒,无咎。", + "九二:需于沙,小有言,终吉。", + "九三:需于泥,致寇至。", + "六四:需于血,出自穴。", + "九五:需于酒食,贞吉。", + "上六:入于穴,有不速之客三人来,敬之终吉。" + ], + "linePlainBottomUp": [ + "在郊野等待,利于用恒常的方法,无灾。", + "在沙滩等待,小有议论,最终吉。", + "在泥中等待,招来贼寇。", + "在血中等待,从洞穴里出来。", + "在酒食中等待,守正吉。", + "进入洞穴,有不请自来的三位客人;尊敬他们,最终吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 6, + "upperTrigram": "QIAN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "name": "讼", + "symbol": "䷅", + "judgmentOriginal": "有孚,窒,惕,中吉,终凶。利见大人,不利涉大川。", + "judgmentPlain": "有诚信,在窒塞中警惕,中正则吉,最终凶。利于见大人,不利于涉大河。", + "lineTextsBottomUp": [ + "初六:不永所事,小有言,终吉。", + "九二:不克讼,归而逋,其邑人三百户无眚。", + "六三:食旧德,贞厉,终吉。或从王事,无成。", + "九四:不克讼,复即命渝,安贞吉。", + "九五:讼,元吉。", + "上九:或锡之鞶带,终朝三褫之。" + ], + "linePlainBottomUp": [ + "不永久纠缠事务,小有议论,最终吉。", + "败于讼事,回家逃避。邑人三百户,无灾。", + "食用旧德,守正有危,最终吉。或跟从王事,没有成功。", + "不能胜诉,仍复归于常理,改变态度,安静守正则吉。", + "讼事,元吉。", + "或赐给大带,一天之内被剥夺三次。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 7, + "upperTrigram": "KUN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "name": "师", + "symbol": "䷆", + "judgmentOriginal": "贞丈人吉,无咎。", + "judgmentPlain": "贞正。大人吉,无灾。兵众,正而不邪才可用。", + "lineTextsBottomUp": [ + "初六:师出以律,否臧,凶。", + "九二:在师中吉,无咎;王三锡命。", + "六三:师或舆尸,凶。", + "六四:师左次,无咎。", + "六五:田有禽,利执言,无咎。长子帅师,弟子舆尸,贞凶。", + "上六:大君有命,开国承家,小人勿用。" + ], + "linePlainBottomUp": [ + "出兵要有纪律;否则,凶。", + "在队伍中,无灾,王三次赐命。", + "师或载尸而还,凶。", + "师左次而退,无灾。", + "田里有禽,利于执言,无灾。长子帅师,弟子载尸,贞凶。", + "大君有命,开国承家。小人不可重用。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 8, + "upperTrigram": "KAN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "name": "比", + "symbol": "䷇", + "judgmentOriginal": "吉。原筮元永贞,无咎。不宁方来,后夫凶。", + "judgmentPlain": "吉。原筮,元永贞,无灾。不安宁的人前来,后夫凶。", + "lineTextsBottomUp": [ + "初六:有孚,比之,无咎。有孚盈缶,终来有它,吉。", + "六二:比之自内,贞吉。", + "六三:比之匪人。", + "六四:外比之,贞吉。", + "九五:显比。王用三驱,失前禽,邑人不诫,吉。", + "上六:比之无首,凶。" + ], + "linePlainBottomUp": [ + "有诚信,比之无灾。有诚信充满瓦缶,终来有别的吉。", + "比之从内,贞吉。", + "比之匪人。", + "在外相比,贞吉。", + "显比。王用三驱,失前禽。邑人不诫,吉。", + "比之无首,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 9, + "upperTrigram": "XUN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "name": "小畜", + "symbol": "䷈", + "judgmentOriginal": "亨。密云不雨,自我西郊。", + "judgmentPlain": "亨通。密云不雨,自我西郊。", + "lineTextsBottomUp": [ + "初九:复自道,何其咎,吉。", + "九二:牵复,吉。", + "九三:舆说辐,夫妻反目。", + "六四:有孚,血去惕出,无咎。", + "九五:有孚挛如,富以其邻。", + "上九:既雨既处,尚德载,妇贞厉,月几望,君子征凶。" + ], + "linePlainBottomUp": [ + "复归于自己的道路,何其咎?吉。", + "牵复,吉。", + "舆说辐。夫妻反目。", + "有孚,血去惕出,无灾。", + "有孚挛如,富以其邻。", + "既雨既处,尚德载。妇贞厉。月几望,君子征凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 10, + "upperTrigram": "QIAN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "name": "履", + "symbol": "䷉", + "judgmentOriginal": "履虎尾,不咥人,亨。", + "judgmentPlain": "踩踏老虎尾巴,不咬人,亨通。", + "lineTextsBottomUp": [ + "初九:素履,往无咎。", + "九二:履道坦坦,幽人贞吉。", + "六三:眇能视,跛能履,履虎尾,咥人,凶。武人为于大君。", + "九四:履虎尾,愬愬终吉。", + "九五:夬履,贞厉。", + "上九:视履考祥,其旋元吉。" + ], + "linePlainBottomUp": [ + "素履往,无灾。", + "履道坦坦,幽人贞吉。", + "眇能视,跛能履,履虎尾,咥人,凶。武人为于大君。", + "履虎尾,愬愬,终吉。", + "夬履,贞厉。", + "视履考祥,其旋元吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 11, + "upperTrigram": "KUN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "name": "泰", + "symbol": "䷊", + "judgmentOriginal": "小往大来,吉亨。", + "judgmentPlain": "小往大来,吉,亨通。", + "lineTextsBottomUp": [ + "初九:拔茅茹以其汇,征吉。", + "九二:包荒。用冯河,不遐遗;朋亡。得尚于中行。", + "九三:无平不陂,无往不复,艰贞无咎。勿恤其孚,于食有福。", + "六四:翩翩,不富以其邻;不戒以孚。", + "六五:帝乙归妹,以祉,元吉。", + "上六:城复于隍,勿用师,自邑告命,贞吝。" + ], + "linePlainBottomUp": [ + "拔茅连根,以其类,征吉。", + "包荒,用冯河,不遐遗。朋亡,得尚于中行。", + "无平不陂,无往不复。艰贞无灾。勿恤其孚,于食有福。", + "翩翩,不富以其邻,不戒以孚。", + "帝乙归妹,以祉元吉。", + "城复于隍,勿用师。自邑告命,贞吝。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 12, + "upperTrigram": "QIAN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "name": "否", + "symbol": "䷋", + "judgmentOriginal": "否之匪人,不利君子贞,大往小来。", + "judgmentPlain": "否之匪人,不利于君子守正。大的往,小的来。", + "lineTextsBottomUp": [ + "初六:拔茅茹以其汇,贞吉。亨。", + "六二:包承,小人吉,大人否。亨。", + "六三:包羞。", + "九四:有命,无咎,畴离祉。", + "九五:休否,大人吉。其亡其亡,系于苞桑。", + "上九:倾否,先否后喜。" + ], + "linePlainBottomUp": [ + "拔茅连根,以其类,守正吉,亨通。", + "包容奉承。小人吉,大人否塞。亨通。", + "包藏羞辱。", + "有天命,无灾。同类依附而得福。", + "休止否塞,大人吉。心中念着将亡将亡,才能系于苞桑。", + "倾覆否塞。先否塞,后喜悦。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 13, + "upperTrigram": "QIAN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "name": "同人", + "symbol": "䷌", + "judgmentOriginal": "同人于野,亨。利涉大川,利君子贞。", + "judgmentPlain": "同人于野,亨通。利于涉大河,利于君子守正。", + "lineTextsBottomUp": [ + "初九:同人于门,无咎。", + "六二:同人于宗,吝。", + "九三:伏戎于莽,升其高陵,三岁不兴。", + "九四:乘其墉,弗克,攻吉。", + "九五:同人,先号啕而后笑。大师克相遇。", + "上九:同人于郊,无悔。" + ], + "linePlainBottomUp": [ + "同人于门,无灾。", + "同人于宗,吝。", + "伏戎于莽,升其高陵,三年不兴。", + "乘其墉,弗克攻,吉。", + "同人,先号咷而后笑。大师克相遇。", + "同人于郊,无悔。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 14, + "upperTrigram": "LI", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "name": "大有", + "symbol": "䷍", + "judgmentOriginal": "元亨。", + "judgmentPlain": "元亨。", + "lineTextsBottomUp": [ + "初九:无交害,匪咎,艰则无咎。", + "九二:大车以载,有攸往,无咎。", + "九三:公用亨于天子,小人弗克。", + "九四:匪其彭,无咎。", + "六五:厥孚交如,威如;吉。", + "上九:自天佑之,吉无不利。" + ], + "linePlainBottomUp": [ + "无交害,匪咎,艰则无灾。", + "大车以载,有攸往,无灾。", + "公用亨于天子。小人弗克。", + "匪其彭,无灾。", + "厥孚交如,威如,吉。", + "自天佑之,吉无不利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 15, + "upperTrigram": "KUN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "name": "谦", + "symbol": "䷎", + "judgmentOriginal": "亨,君子有终。", + "judgmentPlain": "亨通。君子有终。", + "lineTextsBottomUp": [ + "初六:谦谦君子,用涉大川,吉。", + "六二:鸣谦,贞吉。", + "九三:劳谦君子,有终吉。", + "六四:无不利,㧑谦。", + "六五:不富,以其邻,利用侵伐,无不利。", + "上六:鸣谦,利用行师,征邑国。" + ], + "linePlainBottomUp": [ + "谦谦君子,用涉大川,吉。", + "鸣谦,贞吉。", + "劳谦,君子有终,吉。", + "无不利,撝谦。", + "不富以其邻,利用侵伐,无不利。", + "鸣谦,利用行师,征邑国。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 16, + "upperTrigram": "ZHEN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "name": "豫", + "symbol": "䷏", + "judgmentOriginal": "利建侯行师。", + "judgmentPlain": "利于建侯行师。", + "lineTextsBottomUp": [ + "初六:鸣豫,凶。", + "六二:介于石,不终日,贞吉。", + "六三:盱豫,悔。迟有悔。", + "九四:由豫,大有得。勿疑。朋盍簪。", + "六五:贞疾,恒不死。", + "上六:冥豫,成有渝,无咎。" + ], + "linePlainBottomUp": [ + "鸣豫,凶。", + "介于石,不终日,贞吉。", + "盱豫,悔。迟则有悔。", + "由豫,大有得。勿疑,朋盍簪。", + "贞疾,恒不死。", + "冥豫,成有渝,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 17, + "upperTrigram": "DUI", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "name": "随", + "symbol": "䷐", + "judgmentOriginal": "元亨。利贞。无咎。", + "judgmentPlain": "元亨,利贞,无灾。", + "lineTextsBottomUp": [ + "初九:官有渝,贞吉。出门交有功。", + "六二:系小子,失丈夫。", + "六三:系丈夫,失小子。随,有求得利,居贞。", + "九四:随有获,贞凶。有孚在道,以明,何咎。", + "九五:孚于嘉,吉。", + "上六:拘系之,乃从维之。王用亨于西山。" + ], + "linePlainBottomUp": [ + "官有渝,贞吉。出门交有功。", + "系小子,失丈夫。", + "系丈夫,失小子。随有求得,利居贞。", + "随有获,贞凶。有孚在道,以明,何咎。", + "孚于嘉,吉。", + "拘系之,乃从维之。王用亨于西山。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 18, + "upperTrigram": "GEN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "name": "蛊", + "symbol": "䷑", + "judgmentOriginal": "元亨。利涉大川。先甲三日,后甲三日。", + "judgmentPlain": "元亨,利涉大川。先甲三日,后甲三日。", + "lineTextsBottomUp": [ + "初六:干父之蛊,有子考,无咎,厉终吉。", + "九二:干母之蛊,不可贞。", + "九三:干父之蛊,小有悔,无大咎。", + "六四:裕父之蛊,往见吝。", + "六五:干父之蛊,用誉。", + "上九:不事王侯,高尚其事。" + ], + "linePlainBottomUp": [ + "干父之蛊,有子,考无咎。厉,终吉。", + "干母之蛊,不可贞。", + "干父之蛊,小有悔,无大咎。", + "裕父之蛊,往见吝。", + "干父之蛊,用誉。", + "不事王侯,高尚其事。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 19, + "upperTrigram": "KUN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "name": "临", + "symbol": "䷒", + "judgmentOriginal": "元亨。利贞。至于八月有凶。", + "judgmentPlain": "元亨,利贞。至于八月有凶。", + "lineTextsBottomUp": [ + "初九:咸临,贞吉。", + "九二:咸临,吉无不利。", + "六三:甘临,无攸利。既忧之,无咎。", + "六四:至临,无咎。", + "六五:知临,大君之宜,吉。", + "上六:敦临,吉无咎。" + ], + "linePlainBottomUp": [ + "咸临,贞吉。", + "咸临,吉,无不利。", + "甘临,无攸利。既忧之,无灾。", + "至临,无灾。", + "知临,大君之宜,吉。", + "敦临,吉,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 20, + "upperTrigram": "XUN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "name": "观", + "symbol": "䷓", + "judgmentOriginal": "盥而不荐,有孚颙若。", + "judgmentPlain": "盥而不荐,有孚颙若。", + "lineTextsBottomUp": [ + "初六:童观,小人无咎,君子吝。", + "六二:窥观,利女贞。", + "六三:观我生,进退。", + "六四:观国之光,利用宾于王。", + "九五:观我生,君子无咎。", + "上九:观其生,君子无咎。" + ], + "linePlainBottomUp": [ + "童观,小人无咎,君子吝。", + "窥观,利女贞。", + "观我生,进退。", + "观国之光,利用宾于王。", + "观我生,君子无咎。", + "观其生,君子无咎。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 21, + "upperTrigram": "LI", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "name": "噬嗑", + "symbol": "䷔", + "judgmentOriginal": "亨。利用狱。", + "judgmentPlain": "亨通。利用狱。", + "lineTextsBottomUp": [ + "初九:屦校灭趾,无咎。", + "六二:噬肤灭鼻,无咎。", + "六三:噬腊肉,遇毒;小吝,无咎。", + "九四:噬干胏,得金矢,利艰贞,吉。", + "六五:噬干肉,得黄金,贞厉,无咎。", + "上九:何校灭耳,凶。" + ], + "linePlainBottomUp": [ + "屦校灭趾,无灾。", + "噬肤灭鼻,无灾。", + "噬腊肉,遇毒。小吝,无灾。", + "噬干胏,得金矢。利艰贞,吉。", + "噬干肉,得黄金。贞厉,无灾。", + "何校灭耳,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 22, + "upperTrigram": "GEN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "name": "贲", + "symbol": "䷕", + "judgmentOriginal": "亨。小利有攸往。", + "judgmentPlain": "亨通。小利有攸往。", + "lineTextsBottomUp": [ + "初九:贲其趾,舍车而徒。", + "六二:贲其须。", + "九三:贲如濡如,永贞吉。", + "六四:贲如皤如,白马翰如,匪寇婚媾。", + "六五:贲于丘园,束帛戋戋,吝,终吉。", + "上九:白贲,无咎。" + ], + "linePlainBottomUp": [ + "贲其趾,舍车而徒。", + "贲其须。", + "贲如濡如,永贞吉。", + "贲如皤如,白马翰如。匪寇婚媾。", + "贲于丘园,束帛戋戋。吝,终吉。", + "白贲,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 23, + "upperTrigram": "GEN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "name": "剥", + "symbol": "䷖", + "judgmentOriginal": "不利。有攸往。", + "judgmentPlain": "不利于有所前往。", + "lineTextsBottomUp": [ + "初六:剥床以足,蔑贞凶。", + "六二:剥床以辨,蔑贞凶。", + "六三:剥之,无咎。", + "六四:剥床以肤,凶。", + "六五:贯鱼,以宫人宠,无不利。", + "上九:硕果不食,君子得舆,小人剥庐。" + ], + "linePlainBottomUp": [ + "剥床以足,蔑贞,凶。", + "剥床以辨,蔑贞,凶。", + "剥之,无灾。", + "剥床以肤,凶。", + "贯鱼,以宫人宠,无不利。", + "硕果不食。君子得舆,小人剥庐。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 24, + "upperTrigram": "KUN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "name": "复", + "symbol": "䷗", + "judgmentOriginal": "亨。出入无疾,朋来无咎。反复其道,七日来复,利有攸往。", + "judgmentPlain": "亨通。出入没有疾病,朋友来也无灾。一来一回按那条路走,七天会回复。利于有所前往。", + "lineTextsBottomUp": [ + "初九:不复远,无袛悔,元吉。", + "六二:休复,吉。", + "六三:频复,厉无咎。", + "六四:中行独复。", + "六五:敦复,无悔。", + "上六:迷复,凶,有灾眚。用行师,终有大败,以其国君,凶;至于十年,不克征。" + ], + "linePlainBottomUp": [ + "回复得还不远,没有大的悔恨,大为吉祥。", + "美好地回复,吉。", + "频繁回复,有危难,无灾。", + "走在行列中间,独自回复。", + "敦厚地回复,没有悔恨。", + "迷路却不回复,凶,有灾祸。用此出兵,终有大败,连累国君,凶;到十年还不能出征。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 25, + "upperTrigram": "QIAN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "name": "无妄", + "symbol": "䷘", + "judgmentOriginal": "无妄:元亨。利贞。其匪正有眚,不利有攸往。", + "judgmentPlain": "元亨,利贞。其匪正有眚,不利有攸往。", + "lineTextsBottomUp": [ + "初九:无妄,往吉。", + "六二:不耕获,不菑畬,则利有攸往。", + "六三:无妄之灾,或系之牛,行人之得,邑人之灾。", + "九四:可贞,无咎。", + "九五:无妄之疾,勿药有喜。", + "上九:无妄,行有眚,无攸利。" + ], + "linePlainBottomUp": [ + "无妄,往吉。", + "不耕获,不菑畲,则利有攸往。", + "无妄之灾。或系之牛,行人之得,邑人之灾。", + "可贞,无灾。", + "无妄之疾,勿药有喜。", + "无妄,行有眚,无攸利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 26, + "upperTrigram": "GEN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "name": "大畜", + "symbol": "䷙", + "judgmentOriginal": "利贞,不家食吉,利涉大川。", + "judgmentPlain": "利贞。不家食,吉。利涉大川。", + "lineTextsBottomUp": [ + "初九:有厉利已。", + "九二:舆说輹。", + "九三:良马逐,利艰贞。曰闲舆卫,利有攸往。", + "六四:童牛之牿,元吉。", + "六五:豮豕之牙,吉。", + "上九:何天之衢,亨。" + ], + "linePlainBottomUp": [ + "有厉,利已。", + "舆说輹。", + "良马逐,利艰贞。日闲舆卫,利有攸往。", + "童牛之牿,元吉。", + "豮豕之牙,吉。", + "何天之衢,亨。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 27, + "upperTrigram": "GEN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "name": "颐", + "symbol": "䷚", + "judgmentOriginal": "贞吉。观颐,自求口实。", + "judgmentPlain": "贞吉。观颐,自求口实。", + "lineTextsBottomUp": [ + "初九:舍尔灵龟,观我朵颐,凶。", + "六二:颠颐,拂经,于丘颐,征凶。", + "六三:拂颐,贞凶,十年勿用,无攸利。", + "六四:颠颐吉,虎视眈眈,其欲逐逐,无咎。", + "六五:拂经,居贞吉,不可涉大川。", + "上九:由颐,厉吉,利涉大川。" + ], + "linePlainBottomUp": [ + "舍尔灵龟,观我朵颐,凶。", + "颠颐,拂经,于丘颐,征凶。", + "拂颐,贞凶。十年勿用,无攸利。", + "颠颐,吉。虎视眈眈,其欲逐逐,无灾。", + "拂经,居贞吉,不可涉大川。", + "由颐,厉吉,利涉大川。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 28, + "upperTrigram": "DUI", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "name": "大过", + "symbol": "䷛", + "judgmentOriginal": "栋桡,利有攸往,亨。", + "judgmentPlain": "栋桡。利有攸往,亨。", + "lineTextsBottomUp": [ + "初六:藉用白茅,无咎。", + "九二:枯杨生稊,老夫得其女妻,无不利。", + "九三:栋桡,凶。", + "九四:栋隆,吉。有它吝。", + "九五:枯杨生华,老妇得其士夫,无咎无誉。", + "上六:过涉灭顶,凶,无咎。" + ], + "linePlainBottomUp": [ + "藉用白茅,无灾。", + "枯杨生稊,老夫得其女妻,无不利。", + "栋桡,凶。", + "栋隆,吉。有它吝。", + "枯杨生华,老妇得其士夫,无咎无誉。", + "过涉灭顶,凶,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 29, + "upperTrigram": "KAN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "name": "坎", + "symbol": "䷜", + "judgmentOriginal": "有孚,维心亨。行有尚。", + "judgmentPlain": "有孚,维心亨,行有尚。", + "lineTextsBottomUp": [ + "初六:习坎,入于坎窞,凶。", + "九二:坎有险,求小得。", + "六三:来之坎坎,险且枕,入于坎窞,勿用。", + "六四:樽酒簋贰,用缶,纳约自牖,终无咎。", + "九五:坎不盈,祗既平,无咎。", + "上六:系用徽𬙊,寘于丛棘,三岁不得,凶。" + ], + "linePlainBottomUp": [ + "习坎,入于坎窞,凶。", + "坎有险,求小得。", + "来之坎坎,险且枕,入于坎窞,勿用。", + "樽酒簋贰,用缶,纳约自牖,终无灾。", + "坎不盈,祗既平,无灾。", + "系用徽纆,置于丛棘,三岁不得,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 30, + "upperTrigram": "LI", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "name": "离", + "symbol": "䷝", + "judgmentOriginal": "利贞。亨。畜牝牛,吉。", + "judgmentPlain": "利贞,亨。畜牝牛,吉。", + "lineTextsBottomUp": [ + "初九:履错然,敬之无咎。", + "六二:黄离,元吉。", + "九三:日昃之离,不鼓缶而歌,则大耋之嗟,凶。", + "九四:突如其来如,焚如,死如,弃如。", + "六五:出涕沱若,戚嗟若,吉。", + "上九:王用出征,有嘉折首,获匪其丑,无咎。" + ], + "linePlainBottomUp": [ + "履错然,敬之,无灾。", + "黄离,元吉。", + "日昃之离,不鼓缶而歌,则大耋之嗟,凶。", + "突如其来如,焚如,死如,弃如。", + "出涕沱若,戚嗟若,吉。", + "王用出征,有嘉折首,获匪其丑,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 31, + "upperTrigram": "DUI", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "name": "咸", + "symbol": "䷞", + "judgmentOriginal": "亨。利贞。取女吉。", + "judgmentPlain": "亨通。利贞。取女吉。", + "lineTextsBottomUp": [ + "初六:咸其拇。", + "六二:咸其腓,凶,居吉。", + "九三:咸其股,执其随,往吝。", + "九四:贞吉悔亡,憧憧往来,朋从尔思。", + "九五:咸其脢,无悔。", + "上六:咸其辅,颊,舌。" + ], + "linePlainBottomUp": [ + "咸其拇。", + "咸其腓,凶。居吉。", + "咸其股,执其随,往吝。", + "贞吉,悔亡。憧憧往来,朋从尔思。", + "咸其脢,无悔。", + "咸其辅颊舌。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 32, + "upperTrigram": "ZHEN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "name": "恒", + "symbol": "䷟", + "judgmentOriginal": "亨,无咎。利贞,利有攸往。", + "judgmentPlain": "亨通。无灾。利于守正。利于有所前往。", + "lineTextsBottomUp": [ + "初六:浚恒,贞凶,无攸利。", + "九二:悔亡。", + "九三:不恒其德,或承之羞,贞吝。", + "九四:田无禽。", + "六五:恒其德,贞,妇人吉,夫子凶。", + "上六:振恒,凶。" + ], + "linePlainBottomUp": [ + "深求恒久,守正则凶,无所利。", + "悔恨消失。", + "不能恒久其德,或许会承受羞辱,守正有憾。", + "田里没有禽兽。", + "恒久其德,守正。妇人吉,男子凶。", + "振动不安于恒,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 33, + "upperTrigram": "QIAN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "name": "遁", + "symbol": "䷠", + "judgmentOriginal": "亨。小利贞。", + "judgmentPlain": "亨通。小利于守正。", + "lineTextsBottomUp": [ + "初六:遁尾,厉,勿用有攸往。", + "六二:执之用黄牛之革,莫之胜说。", + "九三:系遁,有疾厉,畜臣妾吉。", + "九四:好遁君子吉,小人否。", + "九五:嘉遁,贞吉。", + "上九:肥遁,无不利。" + ], + "linePlainBottomUp": [ + "遁走只剩尾巴,有危,不要有所前往。", + "用黄牛皮捆住,没有人能解脱。", + "被牵绊着退避,有疾病和危难。畜养臣妾,吉。", + "喜好退避,君子吉,小人否塞。", + "嘉美地退避,守正吉。", + "充裕地退避,没有不利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 34, + "upperTrigram": "ZHEN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "name": "大壮", + "symbol": "䷡", + "judgmentOriginal": "利贞。", + "judgmentPlain": "利于守正。", + "lineTextsBottomUp": [ + "初九:壮于趾,征凶,有孚。", + "九二:贞吉。", + "九三:小人用壮,君子用罔,贞厉。羝羊触藩,羸其角。", + "九四:贞吉悔亡,藩决不羸,壮于大舆之輹。", + "六五:丧羊于易,无悔。", + "上六:羝羊触藩,不能退,不能遂,无攸利,艰则吉。" + ], + "linePlainBottomUp": [ + "壮在脚趾,出征凶,有诚信。", + "贞吉。", + "小人用壮,君子用罔,贞厉。公羊触藩,缠住了角。", + "贞吉,悔恨消失。藩篱没被破坏,壮在大车的辐上。", + "在田里丧失羊,无悔。", + "公羊触藩,不能退不能进,无攸利。艰难则吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 35, + "upperTrigram": "LI", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "name": "晋", + "symbol": "䷢", + "judgmentOriginal": "康侯用锡马蕃庶,昼日三接。", + "judgmentPlain": "康侯用锡马蕃庶,白天三次接见。", + "lineTextsBottomUp": [ + "初六:晋如,摧如,贞吉。罔孚,裕无咎。", + "六二:晋如,愁如,贞吉。受兹介福,于其王母。", + "六三:众允,悔亡。", + "九四:晋如鼫鼠,贞厉。", + "六五:悔亡,失得勿恤,往吉无不利。", + "上九:晋其角,维用伐邑,厉吉无咎,贞吝。" + ], + "linePlainBottomUp": [ + "晋如摧如,贞吉。罔孚,裕无灾。", + "晋如愁如,贞吉。受兹介福,于其王母。", + "众允,悔亡。", + "晋如鼫鼠,贞厉。", + "悔亡,失得勿恤。往吉,无不利。", + "晋其角,维用伐邑,厉吉,无灾,贞吝。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 36, + "upperTrigram": "KUN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "name": "明夷", + "symbol": "䷣", + "judgmentOriginal": "利艰贞。", + "judgmentPlain": "利于艰难中守正。", + "lineTextsBottomUp": [ + "初九:明夷于飞,垂其翼。君子于行,三日不食,有攸往,主人有言。", + "六二:明夷,夷于左股,用拯马壮,吉。", + "九三:明夷于南狩,得其大首,不可疾贞。", + "六四:入于左腹,获明夷之心,于出门庭。", + "六五:箕子之明夷,利贞。", + "上六:不明晦,初登于天,后入于地。" + ], + "linePlainBottomUp": [ + "明夷于飞,垂其翼。君子于行,三日不食。有攸往,主人有言。", + "明夷,夷于左股,用拯马壮,吉。", + "明夷于南狩,得其大首,不可疾贞。", + "入于左腹,获明夷之心,于出门庭。", + "箕子之明夷,利贞。", + "不明晦。初登于天,后入于地。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 37, + "upperTrigram": "XUN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "name": "家人", + "symbol": "䷤", + "judgmentOriginal": "利女贞。", + "judgmentPlain": "利于女子守正。", + "lineTextsBottomUp": [ + "初九:闲有家,悔亡。", + "六二:无攸遂,在中馈,贞吉。", + "九三:家人嗃嗃,悔厉吉;妇子嘻嘻,终吝。", + "六四:富家,大吉。", + "九五:王假有家,勿恤。吉。", + "上九:有孚威如,终吉。" + ], + "linePlainBottomUp": [ + "闲有家,悔亡。", + "无攸遂,在中馈,贞吉。", + "家人嗃嗃,悔厉吉;妇子嘻嘻,终吝。", + "富家,大吉。", + "王假有家,勿恤,吉。", + "有孚威如,终吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 38, + "upperTrigram": "LI", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "name": "睽", + "symbol": "䷥", + "judgmentOriginal": "小事吉。", + "judgmentPlain": "小事吉。", + "lineTextsBottomUp": [ + "初九:悔亡,丧马勿逐,自复;见恶人无咎。", + "九二:遇主于巷,无咎。", + "六三:见舆曳,其牛掣,其人天且劓,无初有终。", + "九四:睽孤,遇元夫,交孚,厉无咎。", + "六五:悔亡,厥宗噬肤,往何咎。", + "上九:睽孤,见豕负涂,载鬼一车,先张之弧,后说之弧,匪寇婚媾,往遇雨则吉。" + ], + "linePlainBottomUp": [ + "悔亡。丧马勿逐,自复。见恶人,无灾。", + "遇主于巷,无灾。", + "见舆曳,其牛掣,其人天且劓。无初有终。", + "睽孤,遇元夫,交孚,厉无灾。", + "悔亡。厥宗噬肤,往何咎。", + "睽孤,见豕负涂,载鬼一车。先张之弧,后说之弧。匪寇婚媾。往遇雨则吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 39, + "upperTrigram": "KAN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "name": "蹇", + "symbol": "䷦", + "judgmentOriginal": "利西南,不利东北;利见大人,贞吉。", + "judgmentPlain": "利西南,不利东北。利见大人。贞吉。", + "lineTextsBottomUp": [ + "初六:往蹇,来誉。", + "六二:王臣蹇蹇,匪躬之故。", + "九三:往蹇来反。", + "六四:往蹇来连。", + "九五:大蹇朋来。", + "上六:往蹇来硕,吉;利见大人。" + ], + "linePlainBottomUp": [ + "往蹇,来誉。", + "王臣蹇蹇,匪躬之故。", + "往蹇,来反。", + "往蹇,来连。", + "大蹇,朋来。", + "往蹇,来硕,吉。利见大人。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 40, + "upperTrigram": "ZHEN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "name": "解", + "symbol": "䷧", + "judgmentOriginal": "利西南,无所往,其来复吉。有攸往,夙吉。", + "judgmentPlain": "利西南。无所往,其来复吉。有攸往,夙吉。", + "lineTextsBottomUp": [ + "初六:无咎。", + "九二:田获三狐,得黄矢,贞吉。", + "六三:负且乘,致寇至,贞吝。", + "九四:解而拇,朋至斯孚。", + "六五:君子维有解,吉;有孚于小人。", + "上六:公用射隼,于高墉之上,获之,无不利。" + ], + "linePlainBottomUp": [ + "无灾。", + "田获三狐,得黄矢,贞吉。", + "负且乘,致寇至,贞吝。", + "解而拇,朋至斯孚。", + "君子维有解,吉。有孚于小人。", + "公用射隼于高墉之上,获之,无不利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 41, + "upperTrigram": "GEN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "name": "损", + "symbol": "䷨", + "judgmentOriginal": "有孚,元吉。无咎,可贞,利有攸往。曷之用?二簋可用享。", + "judgmentPlain": "有孚,元吉,无灾,可贞,利有攸往。曷之用?二簋可用享。", + "lineTextsBottomUp": [ + "初九:已事遄往,无咎,酌损之。", + "九二:利贞,征凶,弗损益之。", + "六三:三人行,则损一人;一人行,则得其友。", + "六四:损其疾,使遄有喜,无咎。", + "六五:或益之,十朋之龟弗克违,元吉。", + "上九:弗损益之,无咎,贞吉,利有攸往,得臣无家。" + ], + "linePlainBottomUp": [ + "已事遄往,无灾。酌损之。", + "利贞。征凶。弗损,益之。", + "三人行则损一人,一人行则得其友。", + "损其疾,使遄有喜,无灾。", + "或益之十朋之龟,弗克违,元吉。", + "弗损,益之,无灾。贞吉。利有攸往,得臣无家。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 42, + "upperTrigram": "XUN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "name": "益", + "symbol": "䷩", + "judgmentOriginal": "利有攸往。利涉大川。", + "judgmentPlain": "利有攸往。利涉大川。", + "lineTextsBottomUp": [ + "初九:利用为大作,元吉,无咎。", + "六二:或益之,十朋之龟弗克违,永贞吉。王用享于帝,吉。", + "六三:益之用凶事,无咎。有孚中行,告公用圭。", + "六四:中行,告公从。利用为依迁国。", + "九五:有孚惠心,勿问元吉。有孚惠我德。", + "上九:莫益之,或击之,立心勿恒,凶。" + ], + "linePlainBottomUp": [ + "利用为大作,元吉,无灾。", + "或益之十朋之龟,弗克违。永贞吉。王用享于帝,吉。", + "益之用凶事,无灾。有孚中行,告公用圭。", + "中行,告公从,利用为依迁国。", + "有孚惠心,勿问元吉。有孚惠我德。", + "莫益之,或击之,立心勿恒,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 43, + "upperTrigram": "DUI", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "name": "夬", + "symbol": "䷪", + "judgmentOriginal": "扬于王庭,孚号,有厉,告自邑,不利即戎,利有攸往。", + "judgmentPlain": "扬于王庭。孚号有厉。告自邑,不利即戎,利有攸往。", + "lineTextsBottomUp": [ + "初九:壮于前趾,往不胜为咎。", + "九二:惕号,莫夜有戎,勿恤。", + "九三:壮于頄,有凶。君子夬夬,独行遇雨,若濡有愠,无咎。", + "九四:臀无肤,其行次且。牵羊悔亡,闻言不信。", + "九五:苋陆夬夬,中行无咎。", + "上六:无号,终有凶。" + ], + "linePlainBottomUp": [ + "壮于前趾,往不胜为咎。", + "惕号,莫夜有戎,勿恤。", + "壮于頄,有凶。君子夬夬,独行遇雨,若濡有愠,无灾。", + "臀无肤,其行次且。牵羊悔亡,闻言不信。", + "苋陆夬夬,中行无灾。", + "无号,终有凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 44, + "upperTrigram": "QIAN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "name": "姤", + "symbol": "䷫", + "judgmentOriginal": "女壮,勿用取女。", + "judgmentPlain": "女壮,勿用取女。", + "lineTextsBottomUp": [ + "初六:系于金柅,贞吉,有攸往,见凶,羸豕孚踟躅。", + "九二:包有鱼,无咎,不利宾。", + "九三:臀无肤,其行次且,厉,无大咎。", + "九四:包无鱼,起凶。", + "九五:以杞包瓜,含章,有陨自天。", + "上九:姤其角,吝,无咎。" + ], + "linePlainBottomUp": [ + "系于金柅,贞吉。有攸往,见凶。羸豕孚蹢躅。", + "包有鱼,无灾,不利宾。", + "臀无肤,其行次且,厉,无大咎。", + "包无鱼,起凶。", + "以杞包瓜,含章,有陨自天。", + "姤其角,吝,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 45, + "upperTrigram": "DUI", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "name": "萃", + "symbol": "䷬", + "judgmentOriginal": "亨。王假有庙,利见大人,亨。利贞。用大牲吉,利有攸往。", + "judgmentPlain": "亨通。王假有庙。利见大人,亨,利贞。用大牲吉。利有攸往。", + "lineTextsBottomUp": [ + "初六:有孚不终,乃乱乃萃,若号一握为笑,勿恤,往无咎。", + "六二:引吉,无咎,孚乃利用禴。", + "六三:萃如,嗟如,无攸利,往无咎,小吝。", + "九四:大吉,无咎。", + "九五:萃有位,无咎。匪孚,元永贞,悔亡。", + "上六:赍咨涕洟,无咎。" + ], + "linePlainBottomUp": [ + "有孚不终,乃乱乃萃。若号,一握为笑,勿恤,往无灾。", + "引吉,无灾。孚乃利用禴。", + "萃如嗟如,无攸利。往无灾,小吝。", + "大吉,无灾。", + "萃有位,无灾。匪孚,元永贞,悔亡。", + "赍咨涕洟,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 46, + "upperTrigram": "KUN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "name": "升", + "symbol": "䷭", + "judgmentOriginal": "元亨,用见大人,勿恤,南征吉。", + "judgmentPlain": "元亨。用见大人,勿恤。南征吉。", + "lineTextsBottomUp": [ + "初六:允升,大吉。", + "九二:孚乃利用禴,无咎。", + "九三:升虚邑。", + "六四:王用亨于岐山,吉无咎。", + "六五:贞吉,升阶。", + "上六:冥升,利于不息之贞。" + ], + "linePlainBottomUp": [ + "允升,大吉。", + "孚乃利用禴,无灾。", + "升虚邑。", + "王用亨于岐山,吉,无灾。", + "贞吉,升阶。", + "冥升,利于不息之贞。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 47, + "upperTrigram": "DUI", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "name": "困", + "symbol": "䷮", + "judgmentOriginal": "亨,贞大人吉,无咎,有言不信。", + "judgmentPlain": "亨通。贞,大人吉,无灾。有言不信。", + "lineTextsBottomUp": [ + "初六:臀困于株木,入于幽谷,三岁不觌。", + "九二:困于酒食,朱绂方来,利用亨祀,征凶,无咎。", + "六三:困于石,据于蒺藜,入于其宫,不见其妻,凶。", + "九四:来徐徐,困于金车,吝,有终。", + "九五:劓刖,困于赤绂,乃徐有说,利用祭祀。", + "上六:困于葛藟,于臲卼,曰动悔。有悔,征吉。" + ], + "linePlainBottomUp": [ + "臀困于株木,入于幽谷,三岁不觌。", + "困于酒食,朱绂方来,利用享祀。征凶,无灾。", + "困于石,据于蒺藜。入于其宫,不见其妻,凶。", + "来徐徐,困于金车,吝,有终。", + "劓刖,困于赤绂。乃徐有说,利用祭祀。", + "困于葛藟,于臲卼。曰动悔有悔,征吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 48, + "upperTrigram": "KAN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "name": "井", + "symbol": "䷯", + "judgmentOriginal": "改邑不改井,无丧无得,往来井井。汔至亦未繘井。羸其瓶,凶。", + "judgmentPlain": "改邑不改井,无丧无得。往来井井。汔至,亦未繘井,羸其瓶,凶。", + "lineTextsBottomUp": [ + "初六:井泥不食,旧井无禽。", + "九二:井谷射鲋,瓮敝漏。", + "九三:井渫不食,为我心恻,可用汲,王明,并受其福。", + "六四:井甃,无咎。", + "九五:井冽,寒泉食。", + "上六:井收勿幕,有孚元吉。" + ], + "linePlainBottomUp": [ + "井泥不食,旧井无禽。", + "井谷射鲋,瓮敝漏。", + "井渫不食,为我心恻。可用汲,王明,并受其福。", + "井甃,无灾。", + "井冽,寒泉食。", + "井收勿幕,有孚元吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 49, + "upperTrigram": "DUI", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "name": "革", + "symbol": "䷰", + "judgmentOriginal": "巳日乃孚,元亨。利贞。悔亡。", + "judgmentPlain": "己日乃孚。元亨,利贞,悔亡。", + "lineTextsBottomUp": [ + "初九:巩用黄牛之革。", + "六二:巳日乃革之,征吉,无咎。", + "九三:征凶,贞厉,革言三就,有孚。", + "九四:悔亡,有孚改命,吉。", + "九五:大人虎变,未占有孚。", + "上六:君子豹变,小人革面,征凶,居贞吉。" + ], + "linePlainBottomUp": [ + "巩用黄牛之革。", + "己日乃革之,征吉,无灾。", + "征凶,贞厉。革言三就,有孚。", + "悔亡。有孚改命,吉。", + "大人虎变,未占有孚。", + "君子豹变,小人革面。征凶,居贞吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 50, + "upperTrigram": "LI", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "name": "鼎", + "symbol": "䷱", + "judgmentOriginal": "元吉,亨。", + "judgmentPlain": "元吉,亨通。", + "lineTextsBottomUp": [ + "初六:鼎颠趾,利出否,得妾以其子,无咎。", + "九二:鼎有实,我仇有疾,不我能即,吉。", + "九三:鼎耳革,其行塞,雉膏不食,方雨亏悔,终吉。", + "九四:鼎折足,覆公𫗧,其形渥,凶。", + "六五:鼎黄耳金铉,利贞。", + "上九:鼎玉铉,大吉,无不利。" + ], + "linePlainBottomUp": [ + "鼎颠趾,利出否。得妾以其子,无灾。", + "鼎有实。我仇有疾,不我能即,吉。", + "鼎耳革,其行塞,雉膏不食。方雨亏悔,终吉。", + "鼎折足,覆公餗,其形渥,凶。", + "鼎黄耳金铉,利贞。", + "鼎玉铉,大吉,无不利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 51, + "upperTrigram": "ZHEN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "name": "震", + "symbol": "䷲", + "judgmentOriginal": "亨。震来虩虩,笑言哑哑。震惊百里,不丧匕鬯。", + "judgmentPlain": "亨通。震来虩虩,笑言哑哑。震惊百里,不丧匕鬯。", + "lineTextsBottomUp": [ + "初九:震来虩虩,后笑言哑哑,吉。", + "六二:震来厉,亿丧贝,跻于九陵,勿逐,七日得。", + "六三:震苏苏,震行无眚。", + "九四:震遂泥。", + "六五:震往来厉,亿无丧,有事。", + "上六:震索索,视矍矍,征凶。震不于其躬,于其邻,无咎。婚媾有言。" + ], + "linePlainBottomUp": [ + "震来虩虩,后笑言哑哑,吉。", + "震来厉,亿丧贝。跻于九陵,勿逐,七日得。", + "震苏苏,震行无眚。", + "震遂泥。", + "震往来厉,亿无丧,有事。", + "震索索,视矍矍,征凶。震不于其躬,于其邻,无灾。婚媾有言。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 52, + "upperTrigram": "GEN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "name": "艮", + "symbol": "䷳", + "judgmentOriginal": "艮其背,不获其身,行其庭,不见其人,无咎。", + "judgmentPlain": "艮其背,不获其身;行其庭,不见其人,无灾。", + "lineTextsBottomUp": [ + "初六:艮其趾,无咎,利永贞。", + "六二:艮其腓,不拯其随,其心不快。", + "九三:艮其限,列其夤,厉熏心。", + "六四:艮其身,无咎。", + "六五:艮其辅,言有序,悔亡。", + "上九:敦艮,吉。" + ], + "linePlainBottomUp": [ + "艮其趾,无灾,利永贞。", + "艮其腓,不拯其随,其心不快。", + "艮其限,列其夤,厉薰心。", + "艮其身,无灾。", + "艮其辅,言有序,悔亡。", + "敦艮,吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 53, + "upperTrigram": "XUN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "name": "渐", + "symbol": "䷴", + "judgmentOriginal": "女归吉,利贞。", + "judgmentPlain": "女归吉。利贞。", + "lineTextsBottomUp": [ + "初六:鸿渐于干,小子厉,有言,无咎。", + "六二:鸿渐于磐,饮食衎衎,吉。", + "九三:鸿渐于陆,夫征不复,妇孕不育,凶;利御寇。", + "六四:鸿渐于木,或得其桷,无咎。", + "九五:鸿渐于陵,妇三岁不孕,终莫之胜,吉。", + "上九:鸿渐于陆,其羽可用为仪,吉。" + ], + "linePlainBottomUp": [ + "鸿渐于干,小子厉,有言,无灾。", + "鸿渐于磐,饮食衎衎,吉。", + "鸿渐于陆,夫征不复,妇孕不育,凶。利御寇。", + "鸿渐于木,或得其桷,无灾。", + "鸿渐于陵,妇三岁不孕,终莫之胜,吉。", + "鸿渐于陆,其羽可用为仪,吉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 54, + "upperTrigram": "ZHEN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "name": "归妹", + "symbol": "䷵", + "judgmentOriginal": "征凶,无攸利。", + "judgmentPlain": "征凶,无攸利。", + "lineTextsBottomUp": [ + "初九:归妹以娣,跛能履,征吉。", + "九二:眇能视,利幽人之贞。", + "六三:归妹以须,反归以娣。", + "九四:归妹愆期,迟归有时。", + "六五:帝乙归妹,其君之袂,不如其娣之袂良,月几望,吉。", + "上六:女承筐无实,士刲羊无血,无攸利。" + ], + "linePlainBottomUp": [ + "归妹以娣,跛能履,征吉。", + "眇能视,利幽人之贞。", + "归妹以须,反归以娣。", + "归妹愆期,迟归有时。", + "帝乙归妹,其君之袂不如其娣之袂良。月几望,吉。", + "女承筐无实,士刲羊无血,无攸利。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 55, + "upperTrigram": "ZHEN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "name": "丰", + "symbol": "䷶", + "judgmentOriginal": "亨。王假之,勿忧,宜日中。", + "judgmentPlain": "亨通。王假之。勿忧,宜日中。", + "lineTextsBottomUp": [ + "初九:遇其配主,虽旬无咎,往有尚。", + "六二:丰其蔀,日中见斗,往得疑疾,有孚发若,吉。", + "九三:丰其沛,日中见沫,折其右肱,无咎。", + "九四:丰其蔀,日中见斗,遇其夷主,吉。", + "六五:来章,有庆誉,吉。", + "上六:丰其屋,蔀其家,窥其户,阒其无人,三岁不觌,凶。" + ], + "linePlainBottomUp": [ + "遇其配主,虽旬无灾,往有尚。", + "丰其蔀,日中见斗。往得疑疾,有孚发若,吉。", + "丰其沛,日中见沫。折其右肱,无灾。", + "丰其蔀,日中见斗。遇其夷主,吉。", + "来章,有庆誉,吉。", + "丰其屋,蔀其家,窥其户,阒其无人,三岁不觌,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 56, + "upperTrigram": "LI", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "name": "旅", + "symbol": "䷷", + "judgmentOriginal": "小亨,旅贞吉。", + "judgmentPlain": "小亨。旅贞吉。", + "lineTextsBottomUp": [ + "初六:旅琐琐,斯其所取灾。", + "六二:旅即次,怀其资,得童仆贞。", + "九三:旅焚其次,丧其童仆,贞厉。", + "九四:旅于处,得其资斧,我心不快。", + "六五:射雉一矢亡,终以誉命。", + "上九:鸟焚其巢,旅人先笑后号咷。丧牛于易,凶。" + ], + "linePlainBottomUp": [ + "旅琐琐,斯其所取灾。", + "旅即次,怀其资,得童仆贞。", + "旅焚其次,丧其童仆,贞厉。", + "旅于处,得其资斧,我心不快。", + "射雉,一矢亡,终以誉命。", + "鸟焚其巢,旅人先笑后号咷。丧牛于易,凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 57, + "upperTrigram": "XUN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "name": "巽", + "symbol": "䷸", + "judgmentOriginal": "小亨。利有攸往。利见大人。", + "judgmentPlain": "小亨。利有攸往。利见大人。", + "lineTextsBottomUp": [ + "初六:进退,利武人之贞。", + "九二:巽在床下,用史巫纷若,吉无咎。", + "九三:频巽,吝。", + "六四:悔亡,田获三品。", + "九五:贞吉悔亡,无不利。无初有终,先庚三日,后庚三日,吉。", + "上九:巽在床下,丧其资斧,贞凶。" + ], + "linePlainBottomUp": [ + "进退,利武人之贞。", + "巽在床下,用史巫纷若,吉,无灾。", + "频巽,吝。", + "悔亡,田获三品。", + "贞吉,悔亡,无不利。无初有终。先庚三日,后庚三日,吉。", + "巽在床下,丧其资斧,贞凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 58, + "upperTrigram": "DUI", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "name": "兑", + "symbol": "䷹", + "judgmentOriginal": "亨。利贞。", + "judgmentPlain": "亨通。利贞。", + "lineTextsBottomUp": [ + "初九:和兑,吉。", + "九二:孚兑,吉,悔亡。", + "六三:来兑,凶。", + "九四:商兑,未宁,介疾有喜。", + "九五:孚于剥,有厉。", + "上六:引兑。" + ], + "linePlainBottomUp": [ + "和兑,吉。", + "孚兑,吉,悔亡。", + "来兑,凶。", + "商兑未宁,介疾有喜。", + "孚于剥,有厉。", + "引兑。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 59, + "upperTrigram": "XUN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "name": "涣", + "symbol": "䷺", + "judgmentOriginal": "亨。王假有庙,利涉大川,利贞。", + "judgmentPlain": "亨通。王假有庙。利涉大川,利贞。", + "lineTextsBottomUp": [ + "初六:用拯马壮,吉。", + "九二:涣奔其机,悔亡。", + "六三:涣其躬,无悔。", + "六四:涣其群,元吉。涣有丘,匪夷所思。", + "九五:涣汗其大号,涣王居,无咎。", + "上九:涣其血,去逖出,无咎。" + ], + "linePlainBottomUp": [ + "用拯马壮,吉。", + "涣奔其机,悔亡。", + "涣其躬,无悔。", + "涣其群,元吉。涣有丘,匪夷所思。", + "涣汗其大号,涣王居,无灾。", + "涣其血,去逖出,无灾。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 60, + "upperTrigram": "KAN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "name": "节", + "symbol": "䷻", + "judgmentOriginal": "亨。苦节不可贞。", + "judgmentPlain": "亨通。苦节不可贞。", + "lineTextsBottomUp": [ + "初九:不出户庭,无咎。", + "九二:不出门庭,凶。", + "六三:不节若,则嗟若,无咎。", + "六四:安节,亨。", + "九五:甘节,吉;往有尚。", + "上六:苦节,贞凶,悔亡。" + ], + "linePlainBottomUp": [ + "不出户庭,无灾。", + "不出门庭,凶。", + "不节若,则嗟若,无灾。", + "安节,亨。", + "甘节,吉。往有尚。", + "苦节,贞凶,悔亡。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 61, + "upperTrigram": "XUN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "name": "中孚", + "symbol": "䷼", + "judgmentOriginal": "豚鱼吉,利涉大川,利贞。", + "judgmentPlain": "豚鱼吉。利涉大川,利贞。", + "lineTextsBottomUp": [ + "初九:虞吉,有他不燕。", + "九二:鸣鹤在阴,其子和之,我有好爵,吾与尔靡之。", + "六三:得敌,或鼓或罢,或泣或歌。", + "六四:月几望,马匹亡,无咎。", + "九五:有孚挛如,无咎。", + "上九:翰音登于天,贞凶。" + ], + "linePlainBottomUp": [ + "虞吉,有它不燕。", + "鸣鹤在阴,其子和之。我有好爵,吾与尔靡之。", + "得敌,或鼓或罢,或泣或歌。", + "月几望,马匹亡,无灾。", + "有孚挛如,无灾。", + "翰音登于天,贞凶。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 62, + "upperTrigram": "ZHEN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "name": "小过", + "symbol": "䷽", + "judgmentOriginal": "亨。利贞。可小事,不可大事。飞鸟遗之音,不宜上宜下,大吉。", + "judgmentPlain": "亨通。利贞。可小事,不可大事。飞鸟遗之音,不宜上,宜下,大吉。", + "lineTextsBottomUp": [ + "初六:飞鸟以凶。", + "六二:过其祖,遇其妣;不及其君,遇其臣;无咎。", + "九三:弗过防之,从或戕之,凶。", + "九四:无咎,弗过遇之。往厉必戒,勿用永贞。", + "六五:密云不雨,自我西郊,公弋取彼在穴。", + "上六:弗遇过之,飞鸟离之,凶,是谓灾眚。" + ], + "linePlainBottomUp": [ + "飞鸟以凶。", + "过其祖,遇其妣。不及其君,遇其臣,无灾。", + "弗过防之,从或戕之,凶。", + "无灾。弗过遇之。往厉必戒,勿用永贞。", + "密云不雨,自我西郊。公弋取彼在穴。", + "弗遇过之,飞鸟离之,凶。是谓灾眚。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 63, + "upperTrigram": "KAN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "name": "既济", + "symbol": "䷾", + "judgmentOriginal": "亨小。利贞。初吉终乱。", + "judgmentPlain": "亨通。小利贞。初吉终乱。", + "lineTextsBottomUp": [ + "初九:曳其轮,濡其尾,无咎。", + "六二:妇丧其茀,勿逐,七日得。", + "九三:高宗伐鬼方,三年克之,小人勿用。", + "六四:𦈡有衣袽,终日戒。", + "九五:东邻杀牛,不如西邻之禴祭,实受其福。", + "上六:濡其首,厉。" + ], + "linePlainBottomUp": [ + "曳其轮,濡其尾,无灾。", + "妇丧其茀,勿逐,七日得。", + "高宗伐鬼方,三年克之,小人勿用。", + "繻有衣袽,终日戒。", + "东邻杀牛,不如西邻之禴祭,实受其福。", + "濡其首,厉。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + }, + { + "kingWenNumber": 64, + "upperTrigram": "LI", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "name": "未济", + "symbol": "䷿", + "judgmentOriginal": "亨。小狐汔济,濡其尾,无攸利。", + "judgmentPlain": "亨通。小狐汔济,濡其尾,无攸利。", + "lineTextsBottomUp": [ + "初六:濡其尾,吝。", + "九二:曳其轮,贞吉。", + "六三:未济,征凶,利涉大川。", + "九四:贞吉,悔亡,震用伐鬼方,三年有赏于大国。", + "六五:贞吉,无悔,君子之光,有孚,吉。", + "上九:有孚于饮酒,无咎,濡其首,有孚失是。" + ], + "linePlainBottomUp": [ + "濡其尾,吝。", + "曳其轮,贞吉。", + "未济,征凶,利涉大川。", + "贞吉,悔亡。震用伐鬼方,三年有赏于大国。", + "贞吉,无悔。君子之光,有孚,吉。", + "有孚于饮酒,无灾。濡其首,有孚失是。" + ], + "specialUsageText": null, + "sourceRefs": [ + "wikisource-zhouyi-jing-zh-Hans", + "lingji-plain-zh-Hans-2026.1" + ] + } + ] +} diff --git a/content/plain/lingji-plain.mjs b/content/plain/lingji-plain.mjs new file mode 100644 index 0000000..6c33247 --- /dev/null +++ b/content/plain/lingji-plain.mjs @@ -0,0 +1,67 @@ +/** 灵机自撰白话草稿。按文王序 1–64;每项为 [卦辞, 初, 二, 三, 四, 五, 上]。 */ +export const lingjiPlain = [ + ["开始即通达,利于守持正道。", "龙还潜藏着,先不要施展。", "龙出现在田野,利于去见有识之人。", "君子整日健进,夜里仍警惕;虽有危难,可以无灾。", "或跳进深渊,可以无灾。", "龙飞在天上,利于去见有识之人。", "龙飞得过高,会有悔恨。"], + ["开始即通达,利于像母马那样守持正道。君子有所前往,先会迷路,随后才得到依靠。利于西南得到同类,东北失去同类。安于守正,吉。", "踩到霜,坚冰就要来了。", "正直方正而广大,不必演习,没有不利。", "蕴含文采,可以守正。或跟从王事,不求自己成功,却能有结果。", "扎紧口袋,无灾也无称誉。", "黄色下裳,大为吉祥。", "龙在郊野争斗,血流成青黄色。"], + ["开始即通达,利于守正。不要急着前往,利于立诸侯。", "徘徊不进,利于安居守正,利于立诸侯。", "困顿难行,乘马盘旋。不是强盗,是来求婚。女子守正不嫁,十年才许嫁。", "追鹿却没有虞人向导,只是陷入林中。君子察觉危险,不如放弃;再往前会有憾恨。", "乘马盘旋,去求婚,前往吉,没有不利。", "屯积膏泽。小事守正吉,大事守正凶。", "乘马盘旋,血泪涟涟。"], + ["亨通。我不是要去求童蒙,是童蒙来求我。初次卜问则告知;再三乱问,就不告知。利于守正。", "启发蒙昧,利于用刑罚纠正人,用桎梏约束;若一再用刑,就有憾恨。", "包容蒙昧,吉。接纳妇人,吉。孩子能自立,家庭就不再受困。", "不要娶这个女子,她见了财礼就失了自身。无利可图。", "困于蒙昧,憾恨。", "童蒙,吉。", "打击蒙昧。不利于做强盗,利于抵御强盗。"], + ["有所等待,有诚信。光辉亨通,守正吉。利于涉大河。", "在郊野等待,利于用恒常的方法,无灾。", "在沙滩等待,小有议论,最终吉。", "在泥中等待,招来贼寇。", "在血中等待,从洞穴里出来。", "在酒食中等待,守正吉。", "进入洞穴,有不请自来的三位客人;尊敬他们,最终吉。"], + ["有诚信,在窒塞中警惕,中正则吉,最终凶。利于见大人,不利于涉大河。", "不永久纠缠事务,小有议论,最终吉。", "败于讼事,回家逃避。邑人三百户,无灾。", "食用旧德,守正有危,最终吉。或跟从王事,没有成功。", "不能胜诉,仍复归于常理,改变态度,安静守正则吉。", "讼事,元吉。", "或赐给大带,一天之内被剥夺三次。"], + ["贞正。大人吉,无灾。兵众,正而不邪才可用。", "出兵要有纪律;否则,凶。", "在队伍中,无灾,王三次赐命。", "师或载尸而还,凶。", "师左次而退,无灾。", "田里有禽,利于执言,无灾。长子帅师,弟子载尸,贞凶。", "大君有命,开国承家。小人不可重用。"], + ["吉。原筮,元永贞,无灾。不安宁的人前来,后夫凶。", "有诚信,比之无灾。有诚信充满瓦缶,终来有别的吉。", "比之从内,贞吉。", "比之匪人。", "在外相比,贞吉。", "显比。王用三驱,失前禽。邑人不诫,吉。", "比之无首,凶。"], + ["亨通。密云不雨,自我西郊。", "复归于自己的道路,何其咎?吉。", "牵复,吉。", "舆说辐。夫妻反目。", "有孚,血去惕出,无灾。", "有孚挛如,富以其邻。", "既雨既处,尚德载。妇贞厉。月几望,君子征凶。"], + ["踩踏老虎尾巴,不咬人,亨通。", "素履往,无灾。", "履道坦坦,幽人贞吉。", "眇能视,跛能履,履虎尾,咥人,凶。武人为于大君。", "履虎尾,愬愬,终吉。", "夬履,贞厉。", "视履考祥,其旋元吉。"], + ["小往大来,吉,亨通。", "拔茅连根,以其类,征吉。", "包荒,用冯河,不遐遗。朋亡,得尚于中行。", "无平不陂,无往不复。艰贞无灾。勿恤其孚,于食有福。", "翩翩,不富以其邻,不戒以孚。", "帝乙归妹,以祉元吉。", "城复于隍,勿用师。自邑告命,贞吝。"], + ["否之匪人,不利于君子守正。大的往,小的来。", "拔茅连根,以其类,守正吉,亨通。", "包容奉承。小人吉,大人否塞。亨通。", "包藏羞辱。", "有天命,无灾。同类依附而得福。", "休止否塞,大人吉。心中念着将亡将亡,才能系于苞桑。", "倾覆否塞。先否塞,后喜悦。"], + ["同人于野,亨通。利于涉大河,利于君子守正。", "同人于门,无灾。", "同人于宗,吝。", "伏戎于莽,升其高陵,三年不兴。", "乘其墉,弗克攻,吉。", "同人,先号咷而后笑。大师克相遇。", "同人于郊,无悔。"], + ["元亨。", "无交害,匪咎,艰则无灾。", "大车以载,有攸往,无灾。", "公用亨于天子。小人弗克。", "匪其彭,无灾。", "厥孚交如,威如,吉。", "自天佑之,吉无不利。"], + ["亨通。君子有终。", "谦谦君子,用涉大川,吉。", "鸣谦,贞吉。", "劳谦,君子有终,吉。", "无不利,撝谦。", "不富以其邻,利用侵伐,无不利。", "鸣谦,利用行师,征邑国。"], + ["利于建侯行师。", "鸣豫,凶。", "介于石,不终日,贞吉。", "盱豫,悔。迟则有悔。", "由豫,大有得。勿疑,朋盍簪。", "贞疾,恒不死。", "冥豫,成有渝,无灾。"], + ["元亨,利贞,无灾。", "官有渝,贞吉。出门交有功。", "系小子,失丈夫。", "系丈夫,失小子。随有求得,利居贞。", "随有获,贞凶。有孚在道,以明,何咎。", "孚于嘉,吉。", "拘系之,乃从维之。王用亨于西山。"], + ["元亨,利涉大川。先甲三日,后甲三日。", "干父之蛊,有子,考无咎。厉,终吉。", "干母之蛊,不可贞。", "干父之蛊,小有悔,无大咎。", "裕父之蛊,往见吝。", "干父之蛊,用誉。", "不事王侯,高尚其事。"], + ["元亨,利贞。至于八月有凶。", "咸临,贞吉。", "咸临,吉,无不利。", "甘临,无攸利。既忧之,无灾。", "至临,无灾。", "知临,大君之宜,吉。", "敦临,吉,无灾。"], + ["盥而不荐,有孚颙若。", "童观,小人无咎,君子吝。", "窥观,利女贞。", "观我生,进退。", "观国之光,利用宾于王。", "观我生,君子无咎。", "观其生,君子无咎。"], + ["亨通。利用狱。", "屦校灭趾,无灾。", "噬肤灭鼻,无灾。", "噬腊肉,遇毒。小吝,无灾。", "噬干胏,得金矢。利艰贞,吉。", "噬干肉,得黄金。贞厉,无灾。", "何校灭耳,凶。"], + ["亨通。小利有攸往。", "贲其趾,舍车而徒。", "贲其须。", "贲如濡如,永贞吉。", "贲如皤如,白马翰如。匪寇婚媾。", "贲于丘园,束帛戋戋。吝,终吉。", "白贲,无灾。"], + ["不利于有所前往。", "剥床以足,蔑贞,凶。", "剥床以辨,蔑贞,凶。", "剥之,无灾。", "剥床以肤,凶。", "贯鱼,以宫人宠,无不利。", "硕果不食。君子得舆,小人剥庐。"], + ["亨通。出入没有疾病,朋友来也无灾。一来一回按那条路走,七天会回复。利于有所前往。", "回复得还不远,没有大的悔恨,大为吉祥。", "美好地回复,吉。", "频繁回复,有危难,无灾。", "走在行列中间,独自回复。", "敦厚地回复,没有悔恨。", "迷路却不回复,凶,有灾祸。用此出兵,终有大败,连累国君,凶;到十年还不能出征。"], + ["元亨,利贞。其匪正有眚,不利有攸往。", "无妄,往吉。", "不耕获,不菑畲,则利有攸往。", "无妄之灾。或系之牛,行人之得,邑人之灾。", "可贞,无灾。", "无妄之疾,勿药有喜。", "无妄,行有眚,无攸利。"], + ["利贞。不家食,吉。利涉大川。", "有厉,利已。", "舆说輹。", "良马逐,利艰贞。日闲舆卫,利有攸往。", "童牛之牿,元吉。", "豮豕之牙,吉。", "何天之衢,亨。"], + ["贞吉。观颐,自求口实。", "舍尔灵龟,观我朵颐,凶。", "颠颐,拂经,于丘颐,征凶。", "拂颐,贞凶。十年勿用,无攸利。", "颠颐,吉。虎视眈眈,其欲逐逐,无灾。", "拂经,居贞吉,不可涉大川。", "由颐,厉吉,利涉大川。"], + ["栋桡。利有攸往,亨。", "藉用白茅,无灾。", "枯杨生稊,老夫得其女妻,无不利。", "栋桡,凶。", "栋隆,吉。有它吝。", "枯杨生华,老妇得其士夫,无咎无誉。", "过涉灭顶,凶,无灾。"], + ["有孚,维心亨,行有尚。", "习坎,入于坎窞,凶。", "坎有险,求小得。", "来之坎坎,险且枕,入于坎窞,勿用。", "樽酒簋贰,用缶,纳约自牖,终无灾。", "坎不盈,祗既平,无灾。", "系用徽纆,置于丛棘,三岁不得,凶。"], + ["利贞,亨。畜牝牛,吉。", "履错然,敬之,无灾。", "黄离,元吉。", "日昃之离,不鼓缶而歌,则大耋之嗟,凶。", "突如其来如,焚如,死如,弃如。", "出涕沱若,戚嗟若,吉。", "王用出征,有嘉折首,获匪其丑,无灾。"], + ["亨通。利贞。取女吉。", "咸其拇。", "咸其腓,凶。居吉。", "咸其股,执其随,往吝。", "贞吉,悔亡。憧憧往来,朋从尔思。", "咸其脢,无悔。", "咸其辅颊舌。"], + ["亨通。无灾。利于守正。利于有所前往。", "深求恒久,守正则凶,无所利。", "悔恨消失。", "不能恒久其德,或许会承受羞辱,守正有憾。", "田里没有禽兽。", "恒久其德,守正。妇人吉,男子凶。", "振动不安于恒,凶。"], + ["亨通。小利于守正。", "遁走只剩尾巴,有危,不要有所前往。", "用黄牛皮捆住,没有人能解脱。", "被牵绊着退避,有疾病和危难。畜养臣妾,吉。", "喜好退避,君子吉,小人否塞。", "嘉美地退避,守正吉。", "充裕地退避,没有不利。"], + ["利于守正。", "壮在脚趾,出征凶,有诚信。", "贞吉。", "小人用壮,君子用罔,贞厉。公羊触藩,缠住了角。", "贞吉,悔恨消失。藩篱没被破坏,壮在大车的辐上。", "在田里丧失羊,无悔。", "公羊触藩,不能退不能进,无攸利。艰难则吉。"], + ["康侯用锡马蕃庶,白天三次接见。", "晋如摧如,贞吉。罔孚,裕无灾。", "晋如愁如,贞吉。受兹介福,于其王母。", "众允,悔亡。", "晋如鼫鼠,贞厉。", "悔亡,失得勿恤。往吉,无不利。", "晋其角,维用伐邑,厉吉,无灾,贞吝。"], + ["利于艰难中守正。", "明夷于飞,垂其翼。君子于行,三日不食。有攸往,主人有言。", "明夷,夷于左股,用拯马壮,吉。", "明夷于南狩,得其大首,不可疾贞。", "入于左腹,获明夷之心,于出门庭。", "箕子之明夷,利贞。", "不明晦。初登于天,后入于地。"], + ["利于女子守正。", "闲有家,悔亡。", "无攸遂,在中馈,贞吉。", "家人嗃嗃,悔厉吉;妇子嘻嘻,终吝。", "富家,大吉。", "王假有家,勿恤,吉。", "有孚威如,终吉。"], + ["小事吉。", "悔亡。丧马勿逐,自复。见恶人,无灾。", "遇主于巷,无灾。", "见舆曳,其牛掣,其人天且劓。无初有终。", "睽孤,遇元夫,交孚,厉无灾。", "悔亡。厥宗噬肤,往何咎。", "睽孤,见豕负涂,载鬼一车。先张之弧,后说之弧。匪寇婚媾。往遇雨则吉。"], + ["利西南,不利东北。利见大人。贞吉。", "往蹇,来誉。", "王臣蹇蹇,匪躬之故。", "往蹇,来反。", "往蹇,来连。", "大蹇,朋来。", "往蹇,来硕,吉。利见大人。"], + ["利西南。无所往,其来复吉。有攸往,夙吉。", "无灾。", "田获三狐,得黄矢,贞吉。", "负且乘,致寇至,贞吝。", "解而拇,朋至斯孚。", "君子维有解,吉。有孚于小人。", "公用射隼于高墉之上,获之,无不利。"], + ["有孚,元吉,无灾,可贞,利有攸往。曷之用?二簋可用享。", "已事遄往,无灾。酌损之。", "利贞。征凶。弗损,益之。", "三人行则损一人,一人行则得其友。", "损其疾,使遄有喜,无灾。", "或益之十朋之龟,弗克违,元吉。", "弗损,益之,无灾。贞吉。利有攸往,得臣无家。"], + ["利有攸往。利涉大川。", "利用为大作,元吉,无灾。", "或益之十朋之龟,弗克违。永贞吉。王用享于帝,吉。", "益之用凶事,无灾。有孚中行,告公用圭。", "中行,告公从,利用为依迁国。", "有孚惠心,勿问元吉。有孚惠我德。", "莫益之,或击之,立心勿恒,凶。"], + ["扬于王庭。孚号有厉。告自邑,不利即戎,利有攸往。", "壮于前趾,往不胜为咎。", "惕号,莫夜有戎,勿恤。", "壮于頄,有凶。君子夬夬,独行遇雨,若濡有愠,无灾。", "臀无肤,其行次且。牵羊悔亡,闻言不信。", "苋陆夬夬,中行无灾。", "无号,终有凶。"], + ["女壮,勿用取女。", "系于金柅,贞吉。有攸往,见凶。羸豕孚蹢躅。", "包有鱼,无灾,不利宾。", "臀无肤,其行次且,厉,无大咎。", "包无鱼,起凶。", "以杞包瓜,含章,有陨自天。", "姤其角,吝,无灾。"], + ["亨通。王假有庙。利见大人,亨,利贞。用大牲吉。利有攸往。", "有孚不终,乃乱乃萃。若号,一握为笑,勿恤,往无灾。", "引吉,无灾。孚乃利用禴。", "萃如嗟如,无攸利。往无灾,小吝。", "大吉,无灾。", "萃有位,无灾。匪孚,元永贞,悔亡。", "赍咨涕洟,无灾。"], + ["元亨。用见大人,勿恤。南征吉。", "允升,大吉。", "孚乃利用禴,无灾。", "升虚邑。", "王用亨于岐山,吉,无灾。", "贞吉,升阶。", "冥升,利于不息之贞。"], + ["亨通。贞,大人吉,无灾。有言不信。", "臀困于株木,入于幽谷,三岁不觌。", "困于酒食,朱绂方来,利用享祀。征凶,无灾。", "困于石,据于蒺藜。入于其宫,不见其妻,凶。", "来徐徐,困于金车,吝,有终。", "劓刖,困于赤绂。乃徐有说,利用祭祀。", "困于葛藟,于臲卼。曰动悔有悔,征吉。"], + ["改邑不改井,无丧无得。往来井井。汔至,亦未繘井,羸其瓶,凶。", "井泥不食,旧井无禽。", "井谷射鲋,瓮敝漏。", "井渫不食,为我心恻。可用汲,王明,并受其福。", "井甃,无灾。", "井冽,寒泉食。", "井收勿幕,有孚元吉。"], + ["己日乃孚。元亨,利贞,悔亡。", "巩用黄牛之革。", "己日乃革之,征吉,无灾。", "征凶,贞厉。革言三就,有孚。", "悔亡。有孚改命,吉。", "大人虎变,未占有孚。", "君子豹变,小人革面。征凶,居贞吉。"], + ["元吉,亨通。", "鼎颠趾,利出否。得妾以其子,无灾。", "鼎有实。我仇有疾,不我能即,吉。", "鼎耳革,其行塞,雉膏不食。方雨亏悔,终吉。", "鼎折足,覆公餗,其形渥,凶。", "鼎黄耳金铉,利贞。", "鼎玉铉,大吉,无不利。"], + ["亨通。震来虩虩,笑言哑哑。震惊百里,不丧匕鬯。", "震来虩虩,后笑言哑哑,吉。", "震来厉,亿丧贝。跻于九陵,勿逐,七日得。", "震苏苏,震行无眚。", "震遂泥。", "震往来厉,亿无丧,有事。", "震索索,视矍矍,征凶。震不于其躬,于其邻,无灾。婚媾有言。"], + ["艮其背,不获其身;行其庭,不见其人,无灾。", "艮其趾,无灾,利永贞。", "艮其腓,不拯其随,其心不快。", "艮其限,列其夤,厉薰心。", "艮其身,无灾。", "艮其辅,言有序,悔亡。", "敦艮,吉。"], + ["女归吉。利贞。", "鸿渐于干,小子厉,有言,无灾。", "鸿渐于磐,饮食衎衎,吉。", "鸿渐于陆,夫征不复,妇孕不育,凶。利御寇。", "鸿渐于木,或得其桷,无灾。", "鸿渐于陵,妇三岁不孕,终莫之胜,吉。", "鸿渐于陆,其羽可用为仪,吉。"], + ["征凶,无攸利。", "归妹以娣,跛能履,征吉。", "眇能视,利幽人之贞。", "归妹以须,反归以娣。", "归妹愆期,迟归有时。", "帝乙归妹,其君之袂不如其娣之袂良。月几望,吉。", "女承筐无实,士刲羊无血,无攸利。"], + ["亨通。王假之。勿忧,宜日中。", "遇其配主,虽旬无灾,往有尚。", "丰其蔀,日中见斗。往得疑疾,有孚发若,吉。", "丰其沛,日中见沫。折其右肱,无灾。", "丰其蔀,日中见斗。遇其夷主,吉。", "来章,有庆誉,吉。", "丰其屋,蔀其家,窥其户,阒其无人,三岁不觌,凶。"], + ["小亨。旅贞吉。", "旅琐琐,斯其所取灾。", "旅即次,怀其资,得童仆贞。", "旅焚其次,丧其童仆,贞厉。", "旅于处,得其资斧,我心不快。", "射雉,一矢亡,终以誉命。", "鸟焚其巢,旅人先笑后号咷。丧牛于易,凶。"], + ["小亨。利有攸往。利见大人。", "进退,利武人之贞。", "巽在床下,用史巫纷若,吉,无灾。", "频巽,吝。", "悔亡,田获三品。", "贞吉,悔亡,无不利。无初有终。先庚三日,后庚三日,吉。", "巽在床下,丧其资斧,贞凶。"], + ["亨通。利贞。", "和兑,吉。", "孚兑,吉,悔亡。", "来兑,凶。", "商兑未宁,介疾有喜。", "孚于剥,有厉。", "引兑。"], + ["亨通。王假有庙。利涉大川,利贞。", "用拯马壮,吉。", "涣奔其机,悔亡。", "涣其躬,无悔。", "涣其群,元吉。涣有丘,匪夷所思。", "涣汗其大号,涣王居,无灾。", "涣其血,去逖出,无灾。"], + ["亨通。苦节不可贞。", "不出户庭,无灾。", "不出门庭,凶。", "不节若,则嗟若,无灾。", "安节,亨。", "甘节,吉。往有尚。", "苦节,贞凶,悔亡。"], + ["豚鱼吉。利涉大川,利贞。", "虞吉,有它不燕。", "鸣鹤在阴,其子和之。我有好爵,吾与尔靡之。", "得敌,或鼓或罢,或泣或歌。", "月几望,马匹亡,无灾。", "有孚挛如,无灾。", "翰音登于天,贞凶。"], + ["亨通。利贞。可小事,不可大事。飞鸟遗之音,不宜上,宜下,大吉。", "飞鸟以凶。", "过其祖,遇其妣。不及其君,遇其臣,无灾。", "弗过防之,从或戕之,凶。", "无灾。弗过遇之。往厉必戒,勿用永贞。", "密云不雨,自我西郊。公弋取彼在穴。", "弗遇过之,飞鸟离之,凶。是谓灾眚。"], + ["亨通。小利贞。初吉终乱。", "曳其轮,濡其尾,无灾。", "妇丧其茀,勿逐,七日得。", "高宗伐鬼方,三年克之,小人勿用。", "繻有衣袽,终日戒。", "东邻杀牛,不如西邻之禴祭,实受其福。", "濡其首,厉。"], + ["亨通。小狐汔济,濡其尾,无攸利。", "濡其尾,吝。", "曳其轮,贞吉。", "未济,征凶,利涉大川。", "贞吉,悔亡。震用伐鬼方,三年有赏于大国。", "贞吉,无悔。君子之光,有孚,吉。", "有孚于饮酒,无灾。濡其首,有孚失是。"], +]; diff --git a/content/raw/zhouyi-wikisource-jing.json b/content/raw/zhouyi-wikisource-jing.json new file mode 100644 index 0000000..0488feb --- /dev/null +++ b/content/raw/zhouyi-wikisource-jing.json @@ -0,0 +1,1602 @@ +[ + { + "kingWenNumber": 1, + "wikisourceTitle": "乾", + "sourcePage": "https://zh.wikisource.org/wiki/周易/乾", + "upperTrigram": "QIAN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "元亨。利贞。", + "lineTextsBottomUp": [ + "初九:潜龙勿用。", + "九二:见龙在田,利见大人。", + "九三:君子终日乾乾,夕惕若;厉,无咎。", + "九四:或跃在渊,无咎。", + "九五:飞龙在天,利见大人。", + "上九:亢龙,有悔。" + ], + "specialUsageText": "用九:见群龙无首,吉。" + }, + { + "kingWenNumber": 2, + "wikisourceTitle": "坤", + "sourcePage": "https://zh.wikisource.org/wiki/周易/坤", + "upperTrigram": "KUN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "元亨。利牝马之贞。君子有攸往,先迷后得主。利西南得朋,东北丧朋。安贞,吉。", + "lineTextsBottomUp": [ + "初六:履霜,坚冰至。", + "六二:直方大,不习无不利。", + "六三:含章,可贞。或从王事,无成有终。", + "六四:括囊,无咎无誉。", + "六五:黄裳,元吉。", + "上六:龙战于野,其血玄黄。" + ], + "specialUsageText": "用六:利永贞。" + }, + { + "kingWenNumber": 3, + "wikisourceTitle": "屯", + "sourcePage": "https://zh.wikisource.org/wiki/周易/屯", + "upperTrigram": "KAN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "元亨,利贞。勿用有攸往,利建侯。", + "lineTextsBottomUp": [ + "初九:磐桓,利居贞,利建侯。", + "六二:屯如邅如,乘马班如,匪寇婚媾,女子贞不字,十年乃字。", + "六三:即鹿无虞,惟入于林中,君子几不如舍,往吝。", + "六四:乘马班如,求婚媾,往,吉无不利。", + "九五:屯其膏;小贞吉,大贞凶。", + "上六:乘马班如,泣血涟如。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 4, + "wikisourceTitle": "蒙", + "sourcePage": "https://zh.wikisource.org/wiki/周易/蒙", + "upperTrigram": "GEN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "亨。匪我求童蒙,童蒙求我。初筮告,再三渎,渎则不告。利贞。", + "lineTextsBottomUp": [ + "初六:发蒙,利用刑人,用说桎梏,以往吝。", + "九二:包蒙吉,纳妇吉,子克家。", + "六三:勿用取女,见金夫,不有躬,无攸利。", + "六四:困蒙,吝。", + "六五:童蒙,吉。", + "上九:击蒙,不利为寇,利御寇。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 5, + "wikisourceTitle": "需", + "sourcePage": "https://zh.wikisource.org/wiki/周易/需", + "upperTrigram": "KAN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "有孚,光亨。贞吉,利涉大川。", + "lineTextsBottomUp": [ + "初九:需于郊,利用恒,无咎。", + "九二:需于沙,小有言,终吉。", + "九三:需于泥,致寇至。", + "六四:需于血,出自穴。", + "九五:需于酒食,贞吉。", + "上六:入于穴,有不速之客三人来,敬之终吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 6, + "wikisourceTitle": "訟", + "sourcePage": "https://zh.wikisource.org/wiki/周易/訟", + "upperTrigram": "QIAN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "有孚,窒,惕,中吉,终凶。利见大人,不利涉大川。", + "lineTextsBottomUp": [ + "初六:不永所事,小有言,终吉。", + "九二:不克讼,归而逋,其邑人三百户无眚。", + "六三:食旧德,贞厉,终吉。或从王事,无成。", + "九四:不克讼,复即命渝,安贞吉。", + "九五:讼,元吉。", + "上九:或锡之鞶带,终朝三褫之。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 7, + "wikisourceTitle": "師", + "sourcePage": "https://zh.wikisource.org/wiki/周易/師", + "upperTrigram": "KUN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "贞丈人吉,无咎。", + "lineTextsBottomUp": [ + "初六:师出以律,否臧,凶。", + "九二:在师中吉,无咎;王三锡命。", + "六三:师或舆尸,凶。", + "六四:师左次,无咎。", + "六五:田有禽,利执言,无咎。长子帅师,弟子舆尸,贞凶。", + "上六:大君有命,开国承家,小人勿用。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 8, + "wikisourceTitle": "比", + "sourcePage": "https://zh.wikisource.org/wiki/周易/比", + "upperTrigram": "KAN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "吉。原筮元永贞,无咎。不宁方来,后夫凶。", + "lineTextsBottomUp": [ + "初六:有孚,比之,无咎。有孚盈缶,终来有它,吉。", + "六二:比之自内,贞吉。", + "六三:比之匪人。", + "六四:外比之,贞吉。", + "九五:显比。王用三驱,失前禽,邑人不诫,吉。", + "上六:比之无首,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 9, + "wikisourceTitle": "小畜", + "sourcePage": "https://zh.wikisource.org/wiki/周易/小畜", + "upperTrigram": "XUN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "亨。密云不雨,自我西郊。", + "lineTextsBottomUp": [ + "初九:复自道,何其咎,吉。", + "九二:牵复,吉。", + "九三:舆说辐,夫妻反目。", + "六四:有孚,血去惕出,无咎。", + "九五:有孚挛如,富以其邻。", + "上九:既雨既处,尚德载,妇贞厉,月几望,君子征凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 10, + "wikisourceTitle": "履", + "sourcePage": "https://zh.wikisource.org/wiki/周易/履", + "upperTrigram": "QIAN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "履虎尾,不咥人,亨。", + "lineTextsBottomUp": [ + "初九:素履,往无咎。", + "九二:履道坦坦,幽人贞吉。", + "六三:眇能视,跛能履,履虎尾,咥人,凶。武人为于大君。", + "九四:履虎尾,愬愬终吉。", + "九五:夬履,贞厉。", + "上九:视履考祥,其旋元吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 11, + "wikisourceTitle": "泰", + "sourcePage": "https://zh.wikisource.org/wiki/周易/泰", + "upperTrigram": "KUN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "小往大来,吉亨。", + "lineTextsBottomUp": [ + "初九:拔茅茹以其汇,征吉。", + "九二:包荒。用冯河,不遐遗;朋亡。得尚于中行。", + "九三:无平不陂,无往不复,艰贞无咎。勿恤其孚,于食有福。", + "六四:翩翩,不富以其邻;不戒以孚。", + "六五:帝乙归妹,以祉,元吉。", + "上六:城复于隍,勿用师,自邑告命,贞吝。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 12, + "wikisourceTitle": "否", + "sourcePage": "https://zh.wikisource.org/wiki/周易/否", + "upperTrigram": "QIAN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "否之匪人,不利君子贞,大往小来。", + "lineTextsBottomUp": [ + "初六:拔茅茹以其汇,贞吉。亨。", + "六二:包承,小人吉,大人否。亨。", + "六三:包羞。", + "九四:有命,无咎,畴离祉。", + "九五:休否,大人吉。其亡其亡,系于苞桑。", + "上九:倾否,先否后喜。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 13, + "wikisourceTitle": "同人", + "sourcePage": "https://zh.wikisource.org/wiki/周易/同人", + "upperTrigram": "QIAN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "同人于野,亨。利涉大川,利君子贞。", + "lineTextsBottomUp": [ + "初九:同人于门,无咎。", + "六二:同人于宗,吝。", + "九三:伏戎于莽,升其高陵,三岁不兴。", + "九四:乘其墉,弗克,攻吉。", + "九五:同人,先号啕而后笑。大师克相遇。", + "上九:同人于郊,无悔。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 14, + "wikisourceTitle": "大有", + "sourcePage": "https://zh.wikisource.org/wiki/周易/大有", + "upperTrigram": "LI", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "元亨。", + "lineTextsBottomUp": [ + "初九:无交害,匪咎,艰则无咎。", + "九二:大车以载,有攸往,无咎。", + "九三:公用亨于天子,小人弗克。", + "九四:匪其彭,无咎。", + "六五:厥孚交如,威如;吉。", + "上九:自天佑之,吉无不利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 15, + "wikisourceTitle": "謙", + "sourcePage": "https://zh.wikisource.org/wiki/周易/謙", + "upperTrigram": "KUN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨,君子有终。", + "lineTextsBottomUp": [ + "初六:谦谦君子,用涉大川,吉。", + "六二:鸣谦,贞吉。", + "九三:劳谦君子,有终吉。", + "六四:无不利,㧑谦。", + "六五:不富,以其邻,利用侵伐,无不利。", + "上六:鸣谦,利用行师,征邑国。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 16, + "wikisourceTitle": "豫", + "sourcePage": "https://zh.wikisource.org/wiki/周易/豫", + "upperTrigram": "ZHEN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "利建侯行师。", + "lineTextsBottomUp": [ + "初六:鸣豫,凶。", + "六二:介于石,不终日,贞吉。", + "六三:盱豫,悔。迟有悔。", + "九四:由豫,大有得。勿疑。朋盍簪。", + "六五:贞疾,恒不死。", + "上六:冥豫,成有渝,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 17, + "wikisourceTitle": "隨", + "sourcePage": "https://zh.wikisource.org/wiki/周易/隨", + "upperTrigram": "DUI", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "元亨。利贞。无咎。", + "lineTextsBottomUp": [ + "初九:官有渝,贞吉。出门交有功。", + "六二:系小子,失丈夫。", + "六三:系丈夫,失小子。随,有求得利,居贞。", + "九四:随有获,贞凶。有孚在道,以明,何咎。", + "九五:孚于嘉,吉。", + "上六:拘系之,乃从维之。王用亨于西山。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 18, + "wikisourceTitle": "蠱", + "sourcePage": "https://zh.wikisource.org/wiki/周易/蠱", + "upperTrigram": "GEN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "元亨。利涉大川。先甲三日,后甲三日。", + "lineTextsBottomUp": [ + "初六:干父之蛊,有子考,无咎,厉终吉。", + "九二:干母之蛊,不可贞。", + "九三:干父之蛊,小有悔,无大咎。", + "六四:裕父之蛊,往见吝。", + "六五:干父之蛊,用誉。", + "上九:不事王侯,高尚其事。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 19, + "wikisourceTitle": "臨", + "sourcePage": "https://zh.wikisource.org/wiki/周易/臨", + "upperTrigram": "KUN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "元亨。利贞。至于八月有凶。", + "lineTextsBottomUp": [ + "初九:咸临,贞吉。", + "九二:咸临,吉无不利。", + "六三:甘临,无攸利。既忧之,无咎。", + "六四:至临,无咎。", + "六五:知临,大君之宜,吉。", + "上六:敦临,吉无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 20, + "wikisourceTitle": "觀", + "sourcePage": "https://zh.wikisource.org/wiki/周易/觀", + "upperTrigram": "XUN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "盥而不荐,有孚颙若。", + "lineTextsBottomUp": [ + "初六:童观,小人无咎,君子吝。", + "六二:窥观,利女贞。", + "六三:观我生,进退。", + "六四:观国之光,利用宾于王。", + "九五:观我生,君子无咎。", + "上九:观其生,君子无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 21, + "wikisourceTitle": "噬嗑", + "sourcePage": "https://zh.wikisource.org/wiki/周易/噬嗑", + "upperTrigram": "LI", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "亨。利用狱。", + "lineTextsBottomUp": [ + "初九:屦校灭趾,无咎。", + "六二:噬肤灭鼻,无咎。", + "六三:噬腊肉,遇毒;小吝,无咎。", + "九四:噬干胏,得金矢,利艰贞,吉。", + "六五:噬干肉,得黄金,贞厉,无咎。", + "上九:何校灭耳,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 22, + "wikisourceTitle": "賁", + "sourcePage": "https://zh.wikisource.org/wiki/周易/賁", + "upperTrigram": "GEN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "亨。小利有攸往。", + "lineTextsBottomUp": [ + "初九:贲其趾,舍车而徒。", + "六二:贲其须。", + "九三:贲如濡如,永贞吉。", + "六四:贲如皤如,白马翰如,匪寇婚媾。", + "六五:贲于丘园,束帛戋戋,吝,终吉。", + "上九:白贲,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 23, + "wikisourceTitle": "剝", + "sourcePage": "https://zh.wikisource.org/wiki/周易/剝", + "upperTrigram": "GEN", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "不利。有攸往。", + "lineTextsBottomUp": [ + "初六:剥床以足,蔑贞凶。", + "六二:剥床以辨,蔑贞凶。", + "六三:剥之,无咎。", + "六四:剥床以肤,凶。", + "六五:贯鱼,以宫人宠,无不利。", + "上九:硕果不食,君子得舆,小人剥庐。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 24, + "wikisourceTitle": "復", + "sourcePage": "https://zh.wikisource.org/wiki/周易/復", + "upperTrigram": "KUN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨。出入无疾,朋来无咎。反复其道,七日来复,利有攸往。", + "lineTextsBottomUp": [ + "初九:不复远,无袛悔,元吉。", + "六二:休复,吉。", + "六三:频复,厉无咎。", + "六四:中行独复。", + "六五:敦复,无悔。", + "上六:迷复,凶,有灾眚。用行师,终有大败,以其国君,凶;至于十年,不克征。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 25, + "wikisourceTitle": "无妄", + "sourcePage": "https://zh.wikisource.org/wiki/周易/无妄", + "upperTrigram": "QIAN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "无妄:元亨。利贞。其匪正有眚,不利有攸往。", + "lineTextsBottomUp": [ + "初九:无妄,往吉。", + "六二:不耕获,不菑畬,则利有攸往。", + "六三:无妄之灾,或系之牛,行人之得,邑人之灾。", + "九四:可贞,无咎。", + "九五:无妄之疾,勿药有喜。", + "上九:无妄,行有眚,无攸利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 26, + "wikisourceTitle": "大畜", + "sourcePage": "https://zh.wikisource.org/wiki/周易/大畜", + "upperTrigram": "GEN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "利贞,不家食吉,利涉大川。", + "lineTextsBottomUp": [ + "初九:有厉利已。", + "九二:舆说輹。", + "九三:良马逐,利艰贞。曰闲舆卫,利有攸往。", + "六四:童牛之牿,元吉。", + "六五:豮豕之牙,吉。", + "上九:何天之衢,亨。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 27, + "wikisourceTitle": "頤", + "sourcePage": "https://zh.wikisource.org/wiki/周易/頤", + "upperTrigram": "GEN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "贞吉。观颐,自求口实。", + "lineTextsBottomUp": [ + "初九:舍尔灵龟,观我朵颐,凶。", + "六二:颠颐,拂经,于丘颐,征凶。", + "六三:拂颐,贞凶,十年勿用,无攸利。", + "六四:颠颐吉,虎视眈眈,其欲逐逐,无咎。", + "六五:拂经,居贞吉,不可涉大川。", + "上九:由颐,厉吉,利涉大川。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 28, + "wikisourceTitle": "大過", + "sourcePage": "https://zh.wikisource.org/wiki/周易/大過", + "upperTrigram": "DUI", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "栋桡,利有攸往,亨。", + "lineTextsBottomUp": [ + "初六:藉用白茅,无咎。", + "九二:枯杨生稊,老夫得其女妻,无不利。", + "九三:栋桡,凶。", + "九四:栋隆,吉。有它吝。", + "九五:枯杨生华,老妇得其士夫,无咎无誉。", + "上六:过涉灭顶,凶,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 29, + "wikisourceTitle": "坎", + "sourcePage": "https://zh.wikisource.org/wiki/周易/坎", + "upperTrigram": "KAN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "有孚,维心亨。行有尚。", + "lineTextsBottomUp": [ + "初六:习坎,入于坎窞,凶。", + "九二:坎有险,求小得。", + "六三:来之坎坎,险且枕,入于坎窞,勿用。", + "六四:樽酒簋贰,用缶,纳约自牖,终无咎。", + "九五:坎不盈,祗既平,无咎。", + "上六:系用徽𬙊,寘于丛棘,三岁不得,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 30, + "wikisourceTitle": "離", + "sourcePage": "https://zh.wikisource.org/wiki/周易/離", + "upperTrigram": "LI", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "利贞。亨。畜牝牛,吉。", + "lineTextsBottomUp": [ + "初九:履错然,敬之无咎。", + "六二:黄离,元吉。", + "九三:日昃之离,不鼓缶而歌,则大耋之嗟,凶。", + "九四:突如其来如,焚如,死如,弃如。", + "六五:出涕沱若,戚嗟若,吉。", + "上九:王用出征,有嘉折首,获匪其丑,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 31, + "wikisourceTitle": "咸", + "sourcePage": "https://zh.wikisource.org/wiki/周易/咸", + "upperTrigram": "DUI", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨。利贞。取女吉。", + "lineTextsBottomUp": [ + "初六:咸其拇。", + "六二:咸其腓,凶,居吉。", + "九三:咸其股,执其随,往吝。", + "九四:贞吉悔亡,憧憧往来,朋从尔思。", + "九五:咸其脢,无悔。", + "上六:咸其辅,颊,舌。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 32, + "wikisourceTitle": "恆", + "sourcePage": "https://zh.wikisource.org/wiki/周易/恆", + "upperTrigram": "ZHEN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨,无咎。利贞,利有攸往。", + "lineTextsBottomUp": [ + "初六:浚恒,贞凶,无攸利。", + "九二:悔亡。", + "九三:不恒其德,或承之羞,贞吝。", + "九四:田无禽。", + "六五:恒其德,贞,妇人吉,夫子凶。", + "上六:振恒,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 33, + "wikisourceTitle": "遯", + "sourcePage": "https://zh.wikisource.org/wiki/周易/遯", + "upperTrigram": "QIAN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "亨。小利贞。", + "lineTextsBottomUp": [ + "初六:遁尾,厉,勿用有攸往。", + "六二:执之用黄牛之革,莫之胜说。", + "九三:系遁,有疾厉,畜臣妾吉。", + "九四:好遁君子吉,小人否。", + "九五:嘉遁,贞吉。", + "上九:肥遁,无不利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 34, + "wikisourceTitle": "大壯", + "sourcePage": "https://zh.wikisource.org/wiki/周易/大壯", + "upperTrigram": "ZHEN", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "利贞。", + "lineTextsBottomUp": [ + "初九:壮于趾,征凶,有孚。", + "九二:贞吉。", + "九三:小人用壮,君子用罔,贞厉。羝羊触藩,羸其角。", + "九四:贞吉悔亡,藩决不羸,壮于大舆之輹。", + "六五:丧羊于易,无悔。", + "上六:羝羊触藩,不能退,不能遂,无攸利,艰则吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 35, + "wikisourceTitle": "晉", + "sourcePage": "https://zh.wikisource.org/wiki/周易/晉", + "upperTrigram": "LI", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "康侯用锡马蕃庶,昼日三接。", + "lineTextsBottomUp": [ + "初六:晋如,摧如,贞吉。罔孚,裕无咎。", + "六二:晋如,愁如,贞吉。受兹介福,于其王母。", + "六三:众允,悔亡。", + "九四:晋如鼫鼠,贞厉。", + "六五:悔亡,失得勿恤,往吉无不利。", + "上九:晋其角,维用伐邑,厉吉无咎,贞吝。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 36, + "wikisourceTitle": "明夷", + "sourcePage": "https://zh.wikisource.org/wiki/周易/明夷", + "upperTrigram": "KUN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "利艰贞。", + "lineTextsBottomUp": [ + "初九:明夷于飞,垂其翼。君子于行,三日不食,有攸往,主人有言。", + "六二:明夷,夷于左股,用拯马壮,吉。", + "九三:明夷于南狩,得其大首,不可疾贞。", + "六四:入于左腹,获明夷之心,于出门庭。", + "六五:箕子之明夷,利贞。", + "上六:不明晦,初登于天,后入于地。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 37, + "wikisourceTitle": "家人", + "sourcePage": "https://zh.wikisource.org/wiki/周易/家人", + "upperTrigram": "XUN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "利女贞。", + "lineTextsBottomUp": [ + "初九:闲有家,悔亡。", + "六二:无攸遂,在中馈,贞吉。", + "九三:家人嗃嗃,悔厉吉;妇子嘻嘻,终吝。", + "六四:富家,大吉。", + "九五:王假有家,勿恤。吉。", + "上九:有孚威如,终吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 38, + "wikisourceTitle": "睽", + "sourcePage": "https://zh.wikisource.org/wiki/周易/睽", + "upperTrigram": "LI", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "小事吉。", + "lineTextsBottomUp": [ + "初九:悔亡,丧马勿逐,自复;见恶人无咎。", + "九二:遇主于巷,无咎。", + "六三:见舆曳,其牛掣,其人天且劓,无初有终。", + "九四:睽孤,遇元夫,交孚,厉无咎。", + "六五:悔亡,厥宗噬肤,往何咎。", + "上九:睽孤,见豕负涂,载鬼一车,先张之弧,后说之弧,匪寇婚媾,往遇雨则吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 39, + "wikisourceTitle": "蹇", + "sourcePage": "https://zh.wikisource.org/wiki/周易/蹇", + "upperTrigram": "KAN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "利西南,不利东北;利见大人,贞吉。", + "lineTextsBottomUp": [ + "初六:往蹇,来誉。", + "六二:王臣蹇蹇,匪躬之故。", + "九三:往蹇来反。", + "六四:往蹇来连。", + "九五:大蹇朋来。", + "上六:往蹇来硕,吉;利见大人。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 40, + "wikisourceTitle": "解", + "sourcePage": "https://zh.wikisource.org/wiki/周易/解", + "upperTrigram": "ZHEN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "利西南,无所往,其来复吉。有攸往,夙吉。", + "lineTextsBottomUp": [ + "初六:无咎。", + "九二:田获三狐,得黄矢,贞吉。", + "六三:负且乘,致寇至,贞吝。", + "九四:解而拇,朋至斯孚。", + "六五:君子维有解,吉;有孚于小人。", + "上六:公用射隼,于高墉之上,获之,无不利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 41, + "wikisourceTitle": "損", + "sourcePage": "https://zh.wikisource.org/wiki/周易/損", + "upperTrigram": "GEN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "有孚,元吉。无咎,可贞,利有攸往。曷之用?二簋可用享。", + "lineTextsBottomUp": [ + "初九:已事遄往,无咎,酌损之。", + "九二:利贞,征凶,弗损益之。", + "六三:三人行,则损一人;一人行,则得其友。", + "六四:损其疾,使遄有喜,无咎。", + "六五:或益之,十朋之龟弗克违,元吉。", + "上九:弗损益之,无咎,贞吉,利有攸往,得臣无家。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 42, + "wikisourceTitle": "益", + "sourcePage": "https://zh.wikisource.org/wiki/周易/益", + "upperTrigram": "XUN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "利有攸往。利涉大川。", + "lineTextsBottomUp": [ + "初九:利用为大作,元吉,无咎。", + "六二:或益之,十朋之龟弗克违,永贞吉。王用享于帝,吉。", + "六三:益之用凶事,无咎。有孚中行,告公用圭。", + "六四:中行,告公从。利用为依迁国。", + "九五:有孚惠心,勿问元吉。有孚惠我德。", + "上九:莫益之,或击之,立心勿恒,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 43, + "wikisourceTitle": "夬", + "sourcePage": "https://zh.wikisource.org/wiki/周易/夬", + "upperTrigram": "DUI", + "lowerTrigram": "QIAN", + "patternBottomUp": [ + "YANG", + "YANG", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "扬于王庭,孚号,有厉,告自邑,不利即戎,利有攸往。", + "lineTextsBottomUp": [ + "初九:壮于前趾,往不胜为咎。", + "九二:惕号,莫夜有戎,勿恤。", + "九三:壮于頄,有凶。君子夬夬,独行遇雨,若濡有愠,无咎。", + "九四:臀无肤,其行次且。牵羊悔亡,闻言不信。", + "九五:苋陆夬夬,中行无咎。", + "上六:无号,终有凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 44, + "wikisourceTitle": "姤", + "sourcePage": "https://zh.wikisource.org/wiki/周易/姤", + "upperTrigram": "QIAN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YANG", + "YANG" + ], + "judgmentOriginal": "女壮,勿用取女。", + "lineTextsBottomUp": [ + "初六:系于金柅,贞吉,有攸往,见凶,羸豕孚踟躅。", + "九二:包有鱼,无咎,不利宾。", + "九三:臀无肤,其行次且,厉,无大咎。", + "九四:包无鱼,起凶。", + "九五:以杞包瓜,含章,有陨自天。", + "上九:姤其角,吝,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 45, + "wikisourceTitle": "萃", + "sourcePage": "https://zh.wikisource.org/wiki/周易/萃", + "upperTrigram": "DUI", + "lowerTrigram": "KUN", + "patternBottomUp": [ + "YIN", + "YIN", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨。王假有庙,利见大人,亨。利贞。用大牲吉,利有攸往。", + "lineTextsBottomUp": [ + "初六:有孚不终,乃乱乃萃,若号一握为笑,勿恤,往无咎。", + "六二:引吉,无咎,孚乃利用禴。", + "六三:萃如,嗟如,无攸利,往无咎,小吝。", + "九四:大吉,无咎。", + "九五:萃有位,无咎。匪孚,元永贞,悔亡。", + "上六:赍咨涕洟,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 46, + "wikisourceTitle": "升", + "sourcePage": "https://zh.wikisource.org/wiki/周易/升", + "upperTrigram": "KUN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YIN", + "YIN" + ], + "judgmentOriginal": "元亨,用见大人,勿恤,南征吉。", + "lineTextsBottomUp": [ + "初六:允升,大吉。", + "九二:孚乃利用禴,无咎。", + "九三:升虚邑。", + "六四:王用亨于岐山,吉无咎。", + "六五:贞吉,升阶。", + "上六:冥升,利于不息之贞。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 47, + "wikisourceTitle": "困", + "sourcePage": "https://zh.wikisource.org/wiki/周易/困", + "upperTrigram": "DUI", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨,贞大人吉,无咎,有言不信。", + "lineTextsBottomUp": [ + "初六:臀困于株木,入于幽谷,三岁不觌。", + "九二:困于酒食,朱绂方来,利用亨祀,征凶,无咎。", + "六三:困于石,据于蒺藜,入于其宫,不见其妻,凶。", + "九四:来徐徐,困于金车,吝,有终。", + "九五:劓刖,困于赤绂,乃徐有说,利用祭祀。", + "上六:困于葛藟,于臲卼,曰动悔。有悔,征吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 48, + "wikisourceTitle": "井", + "sourcePage": "https://zh.wikisource.org/wiki/周易/井", + "upperTrigram": "KAN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "改邑不改井,无丧无得,往来井井。汔至亦未繘井。羸其瓶,凶。", + "lineTextsBottomUp": [ + "初六:井泥不食,旧井无禽。", + "九二:井谷射鲋,瓮敝漏。", + "九三:井渫不食,为我心恻,可用汲,王明,并受其福。", + "六四:井甃,无咎。", + "九五:井冽,寒泉食。", + "上六:井收勿幕,有孚元吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 49, + "wikisourceTitle": "革", + "sourcePage": "https://zh.wikisource.org/wiki/周易/革", + "upperTrigram": "DUI", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "巳日乃孚,元亨。利贞。悔亡。", + "lineTextsBottomUp": [ + "初九:巩用黄牛之革。", + "六二:巳日乃革之,征吉,无咎。", + "九三:征凶,贞厉,革言三就,有孚。", + "九四:悔亡,有孚改命,吉。", + "九五:大人虎变,未占有孚。", + "上六:君子豹变,小人革面,征凶,居贞吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 50, + "wikisourceTitle": "鼎", + "sourcePage": "https://zh.wikisource.org/wiki/周易/鼎", + "upperTrigram": "LI", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "元吉,亨。", + "lineTextsBottomUp": [ + "初六:鼎颠趾,利出否,得妾以其子,无咎。", + "九二:鼎有实,我仇有疾,不我能即,吉。", + "九三:鼎耳革,其行塞,雉膏不食,方雨亏悔,终吉。", + "九四:鼎折足,覆公𫗧,其形渥,凶。", + "六五:鼎黄耳金铉,利贞。", + "上九:鼎玉铉,大吉,无不利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 51, + "wikisourceTitle": "震", + "sourcePage": "https://zh.wikisource.org/wiki/周易/震", + "upperTrigram": "ZHEN", + "lowerTrigram": "ZHEN", + "patternBottomUp": [ + "YANG", + "YIN", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨。震来虩虩,笑言哑哑。震惊百里,不丧匕鬯。", + "lineTextsBottomUp": [ + "初九:震来虩虩,后笑言哑哑,吉。", + "六二:震来厉,亿丧贝,跻于九陵,勿逐,七日得。", + "六三:震苏苏,震行无眚。", + "九四:震遂泥。", + "六五:震往来厉,亿无丧,有事。", + "上六:震索索,视矍矍,征凶。震不于其躬,于其邻,无咎。婚媾有言。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 52, + "wikisourceTitle": "艮", + "sourcePage": "https://zh.wikisource.org/wiki/周易/艮", + "upperTrigram": "GEN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YIN", + "YANG" + ], + "judgmentOriginal": "艮其背,不获其身,行其庭,不见其人,无咎。", + "lineTextsBottomUp": [ + "初六:艮其趾,无咎,利永贞。", + "六二:艮其腓,不拯其随,其心不快。", + "九三:艮其限,列其夤,厉熏心。", + "六四:艮其身,无咎。", + "六五:艮其辅,言有序,悔亡。", + "上九:敦艮,吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 53, + "wikisourceTitle": "漸", + "sourcePage": "https://zh.wikisource.org/wiki/周易/漸", + "upperTrigram": "XUN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "女归吉,利贞。", + "lineTextsBottomUp": [ + "初六:鸿渐于干,小子厉,有言,无咎。", + "六二:鸿渐于磐,饮食衎衎,吉。", + "九三:鸿渐于陆,夫征不复,妇孕不育,凶;利御寇。", + "六四:鸿渐于木,或得其桷,无咎。", + "九五:鸿渐于陵,妇三岁不孕,终莫之胜,吉。", + "上九:鸿渐于陆,其羽可用为仪,吉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 54, + "wikisourceTitle": "歸妹", + "sourcePage": "https://zh.wikisource.org/wiki/周易/歸妹", + "upperTrigram": "ZHEN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "征凶,无攸利。", + "lineTextsBottomUp": [ + "初九:归妹以娣,跛能履,征吉。", + "九二:眇能视,利幽人之贞。", + "六三:归妹以须,反归以娣。", + "九四:归妹愆期,迟归有时。", + "六五:帝乙归妹,其君之袂,不如其娣之袂良,月几望,吉。", + "上六:女承筐无实,士刲羊无血,无攸利。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 55, + "wikisourceTitle": "豐", + "sourcePage": "https://zh.wikisource.org/wiki/周易/豐", + "upperTrigram": "ZHEN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨。王假之,勿忧,宜日中。", + "lineTextsBottomUp": [ + "初九:遇其配主,虽旬无咎,往有尚。", + "六二:丰其蔀,日中见斗,往得疑疾,有孚发若,吉。", + "九三:丰其沛,日中见沫,折其右肱,无咎。", + "九四:丰其蔀,日中见斗,遇其夷主,吉。", + "六五:来章,有庆誉,吉。", + "上六:丰其屋,蔀其家,窥其户,阒其无人,三岁不觌,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 56, + "wikisourceTitle": "旅", + "sourcePage": "https://zh.wikisource.org/wiki/周易/旅", + "upperTrigram": "LI", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "小亨,旅贞吉。", + "lineTextsBottomUp": [ + "初六:旅琐琐,斯其所取灾。", + "六二:旅即次,怀其资,得童仆贞。", + "九三:旅焚其次,丧其童仆,贞厉。", + "九四:旅于处,得其资斧,我心不快。", + "六五:射雉一矢亡,终以誉命。", + "上九:鸟焚其巢,旅人先笑后号咷。丧牛于易,凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 57, + "wikisourceTitle": "巽", + "sourcePage": "https://zh.wikisource.org/wiki/周易/巽", + "upperTrigram": "XUN", + "lowerTrigram": "XUN", + "patternBottomUp": [ + "YIN", + "YANG", + "YANG", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "小亨。利有攸往。利见大人。", + "lineTextsBottomUp": [ + "初六:进退,利武人之贞。", + "九二:巽在床下,用史巫纷若,吉无咎。", + "九三:频巽,吝。", + "六四:悔亡,田获三品。", + "九五:贞吉悔亡,无不利。无初有终,先庚三日,后庚三日,吉。", + "上九:巽在床下,丧其资斧,贞凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 58, + "wikisourceTitle": "兌", + "sourcePage": "https://zh.wikisource.org/wiki/周易/兌", + "upperTrigram": "DUI", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YANG", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨。利贞。", + "lineTextsBottomUp": [ + "初九:和兑,吉。", + "九二:孚兑,吉,悔亡。", + "六三:来兑,凶。", + "九四:商兑,未宁,介疾有喜。", + "九五:孚于剥,有厉。", + "上六:引兑。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 59, + "wikisourceTitle": "渙", + "sourcePage": "https://zh.wikisource.org/wiki/周易/渙", + "upperTrigram": "XUN", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "亨。王假有庙,利涉大川,利贞。", + "lineTextsBottomUp": [ + "初六:用拯马壮,吉。", + "九二:涣奔其机,悔亡。", + "六三:涣其躬,无悔。", + "六四:涣其群,元吉。涣有丘,匪夷所思。", + "九五:涣汗其大号,涣王居,无咎。", + "上九:涣其血,去逖出,无咎。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 60, + "wikisourceTitle": "節", + "sourcePage": "https://zh.wikisource.org/wiki/周易/節", + "upperTrigram": "KAN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨。苦节不可贞。", + "lineTextsBottomUp": [ + "初九:不出户庭,无咎。", + "九二:不出门庭,凶。", + "六三:不节若,则嗟若,无咎。", + "六四:安节,亨。", + "九五:甘节,吉;往有尚。", + "上六:苦节,贞凶,悔亡。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 61, + "wikisourceTitle": "中孚", + "sourcePage": "https://zh.wikisource.org/wiki/周易/中孚", + "upperTrigram": "XUN", + "lowerTrigram": "DUI", + "patternBottomUp": [ + "YANG", + "YANG", + "YIN", + "YIN", + "YANG", + "YANG" + ], + "judgmentOriginal": "豚鱼吉,利涉大川,利贞。", + "lineTextsBottomUp": [ + "初九:虞吉,有他不燕。", + "九二:鸣鹤在阴,其子和之,我有好爵,吾与尔靡之。", + "六三:得敌,或鼓或罢,或泣或歌。", + "六四:月几望,马匹亡,无咎。", + "九五:有孚挛如,无咎。", + "上九:翰音登于天,贞凶。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 62, + "wikisourceTitle": "小過", + "sourcePage": "https://zh.wikisource.org/wiki/周易/小過", + "upperTrigram": "ZHEN", + "lowerTrigram": "GEN", + "patternBottomUp": [ + "YIN", + "YIN", + "YANG", + "YANG", + "YIN", + "YIN" + ], + "judgmentOriginal": "亨。利贞。可小事,不可大事。飞鸟遗之音,不宜上宜下,大吉。", + "lineTextsBottomUp": [ + "初六:飞鸟以凶。", + "六二:过其祖,遇其妣;不及其君,遇其臣;无咎。", + "九三:弗过防之,从或戕之,凶。", + "九四:无咎,弗过遇之。往厉必戒,勿用永贞。", + "六五:密云不雨,自我西郊,公弋取彼在穴。", + "上六:弗遇过之,飞鸟离之,凶,是谓灾眚。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 63, + "wikisourceTitle": "既濟", + "sourcePage": "https://zh.wikisource.org/wiki/周易/既濟", + "upperTrigram": "KAN", + "lowerTrigram": "LI", + "patternBottomUp": [ + "YANG", + "YIN", + "YANG", + "YIN", + "YANG", + "YIN" + ], + "judgmentOriginal": "亨小。利贞。初吉终乱。", + "lineTextsBottomUp": [ + "初九:曳其轮,濡其尾,无咎。", + "六二:妇丧其茀,勿逐,七日得。", + "九三:高宗伐鬼方,三年克之,小人勿用。", + "六四:𦈡有衣袽,终日戒。", + "九五:东邻杀牛,不如西邻之禴祭,实受其福。", + "上六:濡其首,厉。" + ], + "specialUsageText": null + }, + { + "kingWenNumber": 64, + "wikisourceTitle": "未濟", + "sourcePage": "https://zh.wikisource.org/wiki/周易/未濟", + "upperTrigram": "LI", + "lowerTrigram": "KAN", + "patternBottomUp": [ + "YIN", + "YANG", + "YIN", + "YANG", + "YIN", + "YANG" + ], + "judgmentOriginal": "亨。小狐汔济,濡其尾,无攸利。", + "lineTextsBottomUp": [ + "初六:濡其尾,吝。", + "九二:曳其轮,贞吉。", + "六三:未济,征凶,利涉大川。", + "九四:贞吉,悔亡,震用伐鬼方,三年有赏于大国。", + "六五:贞吉,无悔,君子之光,有孚,吉。", + "上九:有孚于饮酒,无咎,濡其首,有孚失是。" + ], + "specialUsageText": null + } +] diff --git a/docs/README.md b/docs/README.md index 0ce4d96..5ff9822 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ > 文档状态:方案基线 > 最后核验:2026-08-19 -> 当前阶段:正式产品名“灵机”;P0/P1 已完成;P3 离线主流程(方法说明、起念、手录、卦名/动爻结果)已可走通;P4 仅完成会话级本机保存与设置,问卦簿与本地解释未开始;P2 授权内容未开始;P-1 v0.3 待视觉复核;P5 未开始 +> 当前阶段:正式产品名“灵机”;P0/P1 已完成;P3 离线主流程(方法说明、起念、手录、卦名/动爻结果)已可走通;P4 仅完成会话级本机保存与设置,问卦簿与本地解释未开始;P2 已接入维基文库《易经》原文与项目自撰白话草稿,待内容负责人审校;P-1 v0.3 待视觉复核;P5 未开始 本目录是 Brainwave 的项目知识事实源。产品决策、领域算法、架构边界、验收标准和已知失败模式必须写入仓库;聊天记录、口头约定和临时提示不构成项目规范。 @@ -22,6 +22,7 @@ | [移动端交互原型](prototype.md) | 评审流程、视觉或开始 Compose 页面前 | 可点击原型、截图入口、确认清单和 Android 映射 | | [系统架构](architecture.md) | 新增包、依赖、数据源或网络能力时 | 分层、依赖方向、运行时数据流 | | [数据与内容](data-content.md) | 修改卦库、历史记录或内容来源时 | 数据契约、授权、隐私和迁移规则 | +| [内容审校](content-review.md) | 审校卦辞来源或准备发布时 | 来源、异文和签核状态 | | [AI 解释与安全](ai-safety.md) | 修改提示词、模型调用或解释结果时 | AI 调用门、输入输出契约和安全边界 | | [质量门禁](quality-gates.md) | 实现、评审、发布前 | 自动化验证、需求追踪和完成定义 | | [依赖与许可证](dependency-licenses.md) | 新增/升级依赖或准备分发时 | 当前解析依赖、SPDX 与权威许可来源 | diff --git a/docs/architecture.md b/docs/architecture.md index cfbed78..412ee12 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -69,7 +69,7 @@ app/src/main/java/net/opcapp/flash/ 测试按相同包结构镜像放入 `src/test` 和 `src/androidTest`。 -当前已落地的包:`app/`、`core/model`、`core/designsystem`、`domain/casting`、`data/content`(接口与测试 fake)、`data/history`、`data/settings`、`feature/onboarding`、`feature/home`、`feature/question`、`feature/casting`、`feature/result`、`feature/settings`。尚未创建 `feature/history`、`feature/explanation`、`domain/explanation` 和 `data/ai`。首页不为问卦簿或「解」生成空占位。 +当前已落地的包:`app/`、`core/model`、`core/designsystem`、`domain/casting`、`data/content`(assets 解析器与测试 fake)、`data/history`、`data/settings`、`feature/onboarding`、`feature/home`、`feature/question`、`feature/casting`、`feature/result`、`feature/settings`、`feature/content`。尚未创建 `feature/history`、`feature/explanation`、`domain/explanation` 和 `data/ai`。首页不为问卦簿或「解」生成空占位。 ## 4. 依赖方向 diff --git a/docs/content-review.md b/docs/content-review.md new file mode 100644 index 0000000..3a163e0 --- /dev/null +++ b/docs/content-review.md @@ -0,0 +1,34 @@ +# 内容审校记录 + +> 状态:P2 数据包已生成,待内容负责人确认可再分发 +> 内容版本:`zh-Hans-2026.1` + +## 已接受来源 + +| 来源 ID | 文本 | 许可 | 说明 | +|---|---|---|---| +| `wikisource-zhouyi-jing-zh-Hans` | 卦辞、爻辞、乾用九、坤用六 | 公版(Wikimedia PD-old) | 维基文库《周易》仅《易经》;不含彖、象、文言等十翼。导入脚本:`scripts/import-zhouyi-wikisource.mjs` | +| `lingji-plain-zh-Hans-2026.1` | 本地白话 | 项目自撰草稿 | `content/plain/lingji-plain.mjs`;审校完成前不得当作已授权现代译本 | + +未采用南怀瑾、傅佩荣或其他仍受版权保护的现代译注。 + +## 工程入口 + +- 原始导入:`content/raw/zhouyi-wikisource-jing.json` +- 发布包:`content/packages/hexagram-content.json` +- 构建:`node scripts/build-hexagram-package.mjs` +- 再导入需本机 HTTP 代理(默认 `http://127.0.0.1:1080`)访问 `zh.wikisource.org` + +## 已知异文 + +维基文库复卦初九作「不复远,无袛悔」,与常见通行本「不远复,无祇悔」不同。本包按维基文库底本收录,不在导入时改字。审校时可决定是否改从通行本并提升 `contentVersion`。 + +## 审校清单 + +- [ ] 64 卦卦辞、384 爻与通行《易经》对读,记录有意保留的异文 +- [ ] 确认不含十翼 +- [ ] 白话无占断口吻、无未授权现代译注抄袭 +- [ ] 乾用九、坤用六原文无误 +- [ ] 内容负责人签署可再分发 + +签署前,P2 不得标记完成,商店发布不得进行。 diff --git a/docs/data-content.md b/docs/data-content.md index 57a5f05..38b97d3 100644 --- a/docs/data-content.md +++ b/docs/data-content.md @@ -1,6 +1,6 @@ # 数据、内容与隐私契约 -> 状态:结构已定义,内容来源与授权仍为发布阻塞项 +> 状态:`zh-Hans-2026.1` 已接入应用;白话为草稿,发布仍待审校 > 适用范围:卦库 assets、Room、DataStore、导入脚本和内容审核 ## 1. 数据分类 @@ -58,7 +58,7 @@ 示例中的省略号不是可发布内容。禁止由 AI 在构建时临时补齐缺失卦辞或爻辞。 -机器契约位于 `content/schema/hexagram-content.schema.json`。`specialUsageTexts` 显式声明当前内容版本是否提供乾“用九”和坤“用六”;声明为 `false` 时对应条目的 `specialUsageText` 必须为 `null`,不能用空字符串暗示内容存在。Android parser 尚未建立前,`scripts/verify-content-contract.mjs` 已提供独立构建期校验、稳定 SHA-256 摘要和不含可发布卦辞的自动化夹具;`HexagramContentRepository` 接口与测试 fake 已建立,缺少 ID 或内容版本不匹配时抛出数据完整性错误,不回退到相邻条目。应用当前只使用文王卦名查找表展示结果,不把未授权卦辞打入 APK。 +机器契约位于 `content/schema/hexagram-content.schema.json`。`specialUsageTexts` 显式声明当前内容版本是否提供乾“用九”和坤“用六”;声明为 `false` 时对应条目的 `specialUsageText` 必须为 `null`,不能用空字符串暗示内容存在。`scripts/verify-content-contract.mjs` 校验夹具与 `content/packages/hexagram-content.json`;Kotlin `HexagramContentParser` 用同一套规则加载 assets。`HexagramContentRepository` 在缺少 ID 或内容版本不匹配时抛出数据完整性错误,不回退到相邻条目。来源与审校状态见 [内容审校](content-review.md)。 ## 3. 内容完整性门禁 diff --git a/docs/decisions.md b/docs/decisions.md index 4274356..00e196c 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -142,14 +142,36 @@ - 后果:主代码迁移到 `net.opcapp.flash`;Android 壳使用“灵机”和 `minSdk=26`。应用图标、商店文案和签名仍未由本决策确认。当前 `compileSdk/targetSdk=34` 是已安装工具链基线,不代表永久商店目标;发布前须按当时商店要求复核升级。 - 复审触发:组织域名所有权变化、发布账号要求更换 ID,或依赖/覆盖率数据要求提高最低系统版本。application ID 一旦发布不得轻率更换。 +## ADR-015:自有白话 + 维基文库公版《易经》原文 + +- 状态:`Accepted` +- 日期:2026-08-19 +- 关联:TBD-005、FR-R-005、P2 +- 决定:安装包内的经典原文取自维基文库《周易》的《易经》部分(卦辞、爻辞,以及乾用九、坤用六),不含十翼;现代白话由本项目自撰,标为草稿,待内容负责人审校后才视为可再分发。不把南怀瑾、傅佩荣等现代译注入 APK。 +- 原因:需要可核验、可再分发的公版原文,同时避免把仍受版权保护的现代译文误当成古籍公版。 +- 备选:等待商业授权会继续阻塞离线阅读;使用来源不明的网络译文无法通过内容门禁。 +- 后果:原文事实源为 `content/raw/zhouyi-wikisource-jing.json`,经 `scripts/import-zhouyi-wikisource.mjs` 导入并由 Wikimedia `zh-hans` 转换;白话事实源为 `content/plain/lingji-plain.mjs`;发布包为 `content/packages/hexagram-content.json`,构建时拷入 assets。应用内必须区分“原文”与“本地白话”,并提供内容来源页。P2 在审校签核前不得标为完成。 +- 复审条件:维基文库页面结构变化、发现与通行本有影响阅读的异文、或内容负责人改用另一公版底本。 + +## ADR-016:乾用九、坤用六在内容具备时展示 + +- 状态:`Accepted` +- 日期:2026-08-19 +- 关联:TBD-006、P2/P3 +- 决定:内容包声明并收录乾“用九”、坤“用六”。结果页仅在本卦为乾且六爻皆老阳,或本卦为坤且六爻皆老阴时展示对应特殊文本。 +- 原因:用九/用六是《易经》文本的一部分,不是另造的占断;只有全动时才按传统用法出示,避免静卦或单爻动时误读。 +- 备选:一律隐藏会丢掉已具备的原文;凡见乾坤都展示会把特殊用法当成普通爻辞。 +- 后果:`specialUsageTexts.qian/kun` 必须为 true,且仅乾、坤可有 `specialUsageText`。之卦为乾坤但不满足全九/全六时不展示用九/用六。 +- 复审条件:产品决定对之卦或非全动情形也提示该文本。 + ## 未决问题 | ID | 问题 | 推荐默认 | 阻塞阶段 | |---|---|---|---| | TBD-001 | 应用图标与商店素材 | 产品名已由 ADR-014 确认为“灵机”;图标不使用未确认成稿 | P6 商店配置 | | TBD-004 | 问题是否允许留空 | 允许选择“不写具体内容”,但需显式操作 | P3 | -| TBD-005 | 经典原文、现代白话的版本与授权 | 自有白话 + 可核验公版原文 | P2,发布阻塞 | -| TBD-006 | 乾用九、坤用六是否纳入 MVP | 内容具备时展示 | P2/P3 | +| TBD-005 | 经典原文、现代白话的版本与授权 | 已由 ADR-015 接受;内容负责人审校仍阻塞发布 | P2,发布阻塞 | +| TBD-006 | 乾用九、坤用六是否纳入 MVP | 已由 ADR-016 接受:全九/全六时展示 | P2/P3 | | TBD-009 | AI 模型供应商与自有后端 | 供应商无关接口;先交付本地版 | P5 | | TBD-010 | 服务端问题/回复保留期 | 最小化且明确披露,优先不持久化正文 | P5,发布阻塞 | | TBD-011 | 高风险本地资源表覆盖地区 | 首发市场确认后维护,不让模型编号码 | P5 | diff --git a/docs/dependency-licenses.md b/docs/dependency-licenses.md index 977d99c..25694d7 100644 --- a/docs/dependency-licenses.md +++ b/docs/dependency-licenses.md @@ -41,4 +41,4 @@ | `kotlin-runtime-policy` | `org.jetbrains.kotlin` | 运行时传递依赖 | Apache-2.0 | [Kotlin license](https://github.com/JetBrains/kotlin/blob/v1.9.20/license/LICENSE.txt) | | `kotlinx-runtime-policy` | `org.jetbrains.kotlinx` | 运行时传递依赖 | Apache-2.0 | [Kotlinx Coroutines license](https://github.com/Kotlin/kotlinx.coroutines/blob/1.7.1/LICENSE.txt) | -当前没有第三方字体、纹理、插画、音效或可发布《易经》内容进入工程。应用仅使用 Android 系统字体和代码绘制的卦象;这句话只描述本提交时的资源图,不构成未来授权。 +当前没有第三方字体、纹理、插画或音效进入工程。应用使用 Android 系统字体、代码绘制的卦象,以及 `content/packages/hexagram-content.json` 中的维基文库公版《易经》与项目自撰白话草稿;这句话只描述本提交时的资源图,不构成内容负责人已签核。 diff --git a/docs/environment.md b/docs/environment.md index 2f40334..a6bb154 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -157,7 +157,7 @@ Android Studio 不是当前环境的可用前提。项目必须先支持 PowerSh - `PATH` 中 ADB 1.0.32 与 SDK ADB 1.0.41 会争用 server;当前三星设备的可重复门禁需要显式选择便携 ADB,后续应评估统一驱动和 Platform Tools。 - 代理已配置;本轮 Maven 依赖下载成功,但不能据此保证未来网络始终可用。 -已解除的缺口:Gradle Wrapper、Version Catalog、根 `AGENTS.md`、CI、正式 Android 身份和 application 壳均已建立。2026-08-19,`verifyLocal` 通过(含 22 个 debug 单元测试、`lintDebug` 与 debug APK);便携 ADB 下 Samsung API 31 真机 `run-connected-tests.ps1` 得到 `OK (4 tests)`,覆盖方法说明、保存设置、夹具「复 24 → 坤 2、初爻动」本机保存/当次删除,以及 Room 会话读写。未发现应用崩溃日志。飞行模式人工走查、无障碍抽测和授权内容包仍未做。 +已解除的缺口:Gradle Wrapper、Version Catalog、根 `AGENTS.md`、CI、正式 Android 身份和 application 壳均已建立。2026-08-19,`verifyLocal` 通过(含 debug 单元测试、`lintDebug` 与 debug APK,已校验 `zh-Hans-2026.1` 内容包);便携 ADB 下 Samsung API 31 真机 `run-connected-tests.ps1` 得到 `OK (4 tests)`,覆盖方法说明、保存设置、夹具「复 24 → 坤 2、初爻动」本机保存/当次删除(结果页已展示原文/白话),以及 Room 会话读写。未发现应用崩溃日志。飞行模式人工走查、无障碍抽测和内容负责人签核仍未做。 这些缺口分别由[实施计划](implementation-plan.md)的 P0 和[质量门禁](quality-gates.md)处理。环境缺口不是跳过验证的理由;无法运行的门禁必须在交付报告中准确说明。 diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md index 8b21b29..cb01585 100644 --- a/docs/implementation-plan.md +++ b/docs/implementation-plan.md @@ -1,6 +1,6 @@ # 分阶段实施计划 -> 状态:P0/P1 已完成;P3 离线主流程已落地但未达到 UX 全表验收;P4 会话保存已落地,问卦簿/解读未开始;P2 授权内容未开始;P-1 v0.3 待视觉复核 +> 状态:P0/P1 已完成;P3 离线主流程已落地但未达到 UX 全表验收;P4 会话保存已落地,问卦簿/解读未开始;P2 已接入公版《易经》与自撰白话草稿,待审校签核;P-1 v0.3 待视觉复核 > 计划原则:先用原型确认高返工成本体验,再锁定确定性领域核心,随后接内容和 UI,最后接网络 AI ## 1. 依赖图 @@ -92,18 +92,18 @@ P1 与 P2 可并行,但 P3 不能在领域与内容契约未稳定时复制原 任务: -- [ ] 决定原文版本、现代白话来源和授权(TBD-005,发布阻塞)。 -- [ ] 实现 JSON schema、解析器和内容版本:`schemaVersion=1` 的机器 schema 已完成;Android/Kotlin assets 解析器待 Android 壳建立。 -- [ ] 录入/导入 64 卦、卦辞、384 条爻辞及所需特殊文本。 -- [ ] 建立来源清单、许可证清单和内容审核记录;schema 已强制每个来源包含版本、许可证与 URL。 +- [x] 决定原文版本、现代白话来源和授权(TBD-005):ADR-015 接受“自有白话 + 维基文库公版《易经》原文”;发布仍待审校签核。 +- [x] 实现 JSON schema、解析器和内容版本:`schemaVersion=1` 的机器 schema、Kotlin assets 解析器与 `zh-Hans-2026.1` 包已落地。 +- [x] 录入/导入 64 卦、卦辞、384 条爻辞及乾用九、坤用六;白话为项目自撰草稿。 +- [x] 建立来源清单、许可证清单和内容审核记录:见 [内容审校](content-review.md);schema 已强制每个来源包含版本、许可证与 URL。 - [x] 实现构建期完整性校验、文王序号/上下卦/bottom-up 交叉校验、稳定 SHA-256 摘要及 8 个负向夹具。 -- [ ] 实现 `HexagramContentRepository` fake 与 assets 版本:接口、强校验只读模型和测试 fake 已完成,assets 实现待 Android parser。 +- [x] 实现 `HexagramContentRepository` fake 与 assets 版本:加载失败时展示完整性错误,不回退到相邻卦。 退出条件: -- 64 卦/384 爻数据完整、唯一且来源可追踪。 -- 缺失、重复、非法顺序和错误映射测试均能失败。 -- 内容负责人确认可再分发。 +- [x] 64 卦/384 爻数据完整、唯一且来源可追踪。 +- [x] 缺失、重复、非法顺序和错误映射测试均能失败。 +- [ ] 内容负责人确认可再分发。 ## 6. P3:核心用户流程与东方设计系统 @@ -116,7 +116,7 @@ P1 与 P2 可并行,但 P3 不能在领域与内容契约未稳定时复制原 - [x] 实现首次说明、起念、投币和结果页面:方法说明、问题、六轮手录和结果已接入导航;空问题仍被拒绝,TBD-004 未决。 - [x] 实现 `CastingViewModel` 状态机及 SavedState 恢复:问题、已确认爻和当前轮次写入 `SavedStateHandle`;第六轮才调用 `CastEngine`。 - [x] 支持前五轮返回修改、第六轮封印和明确重新起卦。 -- [ ] 接入本地内容并区分原文/本地白话:结果页只展示卦名、卦号、六爻事实,并明示授权内容包未接入。 +- [x] 接入本地内容并区分原文/本地白话:结果页展示本卦卦辞、动爻爻辞和之卦卦辞,并标注原文/白话;乾全九、坤全六时展示用九/用六。白话仍为待审校草稿。 - [ ] 完成深浅主题、字体缩放、TalkBack、横屏和大屏适配:深浅色随系统;其余未做发布级验收。 退出条件: @@ -126,7 +126,7 @@ P1 与 P2 可并行,但 P3 不能在领域与内容契约未稳定时复制原 - AI/网络代码尚未存在也不影响流程。 - [UX 与东方视觉](ux-design.md)检查表通过。 -当前证据(2026-08-19):`verifyLocal` 通过;仪器测试覆盖方法说明、保存设置和夹具「复 24 → 坤 2、初爻动」的本机保存/当次删除。P3 仍未退出,因为授权卦辞、「解」、问卦簿入口和 UX 全表未完成。飞行模式未做人工走查。 +当前证据(2026-08-19):`verifyLocal` 通过;仪器测试覆盖方法说明、保存设置和夹具「复 24 → 坤 2、初爻动」的本机保存/当次删除。P3 仍未退出,因为「解」、问卦簿入口和 UX 全表未完成。飞行模式未做人工走查。内容包已接入但白话待审校。 ## 7. P4:本地解释与历史 diff --git a/docs/quality-gates.md b/docs/quality-gates.md index 144964e..508e6a8 100644 --- a/docs/quality-gates.md +++ b/docs/quality-gates.md @@ -128,7 +128,7 @@ | FR-C-007 | SavedState/重建测试 | 旋转、切后台、进程恢复 | | FR-R-001~003 | UI 语义与 screenshot 测试 | TalkBack、色觉与长文阅读 | | FR-R-004 | 网络失败测试 | 飞行模式 | -| FR-R-005 | 内容 schema/授权清单检查 | 内容负责人签核 | +| FR-R-005 | 内容 schema/授权清单检查 | 自动校验已接入;内容负责人签核仍待完成 | | FR-E-001~003 | 网络调用次数与同意状态测试 | 首次同意流程 | | FR-E-004~006 | 输出 schema + 安全用例集 | 安全/产品审核 | | FR-H-001~008 | 保存策略、Room 事务/版本、删除、备份排除、零网络调用测试 | 首页告知、设置、当次退出与删除体验 | diff --git a/docs/ux-design.md b/docs/ux-design.md index 97381ce..caeb571 100644 --- a/docs/ux-design.md +++ b/docs/ux-design.md @@ -2,7 +2,7 @@ > 状态:MVP 设计基线 > 适用范围:Android 手机优先,兼顾横屏、平板和系统无障碍设置 -> 当前实现:Compose 已覆盖方法说明、回访首页、起念、六轮手录、卦名/动爻结果和保存设置;问卦簿列表、「解」与授权卦辞仍未进入应用,不能把本文件尚未实现的页面当成已上线功能 +> 当前实现:Compose 已覆盖方法说明、回访首页、起念、六轮手录、卦名/动爻结果、原文/本地白话和保存设置;问卦簿列表与「解」仍未进入应用,不能把本文件尚未实现的页面当成已上线功能 ## 1. 体验定位 diff --git a/scripts/build-hexagram-package.mjs b/scripts/build-hexagram-package.mjs new file mode 100644 index 0000000..c66bcc1 --- /dev/null +++ b/scripts/build-hexagram-package.mjs @@ -0,0 +1,85 @@ +import { readFile, writeFile, mkdir } from "node:fs/promises"; +import path from "node:path"; +import { kingWenEntries, validateContentPackage } from "./content-contract.mjs"; +import { repositoryRoot } from "./repository-files.mjs"; +import { lingjiPlain } from "../content/plain/lingji-plain.mjs"; + +const names = [ + "乾", "坤", "屯", "蒙", "需", "讼", "师", "比", + "小畜", "履", "泰", "否", "同人", "大有", "谦", "豫", + "随", "蛊", "临", "观", "噬嗑", "贲", "剥", "复", + "无妄", "大畜", "颐", "大过", "坎", "离", "咸", "恒", + "遁", "大壮", "晋", "明夷", "家人", "睽", "蹇", "解", + "损", "益", "夬", "姤", "萃", "升", "困", "井", + "革", "鼎", "震", "艮", "渐", "归妹", "丰", "旅", + "巽", "兑", "涣", "节", "中孚", "小过", "既济", "未济", +]; + +if (lingjiPlain.length !== 64) { + throw new Error(`lingji plain table must contain 64 hexagrams, got ${lingjiPlain.length}`); +} + +const jingPath = path.join(repositoryRoot, "content", "raw", "zhouyi-wikisource-jing.json"); +const jing = JSON.parse(await readFile(jingPath, "utf8")); +if (!Array.isArray(jing) || jing.length !== 64) { + throw new Error("Wikisource jing import must contain 64 hexagrams; run scripts/import-zhouyi-wikisource.mjs"); +} + +const jingById = new Map(jing.map((item) => [item.kingWenNumber, item])); +const entries = kingWenEntries(); +const originalSource = "wikisource-zhouyi-jing-zh-Hans"; +const plainSource = "lingji-plain-zh-Hans-2026.1"; + +const contentPackage = { + schemaVersion: 1, + contentVersion: "zh-Hans-2026.1", + specialUsageTexts: { qian: true, kun: true }, + sources: [ + { + id: originalSource, + title: "维基文库《周易》易经", + edition: "仅卦辞、爻辞与乾用九、坤用六,不含十翼;由 zh.wikisource.org 导入并经 Wikimedia zh-hans 转换", + license: "公版(Wikimedia PD-old)", + url: "https://zh.wikisource.org/wiki/周易", + }, + { + id: plainSource, + title: "灵机本地白话", + edition: "2026.1 项目自撰草稿,待内容负责人审校后视为可再分发", + license: "项目自撰;审校完成前仅用于本机构建,不以现代译注冒充公版", + url: "https://creativecommons.org/licenses/by/4.0/deed.zh-Hans", + }, + ], + hexagrams: entries.map((entry) => { + const original = jingById.get(entry.kingWenNumber); + if (!original) { + throw new Error(`Missing jing text for King Wen ${entry.kingWenNumber}`); + } + const plain = lingjiPlain[entry.kingWenNumber - 1]; + if (!Array.isArray(plain) || plain.length !== 7 || plain.some((text) => !String(text).trim())) { + throw new Error(`Plain text for King Wen ${entry.kingWenNumber} must contain 7 non-blank strings`); + } + return { + ...entry, + name: names[entry.kingWenNumber - 1], + symbol: String.fromCodePoint(0x4DC0 + entry.kingWenNumber - 1), + judgmentOriginal: original.judgmentOriginal, + judgmentPlain: plain[0], + lineTextsBottomUp: original.lineTextsBottomUp, + linePlainBottomUp: plain.slice(1), + specialUsageText: original.specialUsageText ?? null, + sourceRefs: [originalSource, plainSource], + }; + }), +}; + +const errors = validateContentPackage(contentPackage); +if (errors.length > 0) { + throw new Error(`Built content package failed validation:\n${errors.join("\n")}`); +} + +const outputDirectory = path.join(repositoryRoot, "content", "packages"); +await mkdir(outputDirectory, { recursive: true }); +const outputPath = path.join(outputDirectory, "hexagram-content.json"); +await writeFile(outputPath, `${JSON.stringify(contentPackage, null, 2)}\n`); +process.stdout.write(`wrote ${outputPath}\n`); diff --git a/scripts/import-zhouyi-wikisource.mjs b/scripts/import-zhouyi-wikisource.mjs new file mode 100644 index 0000000..a4ced7f --- /dev/null +++ b/scripts/import-zhouyi-wikisource.mjs @@ -0,0 +1,221 @@ +import { execFile } from "node:child_process"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { promisify } from "node:util"; +import { kingWenEntries } from "./content-contract.mjs"; +import { repositoryRoot } from "./repository-files.mjs"; + +const execFileAsync = promisify(execFile); +const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "http://127.0.0.1:1080"; +const limit = Number.parseInt(process.env.IMPORT_LIMIT ?? "64", 10); +const userAgent = "LingjiContentImport/1.0 (local Zhouyi pipeline; public-domain jingwen only)"; +const outputDirectory = path.join(repositoryRoot, "content", "raw"); +const outputPath = path.join(outputDirectory, "zhouyi-wikisource-jing.json"); + +const titles = [ + "乾", "坤", "屯", "蒙", "需", "訟", "師", "比", + "小畜", "履", "泰", "否", "同人", "大有", "謙", "豫", + "隨", "蠱", "臨", "觀", "噬嗑", "賁", "剝", "復", + "无妄", "大畜", "頤", "大過", "坎", "離", "咸", "恆", + "遯", "大壯", "晉", "明夷", "家人", "睽", "蹇", "解", + "損", "益", "夬", "姤", "萃", "升", "困", "井", + "革", "鼎", "震", "艮", "漸", "歸妹", "豐", "旅", + "巽", "兌", "渙", "節", "中孚", "小過", "既濟", "未濟", +]; + +const linePattern = /^(初九|九二|九三|九四|九五|上九|初六|六二|六三|六四|六五|上六|用九|用六)[::,,](.*)$/u; + +function stripMarkup(wikitext) { + return wikitext + .replace(/-\{([^}|]+)-\}/gu, "$1") + .replace(/\{\{[^}]*\}\}/gu, "") + .replace(/<[^>]+>/gu, "") + .replace(/'{2,}/gu, "") + .replace(/\[\[File:[^\]]*\]\]/gu, "") + .replace(/\[\[(?:[^\|\]]*\|)?([^\]]+)\]\]/gu, "$1") + .replace(/ /gu, " ") + .replace(/\r/gu, ""); +} + +function parseClassicFields(section) { + const rawLines = section + .split("\n") + .map((line) => line.replace(/^[ *#:]+/u, "").trim()) + .filter(Boolean); + + let judgment = ""; + const lines = []; + let special = null; + for (const rawLine of rawLines) { + const compact = rawLine.replace(/\s+/gu, ""); + const hit = linePattern.exec(compact) ?? linePattern.exec(rawLine); + if (hit) { + const label = hit[1]; + const text = `${label}:${hit[2].trim()}`; + if (label === "用九" || label === "用六") { + special = text; + } else { + lines.push(text); + } + } else if (lines.length === 0 && special == null) { + const fragment = rawLine.replace(/\s+/gu, ""); + judgment = judgment ? `${judgment}${fragment}` : fragment; + } + } + + judgment = judgment + .replace(/^(?:周易)?[\u4e00-\u9fff]{1,3}[::]/u, "") + .trim(); + if (!judgment) throw new Error("missing judgment"); + if (lines.length !== 6) { + throw new Error(`expected 6 lines, got ${lines.length}: ${lines.join(" | ")}`); + } + return { judgmentOriginal: judgment, lineTextsBottomUp: lines, specialUsageText: special }; +} + +function extractClassicSection(wikitext) { + const normalized = stripMarkup(wikitext).replace(/\u3000/gu, " "); + const classicIndex = normalized.search(/易[經经][::]/u); + if (classicIndex < 0) throw new Error("missing 易經 section"); + const afterClassic = normalized.slice(classicIndex); + const stop = afterClassic.search(/\n[ *#]*彖曰[::]/u); + return (stop >= 0 ? afterClassic.slice(0, stop) : afterClassic) + .replace(/^易[經经][::]\s*/u, "") + .trim(); +} + +function stripHtml(value) { + return value + .replace(/<[^>]+>/gu, "") + .replace(/"/gu, "\"") + .replace(/&/gu, "&") + .replace(/</gu, "<") + .replace(/>/gu, ">") + .replace(/\n+/gu, "\n") + .trim(); +} + +async function curlJson(args) { + const { stdout } = await execFileAsync("curl.exe", [ + "-sS", + "--fail", + "--retry", + "12", + "--retry-delay", + "20", + "--retry-all-errors", + "--max-time", + "45", + "-x", + proxyUrl, + "-H", + `User-Agent: ${userAgent}`, + "-H", + "Accept: application/json", + ...args, + ], { encoding: "utf8", maxBuffer: 8 * 1024 * 1024 }); + return JSON.parse(stdout); +} + +const titleFallbacks = { + 恆: ["恒"], + 遯: ["遁"], + 晉: ["晋"], + 大壯: ["大壮"], + 歸妹: ["归妹"], + 豐: ["丰"], + 兌: ["兑"], + 渙: ["涣"], + 節: ["节"], + 既濟: ["既济"], + 未濟: ["未济"], +}; + +async function fetchWikitext(title) { + const candidates = [title, ...(titleFallbacks[title] ?? [])]; + for (const candidate of candidates) { + const url = new URL("https://zh.wikisource.org/w/api.php"); + url.searchParams.set("action", "parse"); + url.searchParams.set("page", `周易/${candidate}`); + url.searchParams.set("prop", "wikitext"); + url.searchParams.set("format", "json"); + const payload = await curlJson([url.toString()]); + const wikitext = payload?.parse?.wikitext?.["*"]; + if (typeof wikitext === "string") return wikitext; + process.stdout.write(`missing ${candidate}, trying fallback\n`); + } + throw new Error(`no wikitext for ${title}`); +} + +async function toHansFields(classic) { + const pieces = [ + classic.judgmentOriginal, + ...classic.lineTextsBottomUp, + ...(classic.specialUsageText == null ? [] : [classic.specialUsageText]), + ]; + const converted = await convertToHans(pieces.join("\n¶\n")); + const parts = converted + .split("¶") + .map((part) => part.replace(/\s+/gu, "").trim()) + .filter(Boolean); + if (parts.length !== pieces.length) { + throw new Error(`zh-hans field count ${parts.length} != ${pieces.length}: ${converted}`); + } + return { + judgmentOriginal: parts[0], + lineTextsBottomUp: parts.slice(1, 7), + specialUsageText: classic.specialUsageText == null ? null : parts[7], + }; +} +async function convertToHans(text) { + const payload = await curlJson([ + "--data-urlencode", "action=parse", + "--data-urlencode", `text=${text}`, + "--data-urlencode", "prop=text", + "--data-urlencode", "variant=zh-hans", + "--data-urlencode", "disablelimitreport=1", + "--data-urlencode", "wrapoutputclass=", + "--data-urlencode", "contentmodel=wikitext", + "--data-urlencode", "format=json", + "https://zh.wikisource.org/w/api.php", + ]); + const html = payload?.parse?.text?.["*"]; + if (typeof html !== "string") throw new Error("zh-hans conversion returned no text"); + return stripHtml(html); +} + +const entries = kingWenEntries(); +await mkdir(outputDirectory, { recursive: true }); +let imported = []; +try { + imported = JSON.parse(await readFile(outputPath, "utf8")); + if (!Array.isArray(imported)) imported = []; +} catch { + imported = []; +} +const done = new Set(imported.map((item) => item.kingWenNumber)); + +for (const [index, title] of titles.entries()) { + if (index >= limit) break; + const kingWenNumber = index + 1; + if (done.has(kingWenNumber)) { + process.stdout.write(`skip ${kingWenNumber}/64 ${title}\n`); + continue; + } + const wikitext = await fetchWikitext(title); + const traditional = extractClassicSection(wikitext); + const classic = await toHansFields(parseClassicFields(traditional)); + imported.push({ + kingWenNumber, + wikisourceTitle: title, + sourcePage: `https://zh.wikisource.org/wiki/周易/${title}`, + ...entries[index], + ...classic, + }); + imported.sort((left, right) => left.kingWenNumber - right.kingWenNumber); + await writeFile(outputPath, `${JSON.stringify(imported, null, 2)}\n`); + process.stdout.write(`imported ${kingWenNumber}/64 ${title}\n`); + await new Promise((resolve) => setTimeout(resolve, 1200)); +} + +process.stdout.write(`wrote ${outputPath} (${imported.length} hexagrams)\n`); diff --git a/scripts/verify-content-contract.mjs b/scripts/verify-content-contract.mjs index 55640bd..eb32852 100644 --- a/scripts/verify-content-contract.mjs +++ b/scripts/verify-content-contract.mjs @@ -104,3 +104,52 @@ for (const [name, mutate, expected] of negativeCases) { console.log( `Content contract verification passed (64 entries cross-checked with Kotlin, ${negativeCases.length} negative fixtures, digest ${digest.slice(0, 12)}…).`, ); + +const packagePath = path.join(repositoryRoot, "content", "packages", "hexagram-content.json"); +const namesPath = path.join( + repositoryRoot, + "app", + "src", + "main", + "java", + "net", + "opcapp", + "flash", + "core", + "model", + "HexagramNames.kt", +); +const namesSource = await readFile(namesPath, "utf8"); +const namesBlock = namesSource.match(/private val names = listOf\(([\s\S]*?)\)/u); +if (!namesBlock) { + throw new Error("HexagramNames.kt name table could not be parsed"); +} +const catalogNames = [...namesBlock[1].matchAll(/"([^"]+)"/gu)].map((match) => match[1]); +if (catalogNames.length !== 64) { + throw new Error("HexagramNames.kt must contain 64 names"); +} + +const published = JSON.parse(await readFile(packagePath, "utf8")); +const publishedErrors = validateContentPackage(published); +if (publishedErrors.length > 0) { + throw new Error(`Published content package failed validation:\n${publishedErrors.join("\n")}`); +} +published.hexagrams.forEach((hexagram) => { + const expectedName = catalogNames[hexagram.kingWenNumber - 1]; + const expectedSymbol = String.fromCodePoint(0x4DC0 + hexagram.kingWenNumber - 1); + if (hexagram.name !== expectedName) { + throw new Error(`Published package name for ${hexagram.kingWenNumber} must be ${expectedName}`); + } + if (hexagram.symbol !== expectedSymbol) { + throw new Error(`Published package symbol for ${hexagram.kingWenNumber} must be ${expectedSymbol}`); + } +}); +if (published.contentVersion !== "zh-Hans-2026.1") { + throw new Error("Published contentVersion must be zh-Hans-2026.1"); +} +if (!published.specialUsageTexts.qian || !published.specialUsageTexts.kun) { + throw new Error("Published package must include Qian 用九 and Kun 用六"); +} +console.log( + `Published content package ${published.contentVersion} passed (digest ${contentDigest(published).slice(0, 12)}…).`, +);