slow.monster

STUDIO HAZE · jeniapp

Topaz source

Open by house policy. Topaz is our own language.

Topaz 5.20.2 · 63 files

apps/secret-train/core/state.tpz

Topaz · 5869 B · Original file

1// 비밀열차의 저장 상태와 그 문자열 형식입니다. 턴마다 바뀌는 사실만 담고 지도와 순찰 경로는 data.levels 에서 읽습니다.
2// 저장 문자열은 BT1|시드|레벨코드|턴|제한턴|x|y|방향|열쇠|가방|결말|경비단계|안내|버팀 이고 경비단계는 ; 로 잇습니다.
3// 경비는 순찰 단계만 저장하고 위치와 방향은 그 단계에서 다시 구하므로 같은 문자열은 늘 같은 상태가 됩니다.
4// 13칸보다 짧으면 첫 칸 처음으로 두고, 읽을 수 없는 숫자는 기본값으로 읽은 뒤 모든 값을 레벨과 범위 안으로 가둡니다. 첫 칸의 판 표시는 보지 않습니다.
5// Secret train save state and its BT1 save string format.
7import data.levels
9// 정상 플레이의 제한턴은 레벨 값이라 이 상한에 닿지 않습니다. 턴은 제한턴 아래로 가두므로 한 턴 뒤의 + 1 과 흔들림 예고의 + 흔들주기가 64비트를 넘지 않습니다.
10let 턴상한 = 1000000000
12export type 결말종류 = "진행" | "탈출" | "발각" | "놓침"
13export type 안내종류 = "없음" | "열쇠" | "가방" | "승리" | "발각" | "놓침" | "버팀" | "다음칸"
15// 버팀은 이번 턴 좌석을 잡아 흔들림과 시야를 피했는지입니다.
16export type 상태 = {
17 시드: string,
18 레벨코드: string,
19 턴: int,
20 제한턴: int,
21 x: int,
22 y: int,
23 방향: levels.방향,
24 열쇠있음: bool,
25 가방있음: bool,
26 버팀: bool,
27 결말: 결말종류,
28 경비단계들: Array<int>,
29 안내: 안내종류,
32// 결말과 안내는 셸이 읽는 번호라 저장 문자열과 HUD 줄에서만 숫자로 씁니다. 모르는 번호는 진행과 없음으로 읽습니다.
33export function 결말번호(결말값: 결말종류) -> int {
34 match 결말값 {
35 case "진행" => 0
36 case "탈출" => 1
37 case "발각" => 2
38 case "놓침" => 3
39 }
42function 결말읽기(번호: int) -> 결말종류 {
43 match 번호 {
44 case 1 => "탈출"
45 case 2 => "발각"
46 case 3 => "놓침"
47 case _ => "진행"
48 }
51export function 안내번호(안내값: 안내종류) -> int {
52 match 안내값 {
53 case "없음" => 0
54 case "열쇠" => 1
55 case "가방" => 2
56 case "승리" => 3
57 case "발각" => 4
58 case "놓침" => 5
59 case "버팀" => 6
60 case "다음칸" => 7
61 }
64function 안내읽기(번호: int) -> 안내종류 {
65 match 번호 {
66 case 1 => "열쇠"
67 case 2 => "가방"
68 case 3 => "승리"
69 case 4 => "발각"
70 case 5 => "놓침"
71 case 6 => "버팀"
72 case 7 => "다음칸"
73 case _ => "없음"
74 }
77export function 레벨시작상태(시드: string, 레벨코드: string, 안내: 안내종류) -> 상태 {
78 let 레벨 = levels.레벨얻기(레벨코드)
79 {
80 시드: 시드,
81 레벨코드: 레벨코드,
82 턴: 0,
83 제한턴: 레벨.제한턴,
84 x: 레벨.시작.x,
85 y: 레벨.시작.y,
86 방향: "아래",
87 열쇠있음: false,
88 가방있음: false,
89 버팀: false,
90 결말: "진행",
91 경비단계들: 레벨.시작단계들,
92 안내: 안내,
93 }
96export function 기본상태(시드: string) -> 상태 {
97 레벨시작상태(시드, "L01", "없음")
100export function 일또는영(참거짓: bool) -> int {
101 if 참거짓 { 1 } else { 0 }
104// 경비가 없어도 칸 수가 줄지 않게 - 를 적습니다.
105function 단계문자열(단계들: Array<int>) -> string {
106 if 단계들.length == 0 { "-" } else { 단계들.map(단계 => "{단계}").join(";") }
109export function 직렬화(현재: 상태) -> string {
110 let 단계 = 단계문자열(현재.경비단계들)
111 "BT1|{현재.시드}|{현재.레벨코드}|{현재.턴}|{현재.제한턴}|{현재.x}|{현재.y}|{levels.방향번호(현재.방향)}|{일또는영(현재.열쇠있음)}|{일또는영(현재.가방있음)}|{결말번호(현재.결말)}|{단계}|{안내번호(현재.안내)}|{일또는영(현재.버팀)}"
114// 개수가 레벨의 경비 수와 다르면 그 레벨의 시작 단계로 두고, 각 단계는 그 경비의 순찰 길이 안으로 가둡니다.
115function 단계읽기(필드: string, 레벨: levels.레벨정보) -> Array<int> {
116 let 조각들: Array<string> = if 필드 == "-" || 필드 == "" { [] } else { 필드.split(";") }
117 if 조각들.length != 레벨.경비들.length { return 레벨.시작단계들 }
118 [for i in 0..<조각들.length => (toInt(조각들[i]) ?? 0).atLeast(0).atMost(레벨.경비들[i].순찰.length - 1)]
121function 참인가(필드: string) -> bool {
122 (toInt(필드) ?? 0) == 1
125export function 역직렬화(저장: string, 대체시드: string) -> 상태 {
126 let 필드들 = 저장.split("|")
127 if 필드들.length < 13 { return 기본상태(대체시드) }
128 let 레벨 = levels.레벨얻기(필드들[2])
129 let 제한턴 = (toInt(필드들[4]) ?? 레벨.제한턴).atLeast(1).atMost(턴상한)
130 let x = toInt(필드들[5]) ?? 레벨.시작.x
131 let y = toInt(필드들[6]) ?? 레벨.시작.y
132 // 플레이어는 바닥으로만 움직이므로 바닥이 아닌 칸은 레벨 시작 칸으로 되돌립니다.
133 let 바닥위 = levels.바닥인가(레벨, x, y)
134 {
135 시드: 필드들[1],
136 레벨코드: levels.레벨코드(레벨),
137 턴: (toInt(필드들[3]) ?? 0).atLeast(0).atMost(제한턴),
138 제한턴: 제한턴,
139 x: if 바닥위 { x } else { 레벨.시작.x },
140 y: if 바닥위 { y } else { 레벨.시작.y },
141 방향: levels.방향읽기(toInt(필드들[7]) ?? 2),
142 열쇠있음: 참인가(필드들[8]),
143 가방있음: 참인가(필드들[9]),
144 // 버팀 칸이 없는 13칸 저장도 읽습니다.
145 버팀: 필드들.length >= 14 && 참인가(필드들[13]),
146 결말: 결말읽기(toInt(필드들[10]) ?? 0),
147 경비단계들: 단계읽기(필드들[11], 레벨),
148 안내: 안내읽기(toInt(필드들[12]) ?? 0),
149 }

SHA256 39a2a8e78510f4e2c0aad0ec04f1fcc8a9fdd258d62e12528db2a43e6cb5ba0f