import os import multiprocessing import threading import logging as log import PIL from util import MsgQueue from gui import gui from imageanalyzer import ImageAnalyzer from go import Go, isLegalPosition from statebag import StateBag import config as cfg class Core: def __init__(self): self.grid=None self.go=Go() self.detector=ImageAnalyzer() self.states=StateBag() self._ownMessages=MsgQueue(self._handleEvent) self._guiMessages=MsgQueue() self._imgDir=os.path.join(os.path.dirname(__file__), "..","images") self._imgs=sorted(os.listdir(self._imgDir)) self._imgIndex=cfg.misc.defaultImage imgPath=os.path.join(self._imgDir,self._imgs[self._imgIndex]) self._frame=PIL.Image.open(imgPath) self._guiProc=multiprocessing.Process(name="gui", target=gui, args=(self._guiMessages,self._ownMessages)) self._guiProc.start() self.relativeFrame(0) def setCorners(self,corners): self.detector.setGridCorners(corners) self.analyze() def setTresholds(self,tresB=None,tresW=None): if tresB is not None: self.detector.tresB=tresB if tresW is not None: self.detector.tresW=tresW self.analyze() def relativeFrame(self,step): self._imgIndex=(self._imgIndex+step)%len(self._imgs) imgPath=os.path.join(self._imgDir,self._imgs[self._imgIndex]) self._frame=PIL.Image.open(imgPath) self._guiMessages.send("setCurrentFrame",(self._frame.copy(),)) self.analyze() def analyze(self): if self.detector.analyze(self._frame): if isLegalPosition(self.detector.board): self.states.pushState(self.detector.board) self._guiMessages.send("setGameState",(self.detector.board,)) self.go.transitionMove(self.detector.board) else: log.info("illegal position detected") def listen(self): listenerThread=threading.Thread(target=lambda: self._ownMessages.listen()) listenerThread.start() def joinGui(self): self._guiProc.join() self._ownMessages.send("!kill") def _handleEvent(self,e): actions={ "setCorners": self.setCorners, "setTresholds": self.setTresholds, "prevFrame": lambda: self.relativeFrame(-1), "nextFrame": lambda: self.relativeFrame(1) } (actionName,args,kwargs)=e return actions[actionName](*args,**kwargs) core=Core() core.listen() core.joinGui() """ core ==== grid go imageAnalyzer gui === corners a) keeps references to important objects and uses them b) gets and sets all relevant data through method calls with core GUI <- addCorner(corner) -> redrawImgView(img,grid) <- refreshTresholds(tresB,tresW) BoardView -> redrawState(go) core-gui: just pass messages with relevant data (!! always pass object copies, don't share instances) """