commit 822ee5d4111928b6192b994cb209dac2a80a732a Author: niart120 <38847256+niart120@users.noreply.github.com> Date: Sat Dec 18 00:02:39 2021 +0900 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..510c73d --- /dev/null +++ b/.gitignore @@ -0,0 +1,114 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5980aef --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 niart120 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..42a5dec --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Project_Xs + diff --git a/munchlax/eye.png b/munchlax/eye.png new file mode 100644 index 0000000..6ff3025 Binary files /dev/null and b/munchlax/eye.png differ diff --git a/src/calc.py b/src/calc.py new file mode 100644 index 0000000..f9c82a4 --- /dev/null +++ b/src/calc.py @@ -0,0 +1,187 @@ +import numpy as np +from functools import reduce +from bisect import bisect + +def getZero(size=32): + return np.zeros((size,size),dtype="uint8") + +def getI(size=32): + return np.identity(size,dtype="uint8") + +def getShift(n,size=32): + return np.eye(size,k=n,dtype="uint8") + +def getTrans(): + t11,t12,t13,t14 = getZero(),getI(),getZero(),getZero() + t21,t22,t23,t24 = getZero(),getZero(),getI(),getZero() + t31,t32,t33,t34 = getZero(),getZero(),getZero(),getI() + t41,t42,t43,t44 = (getI()^getShift(-8))@(getI()^getShift(11))%2,getZero(),getZero(),getI()^getShift(-19) + + + trans = np.block([ + [t11,t12,t13,t14], + [t21,t22,t23,t24], + [t31,t32,t33,t34], + [t41,t42,t43,t44], + ]) + + return trans + +def getS(intervals): + intervals = intervals[:32] + t = getTrans() + t_ = getTrans() + + s = np.zeros((128,128),"uint8") + for i in range(32): + s[4*i:4*(i+1)] = t[-4:] + for j in range(intervals[i]): + t = t@t_%2 + return s + +def getS_munchlax(intervals): + intervals = intervals[::-1] + section = [0, 3.4333333333333336, 3.795832327504833, 3.995832327504833, 4.358332394560066, 4.558332394560066, 4.9208324616153, 5.120832461615299, 5.483332528670533, 5.683332528670532, 6.045832595725767, 6.2458325957257665, 6.608332662781, 6.808332662780999, 7.170832729836233, 7.370832729836232, 7.733332796891467, 7.933332796891467, 8.2958328639467, 8.4958328639467, 8.858332931001934, 9.058332931001933, 9.420832998057167, 9.620832998057166, 9.9833330651124, 10.1833330651124, 10.545833132167635, 10.745833132167634, 11.108333199222866, 11.308333199222865, 11.6708332662781, 11.8708332662781, 12.233333333333334,] + t = getTrans() + t_ = getTrans() + + s = np.zeros((128,128),"uint8") + safe_intervals = [] + for i in range(32): + #intervals[-1]を挿入した際のインデックスが奇数だと危険な値の可能性がある + is_carriable = bisect(section,intervals[-1])%2==1 + + while is_carriable: + #スキップする + t = t@t_%2 + #危険な値を除外 + intervals.pop() + is_carriable = bisect(section,intervals[-1])%2==1 + s[4*i:4*(i+1)] = t[105:109] + t = t@t_%2 + safe_intervals.append(intervals.pop()) + return s, safe_intervals + +def gauss_jordan(mat,observed:list): + r,c = mat.shape + assert r==c + + n = r + bitmat = [list2bitvec(mat[i]) for i in range(r)] + + res = [d for d in observed] + #forward elimination + pivot = 0 + for i in range(n): + isfound = False + for j in range(i,n): + if isfound: + check = 1<<(n-i-1) + if bitmat[j]&check==check: + bitmat[j] ^= bitmat[pivot] + res[j] ^= res[pivot] + else: + check = 1<<(n-i-1) + if bitmat[j]&check==check: + isfound = True + bitmat[j],bitmat[pivot] = bitmat[pivot],bitmat[j] + res[j],res[pivot] = res[pivot],res[j] + if isfound: + pivot += 1 + + #backward assignment + for i in range(1,n)[::-1]: + check = 1<<(n-i-1) + for j in range(i)[::-1]: + if bitmat[j]&check==check: + bitmat[j] ^= bitmat[i] + res[j] ^= res[i] + return res + +def getInverse(mat): + r,c = mat.shape + assert r==c + n = r + + res = [(1<>i)%2 for i in range(size)] + return np.array(lst[::-1]) + +def list2bitvec(lst): + bitvec = reduce(lambda p,q: (int(p)<<1)|int(q),lst) + return bitvec + +def reverseStates(rawblinks:list, intervals:list)->int: + blinks = [] + for b in rawblinks: + blinks.extend([0,0,0]) + blinks.append(b) + blinks = blinks[:128] + #print(blinks) + s = getS(intervals) + lst_result = gauss_jordan(s, blinks) + bitvec_result = list2bitvec(lst_result) + + result = [] + for i in range(4): + result.append(bitvec_result&0xFFFFFFFF) + bitvec_result>>=32 + + result = result[::-1]#reverse order + return result + +def reverseFloatRange(f:float,mi:float,ma:float): + norm_f = (ma-f)/(ma-mi) + norm_i = int(norm_f*8388607.0) + return int(norm_f*8388607.0)&0x7fffff + +def reverseStatesByMunchlax(intervals:list)->int: + s, safe_intervals = getS_munchlax(intervals) + bitvectorized_intervals = [reverseFloatRange(30.0*f,100,370)>>19 for f in safe_intervals] + bitlst_intervals = [] + for b in bitvectorized_intervals[::-1]: + for i in range(4): + bitlst_intervals.append(b&1) + b >>= 1 + bitlst_intervals = bitlst_intervals[::-1] + + bitvec_result = list2bitvec(gauss_jordan(s, bitlst_intervals)) + result = [] + for i in range(4): + result.append(bitvec_result&0xFFFFFFFF) + bitvec_result>>=32 + + result = result[::-1]#reverse order + return result \ No newline at end of file diff --git a/src/debug/expr.py b/src/debug/expr.py new file mode 100644 index 0000000..21107ec --- /dev/null +++ b/src/debug/expr.py @@ -0,0 +1,21 @@ +from xorshift import Xorshift +import secrets +import time +import calc + +def splitstate(state:int): + result = [] + for i in range(4): + result.append(state&0xFFFFFFFF) + state>>=32 + return result[::-1] + + +def main(): + prng = Xorshift(0x12,0x34,0x56,0x00) + for i in range(10): + print(*list(map(hex,prng.getState()))) + prng.prev() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/debug/naetoru.png b/src/debug/naetoru.png new file mode 100644 index 0000000..bda5444 Binary files /dev/null and b/src/debug/naetoru.png differ diff --git a/src/debug/test.py b/src/debug/test.py new file mode 100644 index 0000000..35e2b03 --- /dev/null +++ b/src/debug/test.py @@ -0,0 +1,63 @@ +import cv2 +import time + +def main(): + eye = cv2.imread("E:/documents/VSCodeWorkspace/Project_Xs/src/debug/naetoru.png",cv2.IMREAD_GRAYSCALE) + #video = cv2.VideoCapture("E:/documents/VSCodeWorkspace/Project_Xs/src/debug/naetoru_blink.mp4") + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + + IDLE = 0xFF + CLOSING = 0x0F + state = IDLE + intervals = [] + prev_time = 0 + + offset_time = 0 + fc = 0 + prev_fc = 0 + + prev_roi = None + + # 瞬きの観測 + while len(intervals)<3000: + ret, frame = video.read() + if not ret:break + + time_counter = time.perf_counter() + unix_time = time.time() + x,y = 830,460 + box_w,box_h = 120, 160 + roi = cv2.cvtColor(frame[y:y+box_h,x:x+box_w],cv2.COLOR_RGB2GRAY) + if (roi==prev_roi).all():continue + prev_roi = roi + fc += 1 + + res = cv2.matchTemplate(roi,eye,cv2.TM_CCOEFF_NORMED) + _, match, _, _ = cv2.minMaxLoc(res) + + if 0.40.5: + state = IDLE + if time_counter - prev_time>0.5: + state = IDLE + + cv2.destroyAllWindows() + print(intervals) +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/rngtool.py b/src/rngtool.py new file mode 100644 index 0000000..249b811 --- /dev/null +++ b/src/rngtool.py @@ -0,0 +1,168 @@ +from typing import List, Tuple +import time +import cv2 +from xorshift import Xorshift +import calc + +def randrange(r,mi,ma): + t = (r & 0x7fffff) / 8388607.0 + return t * mi + (1.0 - t) * ma + +def tracking_blink(roi_x=905, roi_y=750, roi_w=55, roi_h=55)->Tuple[List[int],List[int],float]: + """measuring the type and interval of player's blinks + + Returns: + blinks:List[int],intervals:list[int],offset_time:float: [description] + """ + IDLE = 0xFF + CLOSING = 0x0F + + eye = cv2.imread("./trainer/eye.png",cv2.IMREAD_GRAYSCALE) + + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + video.set(cv2.CAP_PROP_BUFFERSIZE,1) + + state = IDLE + blinks = [] + intervals = [] + prev_match = 0 + prev_time = 0 + + offset_time = 0 + + # 瞬きの観測 + while len(blinks)<40 or state==CLOSING: + ret, frame = video.read() + time_counter = time.perf_counter() + unix_time = time.time() + roi = cv2.cvtColor(frame[roi_y:roi_y+roi_h,roi_x:roi_x+roi_w],cv2.COLOR_RGB2GRAY) + res = cv2.matchTemplate(roi,eye,cv2.TM_CCOEFF_NORMED) + _, match, _, _ = cv2.minMaxLoc(res) + + delta = match - prev_match + prev_match = match + #cv2.imshow("",roi) + cv2.waitKey(1) + if 0.080.7: + state = IDLE + cv2.destroyAllWindows() + return (blinks, intervals, offset_time) + +def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[int],List[int],float]: + """measuring the type and interval of pokemon's blinks + + Returns: + intervals:list[int],offset_time:float: [description] + """ + IDLE = 0xFF + CLOSING = 0x0F + + eye = img + + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + video.set(cv2.CAP_PROP_BUFFERSIZE,1) + + state = IDLE + + intervals = [] + prev_roi = None + prev_time = time.perf_counter() + + offset_time = 0 + + # 瞬きの観測 + while len(intervals)0.7: + state = IDLE + if state==CLOSING and time_counter - prev_time>0.7: + state = IDLE + cv2.destroyAllWindows() + video.release() + return (intervals, offset_time) + +def recov(blinks:List[int],intervals:List[int])->Xorshift: + """ + Recover the xorshift from the type and interval of blinks. + + Args: + blinks (List[int]): + intervals (List[int]): + + Returns: + List[int]: internalstate + """ + advanced_frame = sum(intervals[1:]) + states = calc.reverseStates(blinks, intervals[1:]) + prng = Xorshift(*states) + states = prng.getState() + + #validation check + expected_blinks = [r&0xF for r in prng.getNextRandSequence(advanced_frame) if r&0b1110==0] + assert all([o==e for (o,e) in zip(blinks,expected_blinks)]) + + result = Xorshift(*states) + result.getNextRandSequence(len(rawintervals)) + return result + +def recovByMunchlax(rawintervals:List[float])->Xorshift: + advances = len(rawintervals) + intervals = [interval+0.048 for interval in rawintervals]#観測結果のずれを補正 + intervals = intervals[1:]#最初の観測結果はノイズなのでそれ以降を使う + states = calc.reverseStatesByMunchlax(intervals) + + prng = Xorshift(*states) + states = prng.getState() + + #validation check + expected_intervals = [randrange(r,100,370)/30 for r in prng.getNextRandSequence(advances)] + + paired = list(zip(intervals,expected_intervals)) + #print(paired) + + assert all([abs(o-e)<0.1 for o,e in paired]) + result = Xorshift(*states) + result.getNextRandSequence(len(intervals)) + return result \ No newline at end of file diff --git a/src/tidsid.py b/src/tidsid.py new file mode 100644 index 0000000..0a67bcc --- /dev/null +++ b/src/tidsid.py @@ -0,0 +1,121 @@ +import rngtool +import calc +import cv2 +import time +from xorshift import Xorshift + +def randrange(r,mi,ma): + t = (r & 0x7fffff) / 8388607.0 + return t * mi + (1.0 - t) * ma + +def getids(r): + g7tid = ((r%0xFFFFFFFF+0x80000000)&0xFFFFFFFF)%1000000 + tid,sid = r&0xFFFF, r>>16 + return g7tid, tid, sid + +def generate_dangerintervals_list(k): + lst = [] + for b in range(1<>16 + if g7tid==playerid: + print(f"backwarding {i},", hex(tid),hex(sid)) + break + + randlist = prng.getPrevRandSequence(100) + expected_intervals = [randrange(r,100.0,370.0)/30.0 for r in randlist] + + print(f"observed:{gombe_intervals[::-1]}") + print(f"expected:{expected_intervals}") + +def main(): + blinks, intervals, offset = rngtool.tracking_blink() + prng = rngtool.recov(blinks,intervals) + print(f"state:{prng.getState()}") + print("input trainer ID") + playerid = int(input()) + + for i in range(10000): + r = prng.prev() + g7tid = ((r%0xffffffff+0x80000000)&0xFFFFFFFF)%1000000 + tid,sid = r&0xFFFFFFFF, r>>16 + if g7tid==playerid: + print(f"backwarding {i},", hex(tid),hex(sid)) + break + randlist = prng.getPrevRandSequence(100) + expected_intervals = [randrange(r,100.0,370.0)/30.0 for r in randlist] + + print(f"expected:{expected_intervals}") + +if __name__ == "__main__": + expr() \ No newline at end of file diff --git a/trainer/eye.png b/trainer/eye.png new file mode 100644 index 0000000..1b9f955 Binary files /dev/null and b/trainer/eye.png differ