STUDIO HAZE · jeniapp
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.20.2 · 63 files
apps/moon-market/core/state.tpz
Topaz · 5785 B · Original file
1
// 달시장 상태. 한 밤의 진행을 레코드와 품목별 표로 들고, 스텝 경계에서만 저장 문자열로 바꿉니다.2
// 저장 문자열은 DS1|시드|밤|단계|현금|평판|재고|가격|선택|손님차례|손님수|판매|놓침|알림 이고 재고와 가격은 품목 순서대로 ; 로 잇습니다.3
// 같은 상태는 늘 같은 문자열이 됩니다. 시간과 외부 난수를 쓰지 않습니다.4
// 칸이 열넷보다 적으면 새로 시작하고, 숫자가 아닌 칸은 칸마다 정한 기본값으로 읽은 뒤 모든 값을 범위 안으로 가둡니다.5
// moon-market state: the night record, per-good tables and the pipe-separated save string.7
import data.market9
export type 진행단계 = "영업" | "정산" | "끝"10
export type 알림종류 = "없음" | "가격올림" | "가격내림" | "사입" | "판매" | "놓침" | "정산" | "장사끝" | "다음밤"12
export let 마지막밤 = 513
// 아래 상한은 정상 플레이가 닿지 않으므로 정상 저장의 값은 그대로 지나갑니다.14
// 현금, 평판, 판매, 놓침, 재고, 가격의 상한입니다. 한 스텝 뒤의 + 판매가 와 + 1 이 64비트를 넘지 않습니다.15
let 값상한 = 100000000016
// 한 밤의 손님 수 상한입니다. 정상 플레이는 여섯 명입니다.17
let 손님수상한 = 6419
export record 상태 {20
시드: string,21
밤: int,22
단계: 진행단계,23
현금: int,24
평판: int,25
재고: Map<market.품목, int>,26
가격: Map<market.품목, int>,27
선택: int,28
손님차례: int,29
손님수: int,30
판매: int,31
놓침: int,32
알림: 알림종류,33
}35
// 표는 만든 뒤 바꾸지 않습니다. 바뀐 값은 새 표로 만들므로 이전 상태와 표를 함께 써도 안전합니다.36
export function 품목표(값들: Array<int>) -> Map<market.품목, int> {37
let 품목들 = market.품목목록()38
let mut 표: Map<market.품목, int> = Map.new()39
for i in 0..<품목들.length { 표.insert(품목들[i], 값들[i]) }40
표41
}43
export function 표갱신(표: Map<market.품목, int>, 바꿀품목: market.품목, 새값: int) -> Map<market.품목, int> {44
품목표(market.품목목록().map(품 => if 품 == 바꿀품목 { 새값 } else { 표.getOr(품, 0) }))45
}47
export function 기본상태(시드: string) -> 상태 {48
상태 {49
시드: 시드,50
밤: 1,51
단계: "영업",52
현금: 20,53
평판: 50,54
재고: 품목표(market.품목목록().map(품 => 5)),55
가격: 품목표(market.품목목록().map(품 => 10)),56
선택: 0,57
손님차례: 0,58
손님수: 6,59
판매: 0,60
놓침: 0,61
알림: "없음",62
}63
}65
function 표직렬화(표: Map<market.품목, int>) -> string {66
market.품목목록().map(품 => "{표.getOr(품, 0)}").join(";")67
}69
function 값가두기(값: int, 최소: int) -> int {70
값.atLeast(최소).atMost(값상한)71
}73
// 모자라거나 숫자가 아닌 값은 0 으로 읽은 뒤 최소와 값상한 사이로 가둡니다.74
function 표역직렬화(칸: string, 최소: int) -> Map<market.품목, int> {75
let 값들 = 칸.split(";")76
품목표(map(0..<market.품목목록().length, i => 값가두기(if i < 값들.length { toInt(값들[i]) ?? 0 } else { 0 }, 최소)))77
}79
// 알림은 셸이 읽는 번호라 저장 문자열과 HUD 줄에서만 숫자로 씁니다. 모르는 번호는 없음으로 읽습니다.80
export function 알림번호(알림값: 알림종류) -> int {81
match 알림값 {82
case "없음" => 083
case "가격올림" => 184
case "가격내림" => 285
case "사입" => 386
case "판매" => 487
case "놓침" => 588
case "정산" => 689
case "장사끝" => 790
case "다음밤" => 891
}92
}94
function 알림읽기(번호: int) -> 알림종류 {95
match 번호 {96
case 1 => "가격올림"97
case 2 => "가격내림"98
case 3 => "사입"99
case 4 => "판매"100
case 5 => "놓침"101
case 6 => "정산"102
case 7 => "장사끝"103
case 8 => "다음밤"104
case _ => "없음"105
}106
}108
// 저장 문자열과 HUD 줄의 단계 토큰은 serve, summary, 끝 입니다. 모르는 토큰은 영업으로 읽습니다.109
export function 단계토큰(단계값: 진행단계) -> string {110
match 단계값 {111
case "영업" => "serve"112
case "정산" => "summary"113
case "끝" => "끝"114
}115
}117
function 단계읽기(토큰: string) -> 진행단계 {118
match 토큰 {119
case "summary" => "정산"120
case "끝" => "끝"121
case _ => "영업"122
}123
}125
export function 직렬화(현재: 상태) -> string {126
"DS1|{현재.시드}|{현재.밤}|{단계토큰(현재.단계)}|{현재.현금}|{현재.평판}|{표직렬화(현재.재고)}|{표직렬화(현재.가격)}|{현재.선택}|{현재.손님차례}|{현재.손님수}|{현재.판매}|{현재.놓침}|{알림번호(현재.알림)}"127
}129
// 첫 칸의 판 표시는 보지 않고 열네 칸 뒤의 칸도 버립니다.130
export function 역직렬화(저장: string, 대체시드: string) -> 상태 {131
let 칸들 = 저장.split("|")132
if 칸들.length < 14 { return 기본상태(대체시드) }133
let 손님수 = (toInt(칸들[10]) ?? 6).atLeast(1).atMost(손님수상한)134
상태 {135
시드: 칸들[1],136
밤: (toInt(칸들[2]) ?? 1).atLeast(1).atMost(마지막밤),137
단계: 단계읽기(칸들[3]),138
현금: 값가두기(toInt(칸들[4]) ?? 0, 0),139
평판: 값가두기(toInt(칸들[5]) ?? 50, 0),140
재고: 표역직렬화(칸들[6], 0),141
가격: 표역직렬화(칸들[7], 1),142
선택: (toInt(칸들[8]) ?? 0).atLeast(0).atMost(market.품목목록().length - 1),143
손님차례: (toInt(칸들[9]) ?? 0).atLeast(0).atMost(손님수),144
손님수: 손님수,145
판매: 값가두기(toInt(칸들[11]) ?? 0, 0),146
놓침: 값가두기(toInt(칸들[12]) ?? 0, 0),147
알림: 알림읽기(toInt(칸들[13]) ?? 0),148
}149
}SHA256 e38a081a28a6ec6bd74c64a93d9edd86d4431b8bf8d54e2a627763dedb91e34a