Skip to content

Instantly share code, notes, and snippets.

@jaredliw
Last active March 14, 2022 12:49
Show Gist options
  • Save jaredliw/785a7775c5afeae7711a80bcf4215c52 to your computer and use it in GitHub Desktop.
Save jaredliw/785a7775c5afeae7711a80bcf4215c52 to your computer and use it in GitHub Desktop.
A handy script for Juejin ShuZiMiTi
#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;
}
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)
@jaredliw
Copy link
Author

Refer to this article for more: https://juejin.cn/post/7068934579410698270

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment