Cảm ơn cho một câu đố hấp dẫn! Vâng, có vẻ như chúng ta có thể làm tốt hơn một chuyển đổi thông qua tọa độ cartesian của các trung tâm hình lục giác. Nó có thể được thực hiện hoàn toàn với toán số nguyên, mặc dù tôi đã bao gồm một tỷ lệ hợp lý trong một ma trận bên dưới để giữ cho ký hiệu ngắn gọn.
Bạn đúng rằng cả quá trình mã hóa và giải mã đều yêu cầu các vòng lặp. May mắn thay, vì SHM hoạt động theo các đơn đặt hàng cường độ, các vòng lặp sẽ không bao giờ cần nhiều hơn các lần lặp Log_7 (n + 1), trong đó n là số lượng ô trong lưới, rất hợp lý.
Để giữ cho ký hiệu của tôi đối xứng, tôi đã chọn sử dụng lưới 3 tọa độ như lưới bên dưới ( ví dụ của bạn từ Red Blob Games gọi là "Tọa độ khối" ). Nếu bạn thích, bạn có thể bỏ qua tọa độ z và thay thế tất cả các trường hợp của .z bằng - (x + y) để lấy "Tọa độ trục" thay thế.
Để biết tốc độ và độ sạch của mã, tôi khuyên bạn nên sử dụng bảng tra cứu để mã hóa và giải mã. Đầu tiên, để giải mã SHM thành tọa độ khối, bạn có thể xây dựng bảng với các lần lặp lại sau:
Rotate(v) = (-v.z, -v.x, -v.y)
Decode[,] = 2D array of ordered triples, [7 x (max_order_of_magnitude + 1)]
Decode[0, k] = (0, 0, 0) for all k = 0...max_order_of_magnitude
Decode[1, 0] = (0, -1, 1)
Decode[d + 1, k] = Rotate(Decode(d, k)) for d = 2...6, all k
Decode[d, k + 1] = Decode(d, k) + 2 * Rotate(Decode(d, k)) for all d, k
Sau đó giải mã trở nên cực kỳ đơn giản:
SHMToPoint(code)
{
point = (0, 0, 0)
order = 0
while(code > 0)
{
digit = code % 7
point += Decode(digit, order)
code = floor(code/7)
order++
}
return point
}
Điều này hoạt động vì hàng đầu tiên của bảng lưu trữ phần bù của các ô được mã hóa bằng các chữ số 0, 1, 2, 3, 4, 5, 6. Hàng tiếp theo lưu trữ các giá trị bù cho 0, 10, 20, 30, 40, 50, 60, v.v. Bằng cách tính tổng các độ lệch được đóng góp theo từng bậc độ lớn, bạn có thể giải mã bất kỳ điểm nào trong phạm vi của bảng.
Để mã hóa, tôi nghĩ phương pháp sau sẽ hiệu quả, nhưng tôi thú nhận rằng tôi chưa thử nghiệm nó. Nó sử dụng bảng tra cứu đơn giản hơn nhiều:
Encode = [0, 5, 1, 6, 3, 4, 2]
và một ma trận xoay và chia tỷ lệ:
Untwist = | 5 -4 2 |
| 2 5 -4 |
|-4 2 5 | * 1/21
Để mã hóa tọa độ khối vào SHM, sau đó ...
PointToSHM(point)
{
code = 0
magnitude = 1
while(point != (0, 0, 0))
{
digitIndex = (((point.x - 2 * point.y) % 7) + 7) % 7
code += magnitude *Encode[digitIndex]
point = Untwist * (point - Decode[digit, 0])
// treating "point" as a column vector, and rounding if necessary
magnitude *= 7
}
return code
}
Lưu ý rằng mã được tạo ở đây (và được giải mã ở trên) có định dạng số chuẩn (nghĩa là ô được đánh dấu "10" trong sơ đồ SHM sẽ được gán mã 7 trong cơ sở 10 hoặc 111 ở dạng nhị phân). Nếu bạn muốn hiển thị nó trong cơ sở 7, bạn sẽ cần sử dụng cơ số thích hợp khi chuyển đổi nó thành một chuỗi.
Điều này hoạt động bằng cách tìm ra chữ số có nghĩa ít nhất của mã SHM ở mỗi lần lặp, (sử dụng thực tế là các chữ số này lặp lại theo cách xếp mặt phẳng thường xuyên - LUT là chuỗi các chữ số được đọc từ (0, 0, 0) đến (6, 0, -6), lặp lại ở mức bù mỗi hàng). Tiếp theo, nó thực sự thay đổi chữ số đó bằng cách trừ đi phần bù tương ứng từ bảng Giải mã của chúng tôi trước đó và chia tỷ lệ fractal xuống một cấp bằng cách sử dụng ma trận Untwist. Điều này hoạt động giống như một sự thay đổi bên phải trong cơ sở 7, ở dạng hình học - nó đưa chữ số tiếp theo vào vị trí ít quan trọng nhất, đưa ô "10" thành "1", v.v., nơi chúng ta có thể sử dụng lại cùng một mẹo để đọc chữ số trên vòng lặp tiếp theo.
Tôi hi vọng nó làm việc cho bạn!