mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-19 12:58:04 +00:00
223 lines
9.7 KiB
Python
Executable file
223 lines
9.7 KiB
Python
Executable file
from .BaseCipherEnvironment import BaseCipherEnvironment
|
|
|
|
|
|
import random
|
|
from typing import Callable, List
|
|
import functools
|
|
|
|
LETTERS = ['J', 'D', 'W', 'O', 'T', 'R', 'A', 'C', 'X', 'Q', 'M', 'F', 'Y',
|
|
'E', 'Z', 'G', 'U', 'K', 'P', 'V', 'B', 'S', 'H', 'N', 'L', 'I']
|
|
|
|
LETTER_TO_NUM_MAP = {}
|
|
for i, letter in enumerate(LETTERS):
|
|
LETTER_TO_NUM_MAP[letter] = i
|
|
|
|
input_key = [9, 25, 44, 38, 40, 22, 11, 36, 13, 39, 18, 42, 10, 53, 26, 12, 1, 16, 3, 43, 37, 17, 30, 4, 28, 48, 27, 41, 32, 15, 47, 29, 20, 51, 6, 7, 52, 34, 35, 5, 50, 9, 54, 46, 23, 31, 24, 14, 8, 33, 2, 49, 45, 21]
|
|
|
|
|
|
def move_joker_a(cards: List[int]) -> list:
|
|
return move_joker(len(cards) - 1, cards)
|
|
|
|
def move_joker_b(cards: List[int]) -> list:
|
|
return move_joker(len(cards), cards)
|
|
|
|
def move_joker(joker: int, cards: List[int]) -> List[int]:
|
|
def wraparound(n: int) -> int:
|
|
if n >= len(cards):
|
|
return n % len(cards) + 1
|
|
return n
|
|
|
|
cards = list(cards)
|
|
jump = 2 if joker is len(cards) else 1
|
|
index = cards.index(joker)
|
|
cards.insert(wraparound(index + jump), cards.pop(index))
|
|
return cards
|
|
|
|
def triple_cut_by_jokers(cards: List[int]) -> list:
|
|
joker_a = len(cards) - 1
|
|
joker_b = len(cards)
|
|
return triple_cut((cards.index(joker_a), cards.index(joker_b)), cards)
|
|
|
|
def triple_cut(cut_indices: tuple, cards: list) -> List[int]:
|
|
lower, higher = sorted(cut_indices)
|
|
return cards[higher + 1:] + cards[lower:higher + 1] + cards[:lower]
|
|
|
|
def count_cut(cards: List[int]) -> List[int]:
|
|
last = len(cards) - 1
|
|
value = cards[last]
|
|
if is_joker(value, cards):
|
|
return list(cards)
|
|
return cards[value:last] + cards[:value] + [cards[last]]
|
|
|
|
def get_keystream_value(cards: List[int]) -> int:
|
|
index = cards[0] if not is_joker(cards[0], cards) else len(cards) - 1
|
|
return cards[index]
|
|
|
|
def is_joker(value: int, cards: List[int]) -> bool:
|
|
return value > len(cards) - 2
|
|
|
|
|
|
class KorSolitaireCipherEnvironment(BaseCipherEnvironment):
|
|
def __init__(self, *args, **kwargs):
|
|
problem_description = "Solitaire Cipher from kor-bench"
|
|
super().__init__(problem_description, *args, **kwargs)
|
|
|
|
@property
|
|
def cipher_name(self) -> str:
|
|
return "Kor_rule6_SolitaireCipher"
|
|
|
|
def encode(self, text, **kwargs):
|
|
# 将输入转换为大写字母,去除标点和空格
|
|
text = ''.join([c.upper() for c in text if c.isalpha()])
|
|
print(f"处理后的输入文本: {text}")
|
|
|
|
print("开始加密过程:")
|
|
cards = list(input_key)
|
|
output = []
|
|
|
|
for i, char in enumerate(text):
|
|
print(f"\n处理第{i+1}个字符 '{char}':")
|
|
# 获取字母位置值
|
|
x = LETTER_TO_NUM_MAP[char]
|
|
print(f"字符'{char}'在字母表中的位置是: {x}")
|
|
|
|
# 生成密钥流值
|
|
print("生成密钥流值:")
|
|
print("1. 移动A王牌下移一位")
|
|
cards = move_joker_a(cards)
|
|
print("2. 移动B王牌下移两位")
|
|
cards = move_joker_b(cards)
|
|
print("3. 以王牌为界进行三切")
|
|
cards = triple_cut_by_jokers(cards)
|
|
print("4. 根据底牌进行计数切牌")
|
|
cards = count_cut(cards)
|
|
|
|
y = get_keystream_value(cards)
|
|
while is_joker(y, cards):
|
|
print("获得的是王牌值,重新生成密钥流值")
|
|
cards = move_joker_a(cards)
|
|
cards = move_joker_b(cards)
|
|
cards = triple_cut_by_jokers(cards)
|
|
cards = count_cut(cards)
|
|
y = get_keystream_value(cards)
|
|
|
|
print(f"生成的密钥流值是: {y}")
|
|
|
|
# 计算加密位置
|
|
z = (x + y) % 26
|
|
print(f"加密计算: ({x} + {y}) % 26 = {z}")
|
|
|
|
# 获取加密字母
|
|
cipher_char = LETTERS[z]
|
|
print(f"加密后的字符是: {cipher_char}")
|
|
output.append(cipher_char)
|
|
|
|
result = ''.join(output)
|
|
print(f"\n最终加密结果: {result}")
|
|
return result
|
|
|
|
def decode(self, text, **kwargs):
|
|
print(f"开始解密密文: {text}")
|
|
|
|
cards = list(input_key)
|
|
output = []
|
|
|
|
for i, char in enumerate(text):
|
|
print(f"\n处理第{i+1}个字符 '{char}':")
|
|
# 获取密文字母位置
|
|
z = LETTER_TO_NUM_MAP[char]
|
|
print(f"密文字符'{char}'在字母表中的位置是: {z}")
|
|
|
|
# 生成密钥流值
|
|
print("生成密钥流值:")
|
|
print("1. 移动A王牌下移一位")
|
|
cards = move_joker_a(cards)
|
|
print("2. 移动B王牌下移两位")
|
|
cards = move_joker_b(cards)
|
|
print("3. 以王牌为界进行三切")
|
|
cards = triple_cut_by_jokers(cards)
|
|
print("4. 根据底牌进行计数切牌")
|
|
cards = count_cut(cards)
|
|
|
|
y = get_keystream_value(cards)
|
|
while is_joker(y, cards):
|
|
print("获得的是王牌值,重新生成密钥流值")
|
|
cards = move_joker_a(cards)
|
|
cards = move_joker_b(cards)
|
|
cards = triple_cut_by_jokers(cards)
|
|
cards = count_cut(cards)
|
|
y = get_keystream_value(cards)
|
|
|
|
print(f"生成的密钥流值是: {y}")
|
|
|
|
# 计算原文位置
|
|
x = (z - y) % 26
|
|
print(f"解密计算: ({z} - {y}) % 26 = {x}")
|
|
|
|
# 获取原文字母
|
|
plain_char = LETTERS[x]
|
|
print(f"解密后的字符是: {plain_char}")
|
|
output.append(plain_char)
|
|
|
|
result = ''.join(output)
|
|
print(f"\n最终解密结果: {result}")
|
|
return result
|
|
|
|
def get_encode_rule(self, ):
|
|
return """加密规则:
|
|
- 输入:
|
|
- 明文: 大写字母字符串,不含标点和空格
|
|
- 输出:
|
|
- 密文: 大写字母字符串
|
|
- 准备:
|
|
- LETTERS = ['J', 'D', 'W', 'O', 'T', 'R', 'A', 'C', 'X', 'Q', 'M', 'F', 'Y', 'E', 'Z', 'G', 'U', 'K', 'P', 'V', 'B', 'S', 'H', 'N', 'L', 'I']
|
|
- 将每个字母与其在LETTERS中的位置关联(从0开始):
|
|
J->0, D->1, W->2, O->3, T->4, R->5, A->6, C->7, X->8, Q->9, M->10, F->11, Y->12, E->13, Z->14, G->15, U->16, K->17, P->18, V->19, B->20, S->21, H->22, N->23, L->24, I->25
|
|
- 初始卡牌序列:
|
|
- 54张卡牌的列表,包括52张花色牌和2张可区分的王牌(A王牌和B王牌)。花色牌按四种花色顺序编号1-52,王牌值为53和54。
|
|
- [9, 25, 44, 38, 40, 22, 11, 36, 13, 39, 18, 42, 10, 53, 26, 12, 1, 16, 3, 43, 37, 17, 30, 4, 28, 48, 27, 41, 32, 15, 47, 29, 20, 51, 6, 7, 52, 34, 35, 5, 50, 9, 54, 46, 23, 31, 24, 14, 8, 33, 2, 49, 45, 21]
|
|
- 密钥流算法:
|
|
该算法通过移动卡牌生成密钥流值。算法是确定性的,意味着密钥流值仅取决于卡牌的初始顺序。卡牌组被视为循环数组,允许需要移到底部的卡牌绕到顶部。
|
|
|
|
执行以下步骤生成密钥流的一个字符:
|
|
1. 找到A王牌并下移一位。如果是最后一张牌,则成为第二张牌。不能成为第一张牌。
|
|
2. 找到B王牌并下移两位。如果是倒数第二张牌,则绕到第二位。如果是最后一张牌,则成为第三张牌。不能成为第一张牌。
|
|
3. 进行"三切":用王牌作为边界将牌组分成三部分,然后交换顶部和底部。王牌本身及其之间的牌保持不变。
|
|
4. 进行"计数切":检查牌组底牌。如果是王牌(53/54),其值固定为53。从牌组顶部取出该数量的牌,插入到最后一张牌的上方。
|
|
5. 查看顶牌的值。同样,任何王牌计为53。计算该牌下方的位置数,使用该位置的牌值作为下一个密钥流值。如果计算出的牌是王牌,忽略它并重复密钥流算法。
|
|
6. 返回生成的密钥流值
|
|
- 加密步骤:
|
|
- cards=初始卡牌序列
|
|
- 对每个明文字符p:
|
|
- 使用字母表将p转换为对应的位置值x(从0开始)
|
|
- 使用初始卡牌序列为p生成密钥流值y:
|
|
- y, cards = 密钥流算法(cards)
|
|
- 该算法修改卡牌顺序,下次执行使用新顺序
|
|
- 当密钥流值y加到位置值x时,应用模26运算得到z:
|
|
- z=(y+x) % 26
|
|
- 使用LETTERS列表返回对应位置z的字母
|
|
- 将其附加到密文"""
|
|
|
|
def get_decode_rule(self, ):
|
|
return """解密规则:
|
|
- 输入:
|
|
- 密文: 大写字母字符串
|
|
- 输出:
|
|
- 明文: 大写字母字符串
|
|
- 准备:
|
|
- LETTERS = ['J', 'D', 'W', 'O', 'T', 'R', 'A', 'C', 'X', 'Q', 'M', 'F', 'Y', 'E', 'Z', 'G', 'U', 'K', 'P', 'V', 'B', 'S', 'H', 'N', 'L', 'I']
|
|
- 将每个字母与其在LETTERS中的位置关联(从0开始):
|
|
J->0, D->1, W->2, O->3, T->4, R->5, A->6, C->7, X->8, Q->9, M->10, F->11, Y->12, E->13, Z->14, G->15, U->16, K->17, P->18, V->19, B->20, S->21, H->22, N->23, L->24, I->25
|
|
- 初始卡牌序列(与加密相同)
|
|
- 密钥流算法(与加密相同)
|
|
- 解密步骤(与加密步骤完全相反):
|
|
- cards=初始卡牌序列
|
|
- 对每个密文字符c:
|
|
- 使用LETTERS将c转换为对应的位置值z(从0开始)
|
|
- 为c生成密钥流值y:
|
|
- y, cards = 密钥流算法(cards)
|
|
- 该算法修改卡牌顺序,下次执行使用新顺序
|
|
- 从密文字符c计算原始位置值x:
|
|
- x=(z-y) mod 26
|
|
- 使用LETTERS列表返回对应位置x的字母
|
|
- 将其附加到解密明文"""
|