매트릭스 표 — 컬럼 이름이 행 id인 것
두 축의 곱을 격자로 적은 시트를 읽는 설계입니다.
어느 레이아웃의 기능인가 — 지금은 이름 기반 레이아웃 하나입니다. 이 문서는 「격자를 이미 있는 형태로 읽는 법」을 정하고 레이아웃을 한정하지 않는데, 구현은 워크북의 정의된 이름으로 테이블 경계를 잡는 레이아웃에만 있습니다. 주 레이아웃에서 격자를 적으면 이 설계가 아니라 「컬럼 이름이 식별자가 아니다」로 거부됩니다 — 그 거부가 이 설계의 출발점이고, 아래 「매트릭스로 판독하는 조건」이 그것을 뒤집는 규칙입니다. 뒤집는 자리가 레이아웃마다 따로이기 때문에 한쪽에만 있습니다.
주 레이아웃에서 지금 쓸 수 있는 형태는 복합 키입니다 —
key="attacker,defender"로 적으면 두 축의 곱이 행이 되고 조회가 다인자가 됩니다(주 레이아웃 §3.5). 격자보다 넓게 적히는 대신 표기가 이미 있고, 이 설계가 사는 이유(105,558칸을 219행으로)는 규모가 그만할 때 생깁니다.
시트가 하는 말
id 24000000 24000001 24000002 ... (482개)
key:11000000~11999999 number number number
:required 1 1 1
11000000 0 -25 -125
11000001 ...
첫 컬럼은 한 축이고, 나머지 컬럼 이름 전부가 다른 축의 id입니다. 값은 그 둘의 교차점 하나입니다. 219 × 482 = 105,558개.
문제는 하나뿐입니다 — 24000000은 식별자가 아닙니다. 생성되는 코드는 프로퍼티 이름이
필요하고, 숫자로 시작하는 이름을 가질 수 있는 언어가 13개 중에 없습니다.
테이블 여부
낯설게 보이는 것이 당연하고, 답은 그렇다입니다.
매트릭스는 키 두 개의 함수입니다. 우리 테이블은 키 하나에서 레코드로 가는 것이고요. 그 둘을 잇는 방법은 이미 있습니다 — 한 축을 행으로, 다른 축을 배열의 자리로.
행 = 마을, 배열의 자리 = 교역품, 칸 = 값
그러면 남는 문제가 이름 하나뿐입니다. 24000000은 식별자가 아니라 프로퍼티 이름이 될 수 없는데,
배열의 원소는 이름이 필요 없습니다. 대신 「그 자리가 어느 id였나」를 잃으므로, 그것만 옆
테이블로 돌려주면 됩니다.
그래서 이 문서가 정하는 것은 새 형태가 아니라 격자를 이미 있는 형태로 읽는 법입니다.
출력 방식
테이블 둘. 값은 배열 하나로, 컬럼 id는 그 옆의 테이블로.
| 나오는 것 | 형태 |
|---|---|
SystemMatrix | { id, value: number[482] } × 219행 |
SystemMatrixColumn | { id, at: int } × 482행 |
이름이 이름인 컬럼은 그대로 남습니다 — CombatFaction은 { id, name, value: number[7] }입니다.
var at = Data.SystemMatrixColumn.FindById(goodsId).At;
var cost = Data.SystemMatrix.FindById(townId).Value[at];
코어는 한 줄도 바뀌지 않습니다. 배열 컬럼도 기본 인덱스도 이미 있는 것이고, 매트릭스는 우리가 이미 표현할 수 있는 테이블의 다른 표기였을 뿐입니다. 형식도, 생성기 13개도, 와이 어도 그대로입니다 — 바뀌는 것은 그 격자를 읽는 레이아웃 파일 하나입니다.
한 줄은 나중에 필요해졌습니다. 격자에 행 벌이 있으면 컬럼 집합이 벌마다 다르고, 접기는 컬럼 이름으로 맞춥니다 — 그런데 격자의 컬럼 이름은 이 문서가 위치로 다시 붙인 것입니다. 그래서 코어에 「이 컬럼을 벌끼리 맞출 때 쓰는 이름」 하나가 생겼고, 격자는 거기에 컬럼 id를 넣습니다. 코어는 여전히 격자를 모릅니다.
벌이 있는 격자
지역마다 축의 크기가 다를 수 있습니다 — 실측에서 원본이 마을 735개, 벌이 724개이고 벌의 id가 원본의 부분집합이지만 접두사가 아닙니다. 규칙과 실측은 행 벌의 4.2에 있고, 이 문서가 지키는 것은 둘입니다.
| 무엇 | 왜 |
|---|---|
| 컬럼마다 맞추는 이름에 컬럼 id를 넣습니다 | 접기가 위치가 아니라 id로 맞추도록 |
| 벌인 시트는 컬럼 테이블을 만들지 않습니다 | 접힌 뒤 자리는 원본의 것이므로, 벌의 컬럼 테이블은 틀린 자리를 적은 표가 됩니다 |
값 배열은 그 결과로 원소가 없을 수 있는 배열이 됩니다. 벌에 없는 마을이 그 벌의 행에서 「값 없음」이고, 그것이 「0이라고 적혀 있음」과 구별되어야 하기 때문입니다.
상수셋을 쓰지 않는 이유
컬럼 id를 상수로 내는 쪽을 먼저 봤습니다. 되지 않습니다 — 상수는 스칼라뿐이고, 배열 상수를 내려면 렌더러 13개를 고쳐야 합니다. 코어를 건드리지 않는다는 이 설계의 전제가 거기서 깨집니다.
그리고 되더라도 테이블 쪽이 낫습니다. 상수 배열에서 id를 찾는 것은 482개를 훑는 일이고, 테이블은 생성된 인덱스로 한 번에 찾습니다. 원래 하려던 일 — 「id로 자리를 찾는다」 — 을 테이블이 이미 하고 있었습니다.
long-form 3컬럼을 쓰지 않는 이유
{townId, goodsId, value} 한 행이 셀 하나면 105,558행이 됩니다. 코어 무변경인 것은 같지만,
- 행이 500배가 되고,
- 조회가 복합 키라 생성되는 인덱스로는 못 찾습니다 — 로드 후 사전을 손으로 만들어야 합니다.
데이터가 성기다면 이야기가 달랐을 텐데, 측정해 보니 105,558칸 중 비어 있는 것은 482칸(한 행) 뿐입니다. 성기지 않은 격자에 long-form을 쓰면 좌표를 값보다 많이 저장하게 됩니다.
매트릭스로 판독하는 조건
이름이 정수인 컬럼이 하나라도 있을 때입니다. 그 컬럼들만 배열이 되고, 이름이 이름인 컬럼은 지금까지대로 보통 필드로 남습니다.
「나머지 전부가 정수여야 한다」로 두면 실제 시트가 걸립니다 — CombatFaction은 id 다음에
name이 오고 그 뒤부터 id 컬럼입니다. 격자에 설명 컬럼이 하나 붙어 있는 것이지 격자가 아닌
것이 아닙니다.
| 규칙 | 왜 |
|---|---|
| 이름이 정수인 컬럼 → 배열의 원소 | 시트 순서 그대로가 자리입니다 |
| 이름이 식별자인 컬럼 → 그대로 | name은 축이 아니라 그 행의 설명입니다 |
| 정수 컬럼의 타입은 전부 같아야 | 한 배열의 원소들이므로. 다르면 그 컬럼과 함께 거부합니다 |
정수 이름 컬럼이 하나도 없으면 아무것도 달라지지 않습니다. 그리고 있는 표는 지금까지
「24000000은 식별자가 아닙니다」로 거부되던 것이므로, 동작하던 시트가 알아채지 못할 다른 형태가
되는 경우가 없습니다.
자르기는 걸지 않습니다. 이 레이아웃은 값이 있는 마지막 원소에서 배열을 자르는데 (설계), 매트릭스에서 그러면 로우마다 배열 길이가 달라지고
value[at]이 성립하지 않습니다. 자리가 곧 뜻인 배열은 자를 수 있는 배열이 아닙니다.
컬럼 테이블의 이름
<테이블 이름>Column입니다. 두 번째 축에 시트가 붙여준 이름이 없기 때문입니다 — 있는 것은
id 하나뿐이고 그것은 첫 축의 것입니다.
at은 자리이지 id가 아닙니다. 배열이 0부터 세므로 시트에 적힌 순서 그대로이고, 컬럼이
중간에 추가되면 그 뒤가 전부 밀립니다 — 그래서 배포할 때 두 테이블은 같이 나가야 합니다.
한쪽만 새것이면 알아채지 못할 다른 칸을 읽습니다.