Exemple #1
0
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()
Exemple #2
0
 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