- xmas.c, tác phẩm đoạt giải International Obfuscated C Code Contest năm 1988, là đoạn mã C trông như gõ ngẫu nhiên nhưng lại in ra lời bài The Twelve Days of Christmas
- Chương trình nhúng các chuỗi đã mã hóa vào phần mã nhỏ hơn cả phần đầu ra, rồi giải mã từ và cụm từ bằng mật mã thay thế và gọi đệ quy
- Khi tách toán tử ba ngôi thành các khối
if-then-elsevà đặt tênwords,shift, cấu trúc trong đó giá trịtthay đổi luồng đệ quy bắt đầu lộ ra shiftánh xạ ký tự ở phần đầu với ký tự nằm sau 31 vị trí, cònwordschứa các mảnh lời bài hát đã mã hóa được ngăn cách bằng dấu gạch chéo (/)- Dù chỉ là chương trình in lời bài hát đơn giản, sự kết hợp của mật mã thay thế, đệ quy hai chiều, mã thừa và tham số không dùng đến khiến nó vẫn là một ví dụ sáng tạo về mã C làm rối
xmas.c in ra gì
- xmas.c là một chương trình C đoạt giải tại International Obfuscated C Code Contest năm 1988
- Người phân tích lần đầu nhìn thấy chương trình này vào khoảng năm 2000, rồi đến tháng 11 năm 2008 mới tách mã để hiểu cách nó hoạt động
- Khi biên dịch và chạy không có tham số, nó in ra lời bài hát mừng Giáng sinh The Twelve Days of Christmas từ ngày thứ 1 đến ngày thứ 12
- Chú thích trong mã gốc có nói rằng chương trình còn nhỏ hơn cả dạng “nén” của phần đầu ra, và các giám khảo cho rằng nó trông như “kết quả của việc gõ ngẫu nhiên trên một máy đánh chữ cũ”
Cấu trúc bên trong sau khi được viết lại cho dễ đọc
- Bước đầu tiên của quá trình phân tích là chuyển mọi biểu thức dạng
a ? b : cthành các khối if-then-else tường minh - Hai chuỗi khó hiểu được đặt tên theo đúng vai trò của chúng
words: tập hợp các từ và cụm từ đã mã hóa để tạo ra lời bài hát mừng Giáng sinhshift: chuỗi dùng cho phép thay thế để biến ký tự đã mã hóa thành ký tự thực sự được in ra
main()bắt đầu bằngxmas(1, 0, '\0'), sau đó chỉ một hàmxmas()xử lý toàn bộ đầu ra bằng đệ quy- Biến
tlà giá trị then chốt điều khiển hướng đệ quy và hành vi phân nhánh
Mật mã thay thế và dữ liệu lời bài hát
- Chuỗi shift thực tế hoạt động như thể là hai chuỗi được nối lại với nhau
- Ký tự tìm thấy ở nửa đầu sẽ được giải mã thành ký tự nằm sau nó 31 vị trí
- Ví dụ, ký tự đầu tiên
!trong chuỗi tương ứng với ký tự xuống dòng nằm sau 31 vị trí
- Ví dụ, ký tự đầu tiên
- Nhánh
t < -50dịch chuyển chuỗiatừng ký tự một cho đến khi ký tự đầu vào_xuất hiện trongshift- Khi tìm được ký tự khớp, nó in
a[31]rồi trả về
- Khi tìm được ký tự khớp, nó in
- Chuỗi
wordslà dữ liệu lời bài hát đã mã hóa sẽ được giải bằng mật mã thay thế- Cách viết thứ tự và các mảnh lời của từng khổ được ngăn cách bằng ký tự gạch chéo (
/)
- Cách viết thứ tự và các mảnh lời của từng khổ được ngăn cách bằng ký tự gạch chéo (
Vai trò của các nhánh đệ quy
- Nhánh
t < -72gọi lại hàm với hai đối số đầu bị hoán đổi và truyềnwordslàm đối số thứ ba- Mục đích chính là gây nhiễu, đồng thời cho phép đệ quy lồng nhau bỏ qua đối số thứ ba
- Nhánh
t < 0tìm dấu gạch chéo (/) thứ|t|trong chuỗi rồi truyền tiếp chuỗi bắt đầu từ ký tự ngay sau đó - Nhánh
t == 0giải mã và in chuỗi cho đến khi gặp dấu gạch chéo tiếp theo, rồi trả về1 - Nhánh
t == 1chỉ được gọi một lần lúc bắt đầu để khởi động phần đệ quy chính bằngxmas(2, 2, "%s") - Nhánh
t == 2in dòng đầu tiên theo mẫu"On the [ordinal] day of Christmas my true love gave to me\n" - Hai khối điều kiện cuối cùng duy trì đệ quy theo hai hướng
- Đi xuống từ ngày hiện tại để in lời của khổ tương ứng theo thứ tự ngược
- Tăng ngày lên cho đến ngày thứ 12 để lặp lại toàn bộ các khổ
Luồng thực thi hiện rõ sau khi đơn giản hóa
- Sau khi hiểu cách hoạt động, có thể chuyển nó thành mã đơn giản hơn bằng vòng lặp và các hàm thư viện chuỗi của C
- Ngay cả trong phiên bản đơn giản hóa, hai dữ liệu cốt lõi là
wordsvàshiftvẫn được giữ nguyên - Nhánh
t < 0dùngindex(a, '/')để tìm dấu phân cách gạch chéo và di chuyển tới vị trí của mảnh lời mong muốn - Nhánh
t == 0giải mã và in ký tự bằngindex(shift, *a++)[31] - Nhánh
t == 2in phần mở đầu của một khổ theo thứ tự sau"On the "- số thứ tự của ngày tương ứng
" my true love gave to me\n"
Vì sao kiểu làm rối này thú vị
- Khi được đơn giản hóa đến cùng, chương trình này có thể được rút gọn thành đoạn mã chỉ để in lời bài hát
- Bản gốc kết hợp mật mã thay thế với đệ quy để tạo ra cấu trúc phức tạp hơn rất nhiều so với việc in đơn thuần
- Những đoạn mã thừa nhỏ và các đối số ngẫu nhiên thực tế không được dùng đến khiến việc hiểu mã càng khó hơn
- Hiểu được nó và tự tay viết ra thứ tương tự là hai việc khác nhau; xmas.c được xem là một ví dụ sáng tạo về mã C
1 bình luận
Ý kiến trên Hacker News
Phía TeX cũng có một ví dụ tương tự là
xii.texĐặt nội dung này vào một tệp
.tex, chạypdftex, rồi xem PDF kết quả thì sẽ hiện ra thế này: https://shreevatsa.net/post/xii/Tôi đã tải về khi nó được công bố lần đầu, và khác với tên tệp trong bài này, tệp của tôi là
carol.cKhi biên dịch và chạy thử trên hệ thống hiện đại bằng
gcc -o carol carol.c, tôi gặp các cảnh báo nhưreturn type defaults to ‘int’,type of ‘t’ defaults to ‘int’,type of ‘_’ defaults to ‘int’intngầm định sẽ không còn được cho phép nữa: https://fedoraproject.org/wiki/Changes/PortingToModernC#Remo...main, hàmxmas()được gọi trước khi được định nghĩaNếu biên dịch bằng GCC trên macOS thì sẽ báo lỗi
ISO C99 and later do not support implicit function declarations; nếu chuyểnmain()xuống dưới thì nó biên dịch bình thường và cho ra đúng kết quảNhìn cái này làm tôi nghĩ đến độ phức tạp Kolmogorov
Chương trình này trông như lảm nhảm nhưng lại tạo ra đúng đầu ra mong muốn, nên tôi tự hỏi liệu có chương trình nào còn ngắn hơn, còn vô nghĩa hơn mà vẫn cho ra cùng kết quả không
Làm sao có thể tìm được những chương trình như vậy?
Nhưng tìm kiếm vét cạn là cực kỳ kém hiệu quả, nên câu trả lời thực tế gần với kiểu “hãy làm thật thông minh” theo nghĩa toán học
Nói chung, độ phức tạp Kolmogorov là không thể tính được, nên không thể tồn tại một chương trình nhận vào một chuỗi rồi trả về chương trình ngắn nhất tạo ra chuỗi đó
Tuy vậy, về nguyên tắc vẫn có thể chứng minh rằng độ phức tạp Kolmogorov của một chuỗi cụ thể là X
Vì thế nó rất hợp với các cuộc thi và cạnh tranh dài hạn, và do đường cong tăng trưởng theo log nên đôi khi có những phát hiện thú vị ở giai đoạn rất muộn
Hiện tôi đang tổ chức một mini contest kéo dài đến tháng 3 năm sau để xem LLM nào có thể thuộc được nhiều chữ số của số pi nhất; giải thưởng hiện là 100 USD và sẽ được chia theo tỷ lệ đóng góp trong không gian log
Về mặt lý thuyết, số pi có thể nén khá tốt, nên sẽ rất thú vị nếu xem liệu mô hình có thể học được một bộ trọng số gần với độ dài mô tả tối thiểu (MDL) để khôi phục một thuật toán nén mạnh từ dữ liệu hay không
Dù vậy, vẫn chưa rõ liệu các mô hình hiện có có làm được không, nên trước mắt cứ xem đây là một cuộc thi ghi nhớ chữ số rồi chờ xem
Phần giải thích rất hay, và có vẻ IOCCC vẫn còn sống tới tận năm 2023: https://www.ioccc.org/years.html
Tuy nhiên, trang chủ lại ghi trong bản cập nhật tháng 5/2023 rằng họ “dự định tổ chức IOCCC lần thứ 28”
Cũng có những thứ đáng để chờ như một bản phát hành Nethack vậy
Gần đây tôi mới biết một điều thú vị về The Twelve Days of Christmas: tất cả các món quà đều là một loại chim
Kể cả các quý cô đang nhảy hay các lãnh chúa cũng vậy
Theo Wikipedia, bản in lời bài hát sớm nhất được biết đến là cuốn sách minh họa dành cho trẻ em Mirth Without Mischief xuất bản tại London năm 1780: https://en.wikipedia.org/wiki/The_Twelve_Days_of_Christmas_(...
Trang này cố gắng gán tất cả với các loài chim https://www.birdspot.co.uk/culture/the-birds-of-the-twelve-d... nhưng đặc biệt là ở Five Gold Rings thì hơi gượng ép
Trong Mirth and Mischief có minh họa vẽ những chiếc nhẫn rất rõ là đồ trang sức, và trên Archive.org cũng có bản scan: https://archive.org/details/mirth_without_mischief/page/n7/m...
Đây là một nghiên cứu tôi tự làm từ hơn 20 năm trước: http://michaeldnahas.com/xmassong/index.html
Nếu tắt cảnh báo đi thì nó vẫn chạy cả trên trunk: https://compiler-explorer.com/z/hGvs1e9jo
Điều này gợi lại cho tôi một ký ức đẹp: vào năm 2022, trong hai học kỳ cuối ở đại học, giáo sư đã cho xem đoạn mã này ngay khi bắt đầu buổi giảng
Khó phân biệt là nói thật hay là kiểu hài tiết chế
Hồi đại học, giáo sư đã đưa cái này vào tài liệu in môn C, và tôi nhớ có lần đã tự tay gõ lại toàn bộ
Rosetta Code cũng có một bài tương tự
Đó là chương trình in ra bài hát lặp dần Old Lady Swallowed a Fly: https://rosettacode.org/wiki/Old_lady_swallowed_a_fly
puts [zlib inflate [binary decode base64 "7VRNa8MwDL3nV2(...)"]]https://rosettacode.org/wiki/Old_lady_swallowed_a_fly#Tcl
Có lẽ Python, Nim, Julia v.v. cũng có những phiên bản tương tự