Files
CoCoCapitalQuiz/tests/framebuffer.py
T

66 lines
2.5 KiB
Python

import struct,zlib,re,json,runpy,sys,uuid,os,tempfile
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
EVIDENCE=Path(os.environ['CAPITAL_TEST_EVIDENCE'])
S=json.load(open(os.environ['CAPITAL_TEST_STATE']))
ART=next(Path(tempfile.gettempdir()).glob('vcc-c-project-*/Builds/'+S['artifact']['artifact_id']+'/build/CAPITAL.bin'))
mp=ART.with_suffix('.map').read_text()
addr=int(re.search(r'Symbol: _font5x8 .*?= ([0-9A-Fa-f]+)',mp)[1],16)
blob=ART.read_bytes();memory={};p=0
while p<len(blob):
t=blob[p];n,a=struct.unpack('>HH',blob[p+1:p+5]);p+=5
if t==255:break
for i,b in enumerate(blob[p:p+n]):memory[a+i]=b
p+=n
font=bytes(memory[addr+i] for i in range(768))
def png(path):
b=Path(path).read_bytes();p=8;dat=b''
while p<len(b):
n=int.from_bytes(b[p:p+4],'big');t=b[p+4:p+8];v=b[p+8:p+8+n];p+=n+12
if t==b'IHDR':w,h,depth,ct,*_=struct.unpack('>IIBBBBB',v)
if t==b'IDAT':dat+=v
assert depth==8 and ct in (2,6),(depth,ct)
channels=3 if ct==2 else 4;stride=w*channels;raw=zlib.decompress(dat);out=[];prior=bytearray(stride);p=0
for y in range(h):
f=raw[p];p+=1;row=bytearray(raw[p:p+stride]);p+=stride
for i in range(stride):
a=row[i-channels] if i>=channels else 0;b=prior[i];c=prior[i-channels] if i>=channels else 0
if f==1:pred=a
elif f==2:pred=b
elif f==3:pred=(a+b)//2
elif f==4:
v=a+b-c;pa=abs(v-a);pb=abs(v-b);pc=abs(v-c);pred=a if pa<=pb and pa<=pc else b if pb<=pc else c
else:pred=0
row[i]=(row[i]+pred)&255
out.append(row);prior=row
return w,h,channels,out
class Screen:
def __init__(self,path):self.w,self.h,self.ch,self.rows=png(path)
def pixel(self,x,y):return tuple(self.rows[y][x*self.ch:x*self.ch+3])
def guest(self,x,y):return self.pixel(x*2,50+y*2)
def text(self,x,y,n,color=None):
bg=self.guest(x+5,y);out=''
for j in range(n):
bits=[]
for row in range(8):
for col in range(5):bits.append(self.guest(x+j*6+col,y+row)==color if color else self.guest(x+j*6+col,y+row)!=bg)
scores=[]
for c in range(32,127):
expected=[not(font[(c-32)*8+r]&(128>>co)) for r in range(8) for co in range(5)]
scores.append((sum(a!=b for a,b in zip(bits,expected)),c))
d,c=min(scores);out+=chr(c) if d==0 else '?'
return out.rstrip()
def shuffle(seed=2709):
rng=seed
def rand(n):
nonlocal rng
while True:
x=rng;x^=x<<7;x&=65535;x^=x>>9;x^=x<<8;x&=65535;rng=x;x-=1
if x<65535-65535%n:return x%n
order=list(range(50))
for i in range(49,0,-1):j=rand(i+1);order[i],order[j]=order[j],order[i]
return order,rand