STUDIO HAZE · jeniapp
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.20.2 · 63 files
apps/slow-monster/core/evolution.tpz
Topaz · 10948 B · Original file
1
// 진화 준비가 된 크리처가 전투에서 레벨업하면 분기 진화합니다. 부모 게놈, 계통시드, 진화카운터에서 후보 돌연변이 2~3 개를 유도하고 고른 분기를 영구 형태로 고정합니다.2
// 후보는 분기 번호, 파생 형태이름, 돌연변이 게놈, 스탯부스트, 지배트레이트입니다. 고정 결과는 새 전투원과 계통 노드 재료입니다.3
// 모든 진화 난수는 mutation 도메인의 1,000,000 부터 시작하는 카운터 띠에서 뽑아 게놈(0~4)과 흔들림(19 이하) 카운터와 겹치지 않습니다. 같은 시드와 같은 분기 선택은 같은 생명의 나무입니다.4
// 형태 이름은 손으로 쓴 진화 사슬이 아니라 게놈에서 유도합니다. 세대, 진화카운터, 분기 번호를 가둬 조작된 저장이 넘침을 일으키지 않게 합니다.5
// Branch evolution: derives two or three seeded mutation candidates from the parent and locks the chosen branch.7
import core.rng { 난수 }8
import core.genome9
import core.creature10
import core.util { 범위가두기 }11
import data.species13
// 진화카운터마다 1,000 칸의 띠를 씁니다. 진화카운터 상한 1,000,000 이라 띠의 끝도 2^31 아래입니다.14
export let 진화시작 = 100000015
export let 카운터스텝 = 100016
export let 최대후보수 = 317
export let 최소후보수 = 219
export type 후보 = {20
분기: int,21
형태이름: string,22
게놈: genome.게놈,23
스탯부스트: int,24
지배트레이트: int,25
}27
// 시드지문은 새 계통시드이며 같은 시드와 분기면 같은 지문이 나오는 재현의 증거입니다.28
export type 진화결과 = {29
전투원: creature.전투원,30
형태이름: string,31
분기: int,32
세대: int,33
게놈요약후: string,34
시드지문: string,35
}37
// 도감에 그릴 발견 기록입니다. 고유번호는 계통시드의 해시입니다.38
export record 계통노드 {39
고유번호: int,40
부모고유번호: int,41
형태이름: string,42
게놈요약: string,43
세대: int,44
발견스텝: int,45
시드지문: string,46
}48
// 선형합동 난수의 아래 비트는 규칙적이라 위 비트를 씁니다.49
function 진화굴림(엔티티: int, 지역번호: int, 계통시드: string, 진화카운터: int, 폭: int) -> int {50
let 띠 = 진화시작 + creature.진화카운터가두기(진화카운터) * 카운터스텝 + 지역번호51
(난수("mutation", 엔티티, 띠, 계통시드) / 21474836) % 폭.atLeast(1)52
}54
export function 후보수(엔티티: int, 계통시드: string, 진화카운터: int) -> int {55
최소후보수 + 진화굴림(엔티티, 0, 계통시드, 진화카운터, 최대후보수 - 최소후보수 + 1)56
}58
function 트레이트가두기(값: int) -> int {59
범위가두기(값, 0, genome.강도상한 - 1)60
}62
function 트레이트들(대상: genome.게놈) -> Array<int> {63
[대상.색소, 대상.막, 대상.크기, 대상.대사, 대상.촉수]64
}66
// 값이 같으면 앞 번호가 이깁니다.67
export function 지배트레이트(대상: genome.게놈) -> int {68
let 값들 = 트레이트들(대상)69
reduce(1..<genome.트레이트수, 0, (최선, i) => if 값들[i] > 값들[최선] { i } else { 최선 })70
}72
// 진화는 늘 성장으로 보이도록 형질을 위로만 올리고 상한에서 멈춥니다.73
function 너지(값: int, 세기: int) -> int {74
(값 + 세기).atMost(genome.강도상한 - 1)75
}77
// 첫째 형질은 (지배 + 1 + 분기) 로 분기마다 다르게 고정해 분기마다 다른 형질이 자랍니다. 둘째 형질은 첫째와 겹치면 하나 옆으로 옮깁니다.78
function 돌연변이게놈(부모: genome.게놈, 엔티티: int, 분기: int, 계통시드: string, 진화카운터: int) -> genome.게놈 {79
let 기준 = 10 + 분기 * 580
let 첫형질 = (지배트레이트(부모) + 1 + 분기) % genome.트레이트수81
let 뽑은형질 = 진화굴림(엔티티, 기준 + 1, 계통시드, 진화카운터, genome.트레이트수)82
let 둘째형질 = if 뽑은형질 == 첫형질 { (첫형질 + 1) % genome.트레이트수 } else { 뽑은형질 }83
let 첫세기 = 진화굴림(엔티티, 기준 + 2, 계통시드, 진화카운터, 3) + 184
let 둘째세기 = 진화굴림(엔티티, 기준 + 3, 계통시드, 진화카운터, 3) + 185
let 부모값들 = 트레이트들(부모)86
let 값들 = [87
for i in 0..<genome.트레이트수 => 트레이트가두기(if i == 첫형질 { 너지(부모값들[i], 첫세기) } else if i == 둘째형질 { 너지(부모값들[i], 둘째세기) } else { 부모값들[i] })88
]89
genome.게놈만들기(값들[0], 값들[1], 값들[2], 값들[3], 값들[4])90
}92
function 어간(지배: int) -> string {93
match 지배 {94
case 0 => "빛무리"95
case 1 => "갑각"96
case 2 => "거대"97
case 3 => "열소"98
case _ => "촉수"99
}100
}102
// 후보는 2~3 개라 분기 번호로 고른 접미는 늘 서로 달라 어간이 같아도 이름이 겹치지 않습니다.103
function 접미(분기: int) -> string {104
match 분기 % 6 {105
case 0 => "체"106
case 1 => "충"107
case 2 => "포자"108
case 3 => "군체"109
case 4 => "정령"110
case _ => "변이체"111
}112
}114
// 세대는 노드가 따로 들고 있어 이름에 넣지 않습니다.115
function 형태이름(돌연변이: genome.게놈, 분기: int) -> string {116
"{어간(지배트레이트(돌연변이))}{접미(분기)}"117
}119
function 후보유도(부모: genome.게놈, 엔티티: int, 분기: int, 계통시드: string, 진화카운터: int) -> 후보 {120
let 돌연변이 = 돌연변이게놈(부모, 엔티티, 분기, 계통시드, 진화카운터)121
{122
분기: 분기,123
형태이름: 형태이름(돌연변이, 분기),124
게놈: 돌연변이,125
스탯부스트: 진화굴림(엔티티, 40 + 분기, 계통시드, 진화카운터, 4) + 2,126
지배트레이트: 지배트레이트(돌연변이),127
}128
}130
export function 후보들유도(부모: genome.게놈, 엔티티: int, 계통시드: string, 진화카운터: int) -> Array<후보> {131
map(0..<후보수(엔티티, 계통시드, 진화카운터), k => 후보유도(부모, 엔티티, k, 계통시드, 진화카운터))132
}134
// 정확한 형태와 이름은 고정한 뒤에 보여 주고 고르기 전에는 돌연변이게놈의 첫째 형질만 귀띔합니다.135
export function 후보힌트(후보입력: 후보) -> string {136
match (후보입력.지배트레이트 + 1 + 후보입력.분기) % genome.트레이트수 {137
case 0 => "빛을 머금는 색소가 짙어지는 기운"138
case 1 => "막이 단단해지는 기운"139
case 2 => "몸집이 불어나는 기운"140
case 3 => "대사가 빨라지는 기운"141
case _ => "촉수가 뻗어 나가는 기운"142
}143
}145
// 부모에서 후보를 다시 유도해 실제로 고른 게놈을 뺀 나머지, 가지 않은 길의 힌트를 모읍니다.146
export function 형제힌트들(부모게놈: genome.게놈, 부모시드: string, 부모세대: int, 선택게놈요약: string) -> string {147
let 후보들 = 후보들유도(부모게놈, 계통고유번호(부모시드), 부모시드, 부모세대)148
후보들.filter(후 => genome.게놈요약(후.게놈) != 선택게놈요약).map(후보힌트).join(" · ")149
}151
// 상한에 막힌 형질 때문에 두 분기의 게놈이 같을 수 있어 마지막으로 일치한 분기를 씁니다. 없으면 -1 입니다.152
export function 노드분기(부모게놈: genome.게놈, 부모시드: string, 부모세대: int, 자식게놈요약: string) -> int {153
let 후보들 = 후보들유도(부모게놈, 계통고유번호(부모시드), 부모시드, 부모세대)154
let 일치들 = 후보들.filter(후 => genome.게놈요약(후.게놈) == 자식게놈요약)155
if 일치들.length == 0 { -1 } else { 일치들[일치들.length - 1].분기 }156
}158
// 종아이디, 스프라이트, 속성, 기술은 그대로 두고 돌연변이 게놈이 새 기준 게놈이 됩니다. 진화는 체력을 새 최대로 채우고 드리프트를 0 으로 되돌립니다.159
// 범위 밖 분기 선택은 0 번 분기로 돌아갑니다.160
export function 분기진화(부모: creature.전투원, 분기선택: int, 부모세대: int, 부모진화카운터: int) -> 진화결과 {161
let 카운터 = creature.진화카운터가두기(부모진화카운터)162
let 후보들 = 후보들유도(부모.게놈, 계통고유번호(부모.계통시드), 부모.계통시드, 카운터)163
let 분기 = 범위가두기(분기선택, 0, 후보들.length - 1)164
let 고른후보 = 후보들[분기]165
let 시드 = "{부모.계통시드}>{분기}"166
let 새세대 = creature.세대가두기(부모세대 + 1)167
let 종정보 = species.종찾기(부모.종아이디)168
let 부스트 = 고른후보.스탯부스트169
let 새최대 = creature.최대체력(종정보, 부모.레벨) + 부스트 * 2170
let 새전투원 = 부모{171
현재체력: 새최대,172
최대체력: 새최대,173
공격: 종정보.기본공격 + 부모.레벨 + 부스트,174
방어: 종정보.기본방어 + 부모.레벨 + 부스트,175
속도: 종정보.기본속도 + 부모.레벨 + 부스트,176
계통시드: 시드,177
드리프트: 0,178
게놈: 고른후보.게놈,179
세대: 새세대,180
진화카운터: creature.진화카운터가두기(카운터 + 1),181
형태이름: 고른후보.형태이름,182
스탯부스트: 부모.스탯부스트 + 부스트,183
}184
{185
전투원: 새전투원,186
형태이름: 고른후보.형태이름,187
분기: 분기,188
세대: 새세대,189
게놈요약후: genome.게놈요약(고른후보.게놈),190
시드지문: 시드,191
}192
}194
export function 진화발사(드리프트: int, 오른레벨: int) -> bool {195
genome.진화준비(드리프트) && 오른레벨 > 0196
}198
// 후보 메뉴가 이 값으로 분기진화와 똑같은 후보를 다시 유도하므로 메뉴에서 본 후보가 곧 고정되는 후보입니다.199
export function 계통고유번호(계통시드: string) -> int {200
난수("mutation", 0, 0, 계통시드)201
}203
export function 노드빌드(결과: 진화결과, 부모고유번호: int, 스텝: int) -> 계통노드 {204
노드생성(계통고유번호(결과.시드지문), 부모고유번호, 결과.형태이름, 결과.게놈요약후, 결과.세대, 스텝, 결과.시드지문)205
}207
// 토파즈 과제 '구조 타입 주석 속 다른 모듈 레코드' 때문에 모듈째 가져오며 TPZ3017 때문에 레코드를 따로 가져올 수 없어 이 함수로 만듭니다.208
// 5.21 에서 그 과제가 고쳐지면 제거 여부를 다시 봅니다.209
export function 노드생성(고유번호: int, 부모고유번호: int, 형태이름: string, 게놈요약: string, 세대: int, 발견스텝: int, 시드지문: string) -> 계통노드 {210
계통노드 {211
고유번호: 고유번호,212
부모고유번호: 부모고유번호,213
형태이름: 형태이름,214
게놈요약: 게놈요약,215
세대: 세대,216
발견스텝: 발견스텝,217
시드지문: 시드지문,218
}219
}SHA256 1bd267c038ff762be2b2bf8903e64348f89e764b808534606da68c74a54f0806