class MyFrame(wx.Frame): def __init__(self, *args, **kwargs): super(MyFrame, self).__init__(title=APPTITLE, size=(800, 600), pos=(520, 240), *args, **kwargs) self.SetIcon(main_icon.getIcon()) # img2py -i main_icon.ico main_icon.py hsz = wx.BoxSizer(wx.HORIZONTAL) vpnl = wx.Panel(self, -1) vpnl.SetBackgroundColour(wx.Colour(240, 192, 32)) vsz00 = wx.BoxSizer(wx.VERTICAL) self.clock = wx.StaticText(vpnl, -1, u'動作速度 clock %dms' % INTERVAL) vsz00.Add(self.clock, 0, wx.EXPAND) self.clockslider = wx.Slider(vpnl, wx.NewId(), INTERVAL, 1, 500) vsz00.Add(self.clockslider, 0, wx.EXPAND) self.timesfirst = wx.StaticText(vpnl, -1, u'最初に開く場所 7ヶ所') vsz00.Add(self.timesfirst, 0, wx.EXPAND) self.timesfirstslider = wx.Slider(vpnl, wx.NewId(), 7, 1, 20) vsz00.Add(self.timesfirstslider, 0, wx.EXPAND) self.timestrunc = wx.StaticText(vpnl, -1, u'下の行動に遷移するまで 2') vsz00.Add(self.timestrunc, 0, wx.EXPAND) self.timestruncslider = wx.Slider(vpnl, wx.NewId(), 2, 2, 200) vsz00.Add(self.timestruncslider, 0, wx.EXPAND) self.choices = [u'じっくり考える', u'助言を待つ', u'適当に開く'] self.suggestion = wx.RadioBox(vpnl, wx.NewId(), u'知識不足/煮詰まったとき', choices=self.choices, majorDimension=3, style=wx.RA_SPECIFY_COLS) self.suggestion.EnableItem(0, False) self.suggestion.SetSelection(2) vsz00.Add(self.suggestion, 0, wx.EXPAND) hsz0 = wx.BoxSizer(wx.HORIZONTAL) self.stmisscont = wx.StaticText(vpnl, -1, u'失敗時の自動リトライ') hsz0.Add(self.stmisscont, 1, wx.EXPAND) self.misscont1 = wx.CheckBox(vpnl, wx.NewId(), u'序盤') self.misscont1.SetValue(True) hsz0.Add(self.misscont1, 0, wx.EXPAND) self.misscont2 = wx.CheckBox(vpnl, wx.NewId(), u'序盤以外') self.misscont2.SetValue(True) hsz0.Add(self.misscont2, 0, wx.EXPAND) vsz00.Add(hsz0, 0, wx.EXPAND) self.btnpause = wx.Button(vpnl, wx.NewId(), u'Pause') vsz00.Add(self.btnpause, 0, wx.EXPAND) hsz00 = wx.BoxSizer(wx.HORIZONTAL) self.showinfer = wx.CheckBox(vpnl, wx.NewId(), u'推論状態表示') self.showinfer.SetValue(False) hsz00.Add(self.showinfer, 1, wx.EXPAND) self.showdict = wx.CheckBox(vpnl, wx.NewId(), u'辞書検出表示') self.showdict.SetValue(True) hsz00.Add(self.showdict, 1, wx.EXPAND) self.showmap = wx.CheckBox(vpnl, wx.NewId(), u'内部状態表示') self.showmap.SetValue(False) hsz00.Add(self.showmap, 1, wx.EXPAND) vsz00.Add(hsz00, 0, wx.EXPAND) self.txt = wx.TextCtrl(vpnl, style=wx.TE_MULTILINE) vsz00.Add(self.txt, 3, wx.EXPAND) self.ptn = wx.TextCtrl(vpnl, style=wx.TE_MULTILINE) vsz00.Add(self.ptn, 3, wx.EXPAND) self.msg = wx.TextCtrl(vpnl, style=wx.TE_MULTILINE) vsz00.Add(self.msg, 2, wx.EXPAND) vpnl.SetSizer(vsz00) hsz.Add(vpnl, 1 if GENERATE_CHKBMP else 4, wx.EXPAND) vsz01 = wx.BoxSizer(wx.VERTICAL) self.map = wx.TextCtrl(self, style=wx.TE_MULTILINE) self.map.SetFont(wx.Font(8, wx.TELETYPE, wx.NORMAL, wx.NORMAL)) # wx.MODERN vsz01.Add(self.map, 4, wx.EXPAND) self.cap = wx.Panel(self, size=(PANELHW, PANELHH)) vsz01.Add(self.cap, 5, wx.EXPAND) hsz.Add(vsz01, 3 if GENERATE_CHKBMP else 7, wx.EXPAND) self.SetSizer(hsz) self.btd = BTD.BalloonTipDict(main_icon.getBitmap()) self.blnclock = self.btd.get(self, 'clock') self.blntimestrunc = self.btd.get(self, 'timestrunc') self.blnstmisscont = self.btd.get(self, 'stmisscont') wx.CallAfter(self.setup) def setup(self): self.amd = AMD.AutoMineDict() self.x, self.y = 0, 0 self.gcount, self.count, self.phase, self.roll = 0, 0, 0, [] self.fixed = [False] * (LEVELHW * LEVELHH) self.ldelta = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)] self.mdc = MemDC(wx.ClientDC(self.cap), wx.Colour(0, 0, 0)) self.chkbmp = {} self.loadrefimg() self.maptbl = [0xff] * (LEVELHW * LEVELHH) self.target, self.pwm = None, None self.tick1 = False self.timer1 = wx.Timer(self, wx.NewId()) self.Bind(wx.EVT_TIMER, self.onTick, self.timer1) self.Bind(wx.EVT_SLIDER, self.onClockSlider, self.clockslider) self.Bind(wx.EVT_SLIDER, self.onTimesFirstSlider, self.timesfirstslider) self.Bind(wx.EVT_SLIDER, self.onTimesTruncSlider, self.timestruncslider) self.Bind(wx.EVT_RADIOBOX, self.onSuggestion, self.suggestion) self.Bind(wx.EVT_CHECKBOX, self.onMisscont, self.misscont1) self.Bind(wx.EVT_CHECKBOX, self.onMisscont, self.misscont2) self.Bind(wx.EVT_CHECKBOX, self.onShowinfer, self.showinfer) self.Bind(wx.EVT_CHECKBOX, self.onShowdict, self.showdict) self.Bind(wx.EVT_CHECKBOX, self.onShowmap, self.showmap) self.Bind(wx.EVT_BUTTON, self.onPause, self.btnpause) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_CLOSE, self.OnClose) self.onPause(None) def loadrefimg(self): if GENERATE_CHKBMP: bm = wx.Bitmap(u'%s.png' % APPTITLE) self.mdc.gblit(PANELHW, OFFSETH, None, None, bm, 0, 0) fp = open(GENERATE_CHKBMP, 'wb') for i in xrange(14): buf = self.mdc.gclip(CLPW, CLPH, PANELHW + 1, OFFSETH + CELLH * i + 1) fp.write('%s\n' % buf.encode('hex')) for i in xrange(2): buf = self.mdc.gclip(CLPW, CLPH, PANELHW + 32 + 18 * i, OFFSETH + CELLH * 15 - 4) fp.write('%s\n' % buf.encode('hex')) fp.close() for i, h in enumerate(CHKBMP): self.chkbmp[h.decode('hex')] = i - 1 if i > 0 else 0xff def maptxt(self, buf, w, dlm=None, fmt=None): s = [] for y in xrange(len(buf) / w): for x in xrange(w): if x and dlm: s.append(dlm) s.append((fmt if fmt else '%02x') % buf[y * w + x]) s.append('\n') return ''.join(s) def updatemap(self): for y in xrange(LEVELHH): for x in xrange(LEVELHW): k = self.mdc.gclip(CLPW, CLPH, OFFSETW - ADJW + CELLW * x, OFFSETH - ADJH + CELLH * y) self.maptbl[y * LEVELHW + x] = self.chkbmp[k] & 0x0f if \ self.chkbmp.has_key(k) else 0xee def updatepaint(self, dc): self.map.Clear() if self.showmap.GetValue(): self.mdc.flush() self.map.WriteText(self.maptxt(self.maptbl, LEVELHW, ' ', '%x')) else: bdc = wx.BufferedDC(dc) bdc.Clear() bdc.DrawText(u'描画休止中(少しだけ高速化)', 80, 40) def isover(self): k = self.mdc.gclip(CLPW, CLPH, OFFSETW + CELLW * 14 + 5, 23) if not self.chkbmp.has_key(k): return 0 return self.chkbmp[k] - 12 if self.chkbmp[k] else 0 def num(self, x, y): if x < 0 or y < 0: return None if x >= LEVELHW or y >= LEVELHH: return None return self.maptbl[y * LEVELHW + x] def countaround(self, x, y): '''return count of flagged cell, opened cell, closed cell, r, l(=ptn)''' f, o, c, r, l = 0, 0, 0, set(), [] for dx, dy in self.ldelta: n = self.num(x + dx, y + dy) if n is None: l.append(0) continue l.append(n) if n == 9: f += 1 if 0 <= n <= 8: o += 1 if n == 0x0f or n == 0x0c or n == 9: c += 1 if n != 9: r.add((x + dx, y + dy)) # 二重 click 防止 l[4:4] = [self.num(x, y)] return f, o, c, r, ''.join(hex(b)[-1] for b in l) def loginfer(self, s): if self.showinfer.GetValue(): self.txt.AppendText(s) def guess(self): import random self.loginfer(u'guess...') for _ in xrange(100): # block endress loop 効率悪 直接未開地を探す方が速い self.x = random.randint(0, LEVELHW - 1) self.y = random.randint(0, LEVELHH - 1) if self.num(self.x, self.y) == 0x0f: break self.loginfer(u'[%d, %d]' % (self.x, self.y)) return [], set(((self.x, self.y),)), set() # always to be opened def infer(self): self.count += 1 # 手数 if self.count <= self.timesfirstslider.GetValue(): return self.guess() if self.count - self.gcount <= 1: return self.guess() # 1 回だけ適当に開く self.loginfer(u'infer(%d, %d)...' % (self.x, self.y)) roll = [] while True: # 必ず最後は roll で break するので無限ループにはならない x, y = self.x, self.y self.x += 1 if self.x >= LEVELHW: self.x, self.y = 0, self.y + 1 if self.y >= LEVELHH: self.y = 0 if not self.fixed[y * LEVELHW + x]: n = self.num(x, y) if 1 <= n <= 8: self.loginfer(u'%d[%d, %d]' % (n, x, y)) roll.append((x, y)) f, o, c, r, l = self.countaround(x, y) k, m = self.amd.match(l) lop, lmk = set(), set() if k: if self.showdict.GetValue(): self.ptn.AppendText(u'%d[%d, %d]p[%s]q[%s]\n' % (n, x, y, l, k)) self.ptn.AppendText(u'k[%s]m%dr%d\n' % (m[0], m[1], m[2])) self.ptn.AppendText(u'o%s\nm%s\n' % (repr(m[3]), repr(m[4]))) for p in m[3]: # lop px, py = x + p[0], y + p[1] b = self.num(px, py) if b == 0x0f or b == 0x0c: lop.add((px, py)) # 二重 click 防止 for p in m[4]: # lmk px, py = x + p[0], y + p[1] b = self.num(px, py) if b != 9: lmk.add((px, py)) # 二重 click 防止 if len(r) == 0: self.fixed[y * LEVELHW + x] = True if f == n: return roll, lop.union(r), lmk # to be opened if c == n: return roll, lop, lmk.union(r) # to be marked # 戻った先でも lop lmk check しているが ここは roll 検出のため必要 if k and (len(lop) or len(lmk)): return roll, lop, lmk if self.x == 0 and self.y == 0: break return roll, set(), set() def click(self, b, x, y): if x < 0 or y < 0: return 0 if x >= LEVELHW or y >= LEVELHH: return 0 self.loginfer(u'%c(%d, %d)' % ('m' if b else 'o', x, y)) self.pwm.mouseclk(b, OFFSETW + CELLW * x, OFFSETH + CELLH * y) # btn L / R return 1 def onTick(self, ev): if self.timer1.GetId() != ev.GetId(): return if self.tick1: return self.tick1 = True while True: # 除外処理系を break & 最後に break で脱出 (indent 減らすため) if self.target is None: self.msg.AppendText(u'Searching %s ...' % TARGETWCLASS) self.target = PostWinMsg.target(TARGETWCLASS, TARGETWCLASS) if self.target == 0: self.msg.AppendText(u'may not be running.\n') self.target = None break self.msg.AppendText(u'is found.\n') self.pwm = PostWinMsg(self.target, wait=0, fg=False) # self.msg.AppendText(self.pwm.getclassname(len(TARGETWCLASS))) self.pwm.topmost() self.pwm.altkeys('GE') # Alt-G-E select high level self.pwm.keydu(113) # VK_F2 restart self.pwm.sleep(INTERVAL * 4) self.txt.Clear() self.ptn.Clear() self.amd.reload() self.x, self.y = 0, 0 self.gcount, self.count, self.phase, self.roll = 0, 0, 0, [] self.fixed = [False] * (LEVELHW * LEVELHH) break self.mdc.gcapture(0, 0, PANELHW, PANELHH, self.target, 0, 0) self.updatemap() self.updatepaint(wx.ClientDC(self.cap)) o = self.isover() if o == 1: self.msg.AppendText(u'completed\n') self.onPause(None) self.target = None # self.pwm.wm(18, 0, 0) # WM_QUIT break elif o == 2: self.msg.AppendText(u'missed never give up\n') if self.count <= self.timesfirstslider.GetValue() \ and self.misscont1.GetValue(): # 序盤(規定手数内)の失敗続行 self.pwm.topmost(False) elif self.count > self.timesfirstslider.GetValue() \ and self.misscont2.GetValue(): # 序盤以外の失敗続行 self.pwm.topmost(False) else: self.onPause(None) self.target = None break roll, lop, lmk = self.infer() if len(lop) or len(lmk): c = 0 for x, y in lop: c += self.click(0, x, y) # open many boxes for x, y in lmk: c += self.click(1, x, y) # block '?' from double click if c: self.pwm.sleep(INTERVAL) # redraw (block reentry self.tick1) else: self.loginfer(u'roll\n') if roll == self.roll: self.phase += 1 if self.phase >= self.timestruncslider.GetValue(): # 行動遷移 if self.suggestion.GetSelection() == 1: self.msg.AppendText(u'I want your suggestion, and resume it.\n') self.onPause(None) else: self.gcount = self.count self.phase = 0 self.roll = roll break self.tick1 = False def onClockSlider(self, ev): self.clock.SetLabel(u'動作速度 clock %dms' % (self.clockslider.GetValue())) def onTimesFirstSlider(self, ev): self.timesfirst.SetLabel(u'最初に開く場所 %dヶ所' % ( self.timesfirstslider.GetValue())) def onTimesTruncSlider(self, ev): self.timestrunc.SetLabel(u'下の行動に遷移するまで %d' % ( self.timestruncslider.GetValue())) def onSuggestion(self, ev): self.msg.AppendText(u'suggestion=%d\n' % self.suggestion.GetSelection()) def onMisscont(self, ev): self.msg.AppendText(u'misscont%d=%d\n' % ( 1 if ev.GetId() == self.misscont1.GetId() else 2, ev.GetEventObject().GetValue())) def onShowinfer(self, ev): self.msg.AppendText(u'showinfer=%d\n' % self.showinfer.GetValue()) def onShowdict(self, ev): self.msg.AppendText(u'showdict=%d\n' % self.showdict.GetValue()) def onShowmap(self, ev): self.msg.AppendText(u'showmap=%d\n' % self.showmap.GetValue()) def onPause(self, ev): if self.timer1.IsRunning(): self.msg.AppendText(u'pause...\n') self.btnpause.SetLabel(u'Resume') self.timer1.Stop() if self.pwm: self.pwm.topmost(False) # after stop timer else: self.msg.AppendText(u'running...\n') self.btnpause.SetLabel(u'Pause') if self.pwm: self.pwm.topmost(True) # before start timer self.timer1.Start( milliseconds=self.clockslider.GetValue(), oneShot=False) def OnPaint(self, ev): dc = wx.PaintDC(self) # Don't delete this line wx.CallAfter(self.updatepaint, wx.ClientDC(self.cap)) def OnClose(self, ev): if self.timer1.IsRunning(): self.timer1.Stop() if self.pwm: self.pwm.topmost(False) self.Destroy()
def onTick(self, ev): if self.timer1.GetId() != ev.GetId(): return if self.tick1: return self.tick1 = True while True: # 除外処理系を break & 最後に break で脱出 (indent 減らすため) if self.target is None: self.msg.AppendText(u'Searching %s ...' % TARGETWCLASS) self.target = PostWinMsg.target(TARGETWCLASS, TARGETWCLASS) if self.target == 0: self.msg.AppendText(u'may not be running.\n') self.target = None break self.msg.AppendText(u'is found.\n') self.pwm = PostWinMsg(self.target, wait=0, fg=False) # self.msg.AppendText(self.pwm.getclassname(len(TARGETWCLASS))) self.pwm.topmost() self.pwm.altkeys('GE') # Alt-G-E select high level self.pwm.keydu(113) # VK_F2 restart self.pwm.sleep(INTERVAL * 4) self.txt.Clear() self.ptn.Clear() self.amd.reload() self.x, self.y = 0, 0 self.gcount, self.count, self.phase, self.roll = 0, 0, 0, [] self.fixed = [False] * (LEVELHW * LEVELHH) break self.mdc.gcapture(0, 0, PANELHW, PANELHH, self.target, 0, 0) self.updatemap() self.updatepaint(wx.ClientDC(self.cap)) o = self.isover() if o == 1: self.msg.AppendText(u'completed\n') self.onPause(None) self.target = None # self.pwm.wm(18, 0, 0) # WM_QUIT break elif o == 2: self.msg.AppendText(u'missed never give up\n') if self.count <= self.timesfirstslider.GetValue() \ and self.misscont1.GetValue(): # 序盤(規定手数内)の失敗続行 self.pwm.topmost(False) elif self.count > self.timesfirstslider.GetValue() \ and self.misscont2.GetValue(): # 序盤以外の失敗続行 self.pwm.topmost(False) else: self.onPause(None) self.target = None break roll, lop, lmk = self.infer() if len(lop) or len(lmk): c = 0 for x, y in lop: c += self.click(0, x, y) # open many boxes for x, y in lmk: c += self.click(1, x, y) # block '?' from double click if c: self.pwm.sleep(INTERVAL) # redraw (block reentry self.tick1) else: self.loginfer(u'roll\n') if roll == self.roll: self.phase += 1 if self.phase >= self.timestruncslider.GetValue(): # 行動遷移 if self.suggestion.GetSelection() == 1: self.msg.AppendText(u'I want your suggestion, and resume it.\n') self.onPause(None) else: self.gcount = self.count self.phase = 0 self.roll = roll break self.tick1 = False