JavaScript (ES7), 121 117 byte
x=>(a=b=0,[for(c of x)for(d of'1234')(e=c.charCodeAt()/26|0)==d?a^=1<<d:b^=(a>>d&1)<<d*4+e],f=y=>y&&y%2+f(y>>1))(b)/2
Ồ Đó là niềm vui. Tôi đã phác thảo một ý tưởng trả lời khi thử thách này lần đầu tiên xuất hiện, nhưng nó dài hơn 150 byte và tôi không muốn nỗ lực để chơi nó. Tôi đã chạy qua ý tưởng này trong cuốn sổ tay của mình ngày hôm qua và quyết định tôi sẽ không ngừng nghĩ về nó cho đến khi tôi hoàn toàn đánh golf nó. Cuối cùng tôi đã viết ra hai thuật toán hoàn toàn mới, thuật toán đầu tiên kết thúc ngắn hơn vài byte sau khi đánh gôn khoảng 25 byte với hàng tấn hack.
Làm thế nào nó hoạt động
Đầu tiên chúng ta đặt biến a
và b
thành 0
. a
là mảng nhị phân 4 bit trong đó các cặp khung mà chúng ta hiện đang ở bên trong và b
là mảng nhị phân 16 bit trong đó các cặp khung được liên kết với nhau.
Tiếp theo, chúng ta lặp qua từng nhân vật c
trong x
, và mỗi char d
trong '0123'
. Đầu tiên chúng tôi xác định loại khung c
là với e=c.charCodeAt()/26-1|0
. Mã char thập phân của từng loại khung như sau:
() => 40,41
<> => 60,62
[] => 91,93
{} => 123,125
Bằng cách chia cho 26, trừ 1 và sàn, chúng tôi ánh xạ các giá trị này thành 0, 1, 2 và 3 tương ứng.
Tiếp theo chúng tôi kiểm tra xem con số này có bằng giá trị hiện tại của không d
. Nếu đúng như vậy, chúng ta đang nhập hoặc thoát khỏi d
loại khung thứ, vì vậy chúng ta lật d
bit thứ a
với a^=1<<d
. Nếu không, nhưng chúng ta nằm trong d
loại khung thứ, chúng ta cần lật e
bit thứ trong phần d
4 bit của b
. Điều này được thực hiện như vậy:
b^=(a>>d&1)<<d*4+e
(a>>d&1)
Trả về d
bit thứ trong a
. Nếu chúng ta ở trong d
loại khung thứ, điều này trả về 1; mặt khác, nó trả về 0. Tiếp theo, chúng ta thay đổi kết quả này theo d*4+e
bit và XOR b
theo kết quả. Nếu chúng ta ở trong d
kiểu khung thứ, thì XOR này là d*4+e
bit thứ của b
; mặt khác, nó không làm gì cả
Khi kết thúc tất cả các vòng lặp, b
sẽ chứa một số bit 1 bằng hai lần giá trị trả về mong muốn. Nhưng chúng ta vẫn cần tính xem có bao nhiêu bit. Đó là nơi chức năng phụ f
xuất hiện:
f=y=>y&&y%2+f(y>>1)
Nếu y
là 0, điều này chỉ đơn giản trả về 0. Nếu không, nó sẽ lấy bit cuối cùng y
với y%2
, sau đó thêm kết quả của việc chạy tất cả trừ bit cuối cùng y
thông qua hàm một lần nữa. Ví dụ:
f(y) => y && y%2 + f(y>>1)
f(0b1001101) => 1 + f(0b100110) = 4
f(0b100110) => 0 + f(0b10011) = 3
f(0b10011) => 1 + f(0b1001) = 3
f(0b1001) => 1 + f(0b100) = 2
f(0b100) => 0 + f(0b10) = 1
f(0b10) => 0 + f(0b1) = 1
f(0b1) => 1 + f(0b0) = 1
f(0b0) => 0 = 0
Chúng tôi chạy b
qua chức năng này và chia kết quả cho 2, và đó là câu trả lời của chúng tôi.