slow.monster

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.
7import data.market
9export type 진행단계 = "영업" | "정산" | "끝"
10export type 알림종류 = "없음" | "가격올림" | "가격내림" | "사입" | "판매" | "놓침" | "정산" | "장사끝" | "다음밤"
12export let 마지막밤 = 5
13// 아래 상한은 정상 플레이가 닿지 않으므로 정상 저장의 값은 그대로 지나갑니다.
14// 현금, 평판, 판매, 놓침, 재고, 가격의 상한입니다. 한 스텝 뒤의 + 판매가 와 + 1 이 64비트를 넘지 않습니다.
15let 값상한 = 1000000000
16// 한 밤의 손님 수 상한입니다. 정상 플레이는 여섯 명입니다.
17let 손님수상한 = 64
19export 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 알림: 알림종류,
35// 표는 만든 뒤 바꾸지 않습니다. 바뀐 값은 새 표로 만들므로 이전 상태와 표를 함께 써도 안전합니다.
36export 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 표
43export function 표갱신(표: Map<market.품목, int>, 바꿀품목: market.품목, 새값: int) -> Map<market.품목, int> {
44 품목표(market.품목목록().map(품 => if 품 == 바꿀품목 { 새값 } else { 표.getOr(품, 0) }))
47export 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 }
65function 표직렬화(표: Map<market.품목, int>) -> string {
66 market.품목목록().map(품 => "{표.getOr(품, 0)}").join(";")
69function 값가두기(값: int, 최소: int) -> int {
70 값.atLeast(최소).atMost(값상한)
73// 모자라거나 숫자가 아닌 값은 0 으로 읽은 뒤 최소와 값상한 사이로 가둡니다.
74function 표역직렬화(칸: string, 최소: int) -> Map<market.품목, int> {
75 let 값들 = 칸.split(";")
76 품목표(map(0..<market.품목목록().length, i => 값가두기(if i < 값들.length { toInt(값들[i]) ?? 0 } else { 0 }, 최소)))
79// 알림은 셸이 읽는 번호라 저장 문자열과 HUD 줄에서만 숫자로 씁니다. 모르는 번호는 없음으로 읽습니다.
80export function 알림번호(알림값: 알림종류) -> int {
81 match 알림값 {
82 case "없음" => 0
83 case "가격올림" => 1
84 case "가격내림" => 2
85 case "사입" => 3
86 case "판매" => 4
87 case "놓침" => 5
88 case "정산" => 6
89 case "장사끝" => 7
90 case "다음밤" => 8
91 }
94function 알림읽기(번호: 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 }
108// 저장 문자열과 HUD 줄의 단계 토큰은 serve, summary, 끝 입니다. 모르는 토큰은 영업으로 읽습니다.
109export function 단계토큰(단계값: 진행단계) -> string {
110 match 단계값 {
111 case "영업" => "serve"
112 case "정산" => "summary"
113 case "끝" => "끝"
114 }
117function 단계읽기(토큰: string) -> 진행단계 {
118 match 토큰 {
119 case "summary" => "정산"
120 case "끝" => "끝"
121 case _ => "영업"
122 }
125export function 직렬화(현재: 상태) -> string {
126 "DS1|{현재.시드}|{현재.밤}|{단계토큰(현재.단계)}|{현재.현금}|{현재.평판}|{표직렬화(현재.재고)}|{표직렬화(현재.가격)}|{현재.선택}|{현재.손님차례}|{현재.손님수}|{현재.판매}|{현재.놓침}|{알림번호(현재.알림)}"
129// 첫 칸의 판 표시는 보지 않고 열네 칸 뒤의 칸도 버립니다.
130export 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 }

SHA256 e38a081a28a6ec6bd74c64a93d9edd86d4431b8bf8d54e2a627763dedb91e34a