祕密

祕密

學習練習

簡介

Crystal 提供了位元運算子,可以在二進位層級操作 Int。

位移運算子

Crystal 提供了位移運算子,可以將位元向左(<<)或向右(>>)位移。

左移(<<)

左移運算子(<<)會將位元向左位移。 要位移的值放在左邊,要位移的位數放在右邊。

0b0010 << 1
# => 0b0100

0b0010 << 2
# => 0b1000

如果數字是負數,就會改為向右位移。

0b0010 << -1
# => 0b0001

右移(>>)

右移運算子(>>)會將位元向右位移。 和左移運算子一樣,要位移的值放在左邊,要位移的位數放在右邊。

0b0100 >> 1
# => 0b0010

0b0100 >> 2
# => 0b0001

同樣地,如果數字是負數,運算子就會改為向左位移。

0b0100 >> -1
# => 0b1000

二元運算子

Crystal 有 3 個二元運算子(&、|、^),以及一個用來執行位元運算的 ~ 運算子。

位元 AND(&)

二元 AND 運算子(&)會對兩個值執行位元 AND 運算。 它會把第一個值的每個位元,和第二個值中相同位置的位元做比較。 如果兩個位元都是 1,結果位元就會設為 1,否則設為 0。

0b0011 & 0b1010
# => 0b0010

位元 OR(|)

二元 OR 運算子(|)會對兩個值執行位元 OR 運算。 它同樣會比較第一個值的每個位元,和第二個值中相同位置的位元。 只要其中一個位元是 1,結果位元就會設為 1,否則設為 0。

0b0011 | 0b1010
# => 0b1011

位元 XOR(^)

二元 XOR 運算子(^)會執行位元 XOR 運算。 和位元 AND、位元 OR 運算子一樣,它會把第一個值的每個位元,和第二個值中相同位置的位元做比較。 如果兩者中_只有一個_是 1,結果位元就是 1,否則就是 0。

0b0011 ^ 0b1010
# => 0b1001

位元 NOT(~)

最後,位元 NOT 運算子(~)會翻轉值的每個位元。 和其他二元運算子不同,這是一元運算子,只對右邊的值運作。

~0b1110_0010
# => 0b0001_1101

說明

有人剛傳了一則帶有重要秘密的訊息給你。 對方不想讓其他人輕易讀到內容,所以這則訊息經過一連串位元操作加密。 你需要寫一個程式來協助解密這則訊息。

1. 把位元移回去

解密訊息的第一步,是把加密過程中做的位移還原,也就是把位元往左移回去。 每則訊息需要位移的位數可能不同。

實作 Secrets.shift_back方法,它接受一個值和要往左位移的位數。

Secrets.shift_back(0b0001, 2)
# => 0b0100

2. 套用位元遮罩

下一步是套用位元遮罩,取出特定幾個位元的值。 遮罩的套用方式是對值和遮罩做位元 AND 運算。

實作 Secrets.apply_mask方法,它接受一個值並套用遮罩。

Secrets.apply_mask(0b0110, 0b0101)
# => 0b0100

3. 設定部分位元

把位元往左移之後,會多出一些新的 0 位元。 其中有些新的位元需要設成 1。 位元 OR 很適合用來把特定幾個位元設成 1,同時保留其他位元。

實作 Secrets.set_bits方法,它接受兩個值並執行位元 OR。

Secrets.set_bits(0b0110, 0b0101)
# => 0b111

4. 反向 XOR

加密過程的其中一個步驟,是對一個雙方講好的值做 XOR。 要還原成原始的值,只要把加密後的值再跟講好的值做一次 XOR 就行了。 不過,因為一場誤會,你的朋友在套用 XOR 之前,先把講好的值的位元翻轉了(也就是對講好的值做了位元 NOT)。

實作 Secrets.reverse_xor方法,它接受加密後的值和講好的值,算出原始的值。

Secrets.reverse_xor(0b1100, 0b0101)
# => 0b(0110)
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Crystal Exercism

準備好開始 祕密 了嗎?

註冊 Exercism,透過 26 個概念142 個練習 和真人引導來學習並精通 Crystal,全部免費。