Last active
March 14, 2022 12:49
-
-
Save jaredliw/785a7775c5afeae7711a80bcf4215c52 to your computer and use it in GitHub Desktop.
A handy script for Juejin ShuZiMiTi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <math.h> | |
#include <string.h> | |
#include <stdio.h> | |
int calc(int num1, int sym, int num2) { | |
int offset = num2 != 0 ? log10(num2) + 1 : 1; | |
switch (sym) { | |
case 0: | |
return num1 + num2; | |
case 1: | |
return num2 > num1 ? num2 - num1 : -1; | |
case 2: | |
return num1 * num2; | |
case 3: | |
return num2 != 0 && num1 % num2 == 0 ? num1 / num2 : -1; | |
case 4: | |
return num1 * pow(10, offset) + num2; | |
default: | |
return -1; | |
} | |
} | |
int* brute_force(int target, | |
int nums[], int n_size, | |
int symbols[], int s_size, | |
int history[], int h_size) { | |
if (n_size == 1 && s_size == 0 && nums[0] == target) { | |
return history; | |
} | |
for (int symbol = 0; symbol < 5; symbol++) { | |
int symbols_copied[s_size - 1]; | |
int once = 1; | |
int ptr = 0; | |
for (int idx = 0; idx < s_size; idx++) { | |
if (symbols[idx] == symbol && once) { | |
once = 0; | |
continue; | |
} | |
symbols_copied[ptr++] = symbols[idx]; | |
} | |
if (once == 1){ | |
continue; | |
} | |
for (int num1_idx = 0; num1_idx < n_size - 1; num1_idx++) { | |
for (int num2_idx = num1_idx + 1; num2_idx < n_size; num2_idx++) { | |
for (int idx = 0; idx < 2; idx++) { | |
int num1 = nums[num1_idx]; | |
int num2 = nums[num2_idx]; | |
int result = calc(num1, symbol, num2); | |
if (result != -1) { | |
int numbers_copied[n_size - 1]; | |
numbers_copied[0] = result; | |
int ptr = 1; | |
for (int idx = 0; idx < n_size; idx++) { | |
if (idx == num1_idx || idx == num2_idx) { | |
continue; | |
} | |
numbers_copied[ptr++] = nums[idx]; | |
} | |
int history_copied[h_size + 3]; | |
for (int idx = 0; idx < h_size; idx++) { | |
history_copied[idx] = history[idx]; | |
} | |
history_copied[h_size] = num1; | |
history_copied[h_size + 1] = symbol; | |
history_copied[h_size + 2] = num2; | |
int* ret = brute_force(target, | |
numbers_copied, n_size - 1, | |
symbols_copied, s_size - 1, | |
history_copied, h_size + 3); | |
if (ret != NULL) { | |
return ret; | |
} | |
} | |
if ((symbol == 1 || symbol == 3 || symbol == 4) && num1 != num2) { | |
num1_idx ^= num2_idx; | |
num2_idx ^= num1_idx; | |
num1_idx ^= num2_idx; | |
} | |
} | |
} | |
} | |
} | |
return NULL; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from ctypes import CDLL, c_uint, POINTER | |
from itertools import chain | |
from pathlib import Path | |
from time import time, sleep | |
from typing import List, Literal, Tuple, Union | |
from jwt import decode | |
from requests import post, RequestException, get | |
VALID_OPERATIONS = ("+", "-", "*", "/", "&") | |
GET_TOKEN_URL = "https://juejin.cn/get/token" | |
GAME_URL = "https://juejin-game.bytedance.com/game/num-puzz/ugc/start" | |
SO_FILENAME = "puzzle.so" | |
try: | |
C_LIB = CDLL(str(Path(__file__).resolve().parent / SO_FILENAME)) | |
except FileNotFoundError: | |
raise FileNotFoundError(f"file '{SO_FILENAME}' not found, please make sure that you have compiled the script into " | |
f".so file using the following command: gcc -shared -o puzzle.so -fPIC puzzle.c") from None | |
class JuejinError(RequestException): | |
pass | |
def brute_force(target: int, nums: List[int], syms: List[Literal[0, 1, 2, 3, 4]]) \ | |
-> List[Tuple[int, Literal["+", "-", "*", "/", "&"], int]]: | |
if not all(map(lambda x: isinstance(x, int), nums)): | |
raise ValueError("'nums' should only be comprised of integers") | |
if not all(map(lambda x: 0 <= x < len(VALID_OPERATIONS), syms)): | |
raise ValueError(f"'syms' contains invalid value") | |
if not isinstance(target, int): | |
raise TypeError(f"'target' should be '{int.__name__}', not {type(target).__name__}") | |
nums_length = len(nums) | |
c_nums = (c_uint * nums_length)(*nums) | |
syms_length = len(nums) - 1 | |
syms.extend([4] * (syms_length - len(syms))) | |
c_syms = (c_uint * syms_length)(*syms) | |
history_length = 0 | |
c_history = (c_uint * history_length)() | |
C_LIB.brute_force.restype = POINTER(c_uint * (syms_length * 3)) | |
try: | |
result = list(C_LIB.brute_force(target, | |
c_nums, nums_length, | |
c_syms, syms_length, | |
c_history, history_length).contents) | |
except ValueError as e: | |
if str(e) == "NULL pointer access": | |
raise ValueError("puzzle not solvable; If you think this is a bug, please report to the author") from None | |
raise e | |
formatted = [] | |
for idx in range(0, syms_length * 3, 3): | |
num1, symbol, num2 = result[idx:idx + 3] | |
symbol = VALID_OPERATIONS[symbol] | |
formatted.append([num1, symbol, num2]) | |
return formatted | |
def get_token_and_uid(session_id: str) -> Tuple[str, str]: | |
response = get(GET_TOKEN_URL, cookies={ | |
"sessionid": session_id | |
}).json() | |
try: | |
token = response["data"] | |
except: | |
raise JuejinError(response["err_msg"]) from None # Suppress the context being printed | |
try: | |
uid = decode(token, options={"verify_signature": False})["userId"] | |
except: | |
raise ValueError("invalid token") | |
return token, uid | |
def fetch_data(token: str, uid: str) -> dict: | |
response = post(GAME_URL, headers={ | |
"authorization": "Bearer " + token | |
}, params={ | |
"uid": uid, | |
"time": int(time() * 1000) | |
}).json() | |
try: | |
return response["data"] | |
except KeyError: | |
raise JuejinError(response["message"]) from None | |
def resolve_map(game_map: List[List[Union[int, float]]]) -> Tuple[List[int], List[Literal[1, 2, 3, 4]]]: | |
nums = [] | |
syms = [] | |
for item in chain(*game_map): | |
if isinstance(item, int): | |
nums.append(item) | |
elif item == 0.3: | |
syms.append(0) | |
elif item == 0.4: | |
syms.append(1) | |
elif item == 0.5: | |
syms.append(2) | |
elif item == 0.6: | |
syms.append(3) | |
return nums, syms | |
if __name__ == "__main__": | |
# Edit here | |
MY_SESSION_ID = "xxx" | |
TOKEN, UID = get_token_and_uid(MY_SESSION_ID) | |
last_level = None | |
while True: | |
data = fetch_data(TOKEN, UID) | |
level = data["round"] | |
if last_level != level: | |
print("Level", level) | |
print() | |
for step in brute_force(data["target"], *resolve_map(data["map"])): | |
print(*step) | |
print() | |
last_level = level | |
sleep(3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Refer to this article for more: https://juejin.cn/post/7068934579410698270