既に#gdd2010jpでdevquizのソースが色々と晒されていますが、自分も晒します。
今回、全ての回答をPythonで書くことにしました。
自分はJava屋でPythonは前回のDevQuiz以来書いていないのですが、新しいことを覚えるには何か動機が必要な人なので今回もまた縛りを付けてみました。
最後にJava屋から見たPythonの感想を付けておきます。
OAuth
HTTP の POST メソッドを用いて、 hello=world (キーが hello で値が world となるPOSTデータ) というパラメータを送信してください。
OAuth のパラメータは、 Authorization ヘッダに含める形式 で送信してください。 その際、認証の realm には devquiz という文字列を使用してください。
POST データや GET パラメータに OAuth のパラメータを含める形式には対応していません。
OAuth 署名を作成する際に、下記の consumer key と consumer secret を使用してください。
Consumer key: xxxxxxxxxxxxxxxxxxxxxxxx
Consumer secret: xxxxxxxxxxxxxxxxxxxxxxx
OAuth 署名方式は HMAC-SHA1 を使用してください。 その他の署名方式には対応していません。
この問題ですが、検索したらあっとういう間に答が見つかったように思いました。
pythonで署名付きリクエストを送る(2-legged OAuth) – taichino.com
ただ残念なことにこちらのプログラムはGETで書かれていました。
このプログラムを問題に合わせるにはGETをPOSTに変え、Authorizationヘッダを利用せねばなりません。
Pythonには標準ライブラリにoauthがありました。しかしGETのサンプルしか見ていないのでどうすればヘッダに情報を書くことができるのかわかりませんでした。色々と検索して結局OAuthのソースを読んでわかりました。oauthのlibraryにto_headerというメソッドがありそれがヘッダに利用できるリストを吐くというものでした。
PythonにはなぜかHTTPクライアントのライブラリがurllibとurllib2と二つあります。
恐らく歴史的な理由でしょうが、HTTPリクエストヘッダを書き換えるにはurllib2を使用しなければ無理なようです。しかもurllibとurllib2の両方が必要なようです。
そこまでわかってやっと書けたのが以下です。
#!/usr/bin/python # -*- coding: utf-8 -*- import urllib import urllib2 from oauth import oauth # ユーザ登録時にもらえる情報 consumer_key = '' secret_key = '' # リクエストしたいURLとパラメータ url = 'http://gdd-2010-quiz-japan.appspot.com/oauth/************************' params = { 'hello' : 'world' } # 1. Consumerオブジェクト作成 consumer = oauth.OAuthConsumer(consumer_key, secret_key) # 2. HTTPリクエスト組み立て request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method='POST', http_url=url, parameters=params) # 3. リクエストに署名して発行 request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None) req = urllib2.Request(url, urllib.urlencode(params), request.to_header(realm='devquiz')) response = urllib2.urlopen(req) print response.read() #200 OK #Congraturations! You solved this problem.
しりとり
サーバーとしりとりで勝負していただきます。
3 つのレベルがありますので、それぞれのレベルでサーバーに勝ってください。サーバーに勝つと、レベルに応じた点数が加算されます。
サーバーが先手です。上のリンクをクリックすると、サーバーから辞書(使用可能な単語のセット)と初手が提示されますので、それに続いてください。
しりとりの途中でブラウザを閉じても、上のリンクをクリックすれば再開できます。
手詰まりなどの理由で、ゲームをやり直したいときはゲームをリセットというボタンを押してください。新しいゲームが始まります。
サーバーに一度勝った後は、そのレベルで新しいゲームを始めることはできません。別のレベルに挑戦してください。
この問題ですが、ソース提出必須にしてほしいとバカを言っていたのは私です。
良く考えればまたこれも個人個人で問題が異なる訳ですね。
Level1とLevel2は全探索で解けました。
私の場合、L1では辞書が22語、L2では46語、L3では187語になります。
L3は単語の頭と別の単語のお尻が同じ字になっている場合が多く、全探索ですと組み合わせの爆発が起こります。L3は全探索だと終わる気配が感じられませんでした。
最初は序盤を適当に答え、終盤だけを読み切れば勝てるかと思いましたがどうしても負けてしまいました。
ある程度負けを重ねたところでサーバー側の手がわかりました。ある文字で始まる単語は何を答えても同じ文字で終わる単語を答えられてしまい、こちらの手が尽きて負けてしまいます。つまりある文字で始まる単語を選ばされたらもう負けな訳です。
さらに絶対に負ける単語がわかれば絶対に勝てる手もわかります。その文字で終わる単語を選べば後は失敗しない限りこちらの勝ちです。それを調べるとある文字で始まる単語は何を選んでも絶対に勝てることがわかりました。
ここから最初に辞書をもらった時に二つのリストを作れば良いことになります。
自分の手では必ず相手が負ける字に誘導し、相手の手ではできるだけ自分が勝てる字が来ることを願う訳です。これを探索中で枝刈りに利用しました。そうすると非常に探索時間が短くなり簡単にL3に勝てました。問題の性質上、絶対に勝てる手が用意されているので当然ですね。
以下がL3に勝ったプログラムです。
#!/usr/bin/env python import sys words = ['zhtqjb','bglbwir','binaqofibn','bhfbuwox','riartzn','rljjkx','rotxttg','nriynhitx','nenemhg','nlumqkqltz','xcbwlkisuqg','xxreewewwz','xswzmyq','gaepz','gjcrbgq','ghqhhwql','zfrvjjcncq','znwfl','zehpnlmqiea','qqkptl','qoztsna','qpyuwspeb','leheosfkmsa','lhjmfzeb','lwqir','akidjknb','abhfwqfkr','asmskhfpun','bryvkdqs','sgzdam','sfzbugash','sscolpcrmej','rmficolezt','twedci','tbjctsy','tbztchfbjo','nfglypw','wmrsre','wvjlwpgvik','wnergv','xyqcs','gxlnxvcdbvt','zsmmjypw','qzkls','lftmbhhixmt','abuofnvw','mcagfrixifi','mpaerpkane','mqwnhjmieh','mdgzrzyy','mnkrk','mpgldj','mbviso','mpsdav','maygakc','mbexzu','mazywod','ivnkhtm','isxoke','ijmclfhh','inbxgsy','idcanzk','inhvynxcaj','ibktno','ibruwejv','iiycffthdc','iatdegrwu','iuzjd','eceamplvatm','exaejvi','eptlnh','emjojhqbtty','eovfutxcsvk','ekejlknshj','ereigbo','ejctpwiilv','egelfc','erxintdtru','evtvgvsd','htzjmuom','heuindyxxii','huhethhmaie','hjdmjxueuy','hwvdjgk','hszkgrvgknj','hjtxqio','hutuikev','hvbglnmtc','hjiimohuu','hjqfnbd','yuzwjmrkgm','yrphmi','yiuazmwtwe','yxncvskuwh','yszmtak','ybocj','yvfqsjotpo','yvpgtguwfnv','yzptnedc','ymideu','yhpgjunsd','kfpjraqaxim','klljvqokpmi','knvzoyvae','kpdth','kavxlkmrity','kaixzweqj','kaltcxvcwo','kafnwziv','kjgxiacyjc','kkqcu','kindpgrd','jzqwcem','jxtji','jztipze','jgfyaajgh','jdxonjbsy','jrnotwlvck','jksio','jfltv','jppopvmac','jebwou','jewxwfd','obggm','ocbkoeuzpai','otxgzqcpe','ohdwisfh','obqwsnlrsy','ortvcwssqxk','omopyikhj','oyjwxv','ovnyc','olttxagu','ocrerlikd','vtjpfylqqm','vzczeixi','vlwfaaejxe','vkocpmh','vmladqeiwy','vqfypmk','vxxsognwfj','vyaaso','vxzaezppc','vboatau','vnfdxxcekhd','clpirjcem','cheffvqbui','ccone','ckmnvrebeuh','ccypuy','coihzrk','cspij','coiuoeeuro','ckpditmltv','cqhru','cabqathzfcd','ujuxlvm','uunnevpi','ubwxgwkicxe','ulrych','umotpkowwoy','uthtk','uhjpyltqj','umaqyfjio','ugjrapsyhmv','uirwoac','uasikmcvld','dtchjbgm','dbdaggni','dzmtwoee','dcgrhdh','dnckiky','difrdubmyk','dwerqlthnj','dwkyyo','drwmiknpuv','dhjeuoqc','dliojujlbku','czdwssnb','cxfwudwemkx','cgvmuhztqq','ubjvtuzcr','ugacbg','ufnurlheihl','dkttn','dxofozpvvqz','dgernspxva'] words = sorted(words) hc = {} tc = {} for c in 'abcdefghijklmnopqrstuvwxyz': hc[c] = 0 tc[c] = 0 for l in words: l = l.strip() head = l[0] tail = l[-1] hc[head] = hc[head] + 1 tc[tail] = tc[tail] + 1 print hc,'\n',tc #print words dlist = [] # Danger list for c in 'abcdefghijklmnopqrstuvwxyz': # print "Pattern :", c hwords = [x for x in words if x[0] == c] # print hwords hback = [] for h in hwords: hback += [x for x in words if x[-1] == c and x[0] == h[-1]] # print hback if len(hwords) == len(hback): dlist.append(c) # print "Danger" # else: # print "Safe" print dlist # Safe list #for c in 'abcdefghijklmnopqrstuvwxyz': # tmp = [x for x in words if x[0] == c and x[-1] in dlist] # print c,":",tmp llist = [] # Lucky List for c in 'abcdefghijklmnopqrstuvwxyz': clist = [x for x in words if x[0] == c] flag = True if len(clist) > 0: for j in clist: if not j[-1] in dlist: flag = False if flag: llist.append(c) print c, ":", clist print llist calc_memo = {} def calc_score(words, hc, tc, chosen, myturn, nest): key = (tuple(words), chosen) if key in calc_memo: return calc_memo[key] # if nest < 8: # for i in range(nest): # if myturn: # print "+", # else: # print "-", # print chosen, ret = 101 if myturn else 1 head = chosen[0] tail = chosen[-1] # no left word if hc[tail] == 0 or head in llist or tail in dlist: if myturn: print " Win!" else: print " Lose!" calc_memo[key] = ret return ret # print words.remove(chosen) hc[head] = hc[head] - 1 tc[tail] = tc[tail] - 1 score = 0 win = 0 lost = 0 myturn = not myturn able = [x for x in words if x[0] == tail] for a in able: tmp = calc_score(words[:], hc.copy(), tc.copy(), a, myturn, nest + 1) if tmp >= 100: win += 1 else: lost += 1 score += tmp if len(a) == 1 or (win > 0 and lost == 0): calc_memo[key] = score return score if (win == 0 and lost > 0) or (not myturn and win == 1 and lost == 1): calc_memo[key] = score % 100 return score % 100 calc_memo[key] = score return score while True: while True: try: w = raw_input('Enter 1st: ') head = w[0] tail = w[-1] print head,tail words.remove(w) hc[head] = hc[head] - 1 tc[tail] = tc[tail] - 1 break except: print "Not found: ", w if head in dlist: alist = [x for x in words if x[0] == tail and x[-1] == head] if len(alist) > 0: print "Choose: ", alist[0] continue if tail in llist: alist = [x for x in words if x[0] == tail] if len(alist) > 0: print "Choose: ", alist[0] continue alist = [x for x in words if x[0] == tail] print alist maxscore = 0 who = alist[0] # if len(words) < 10: for a in alist: score = calc_score(words[:], hc.copy(), tc.copy(), a, True, 0) print a, " : ", score if score > maxscore: maxscore = score who = a words.remove(who) head = who[0] tail = who[-1] hc[head] = hc[head] - 1 tc[tail] = tc[tail] - 1 print hc,'\n',tc print words print print "Choose: ", who
このプログラムは手抜きで勝ち負けの判定が付いていません。(^^;
敵が選んだ単語を入力し、指定された手を選択していると勝てます。
パックマン
すみません。L1、L2、L3と全部手動で解きました。
シミュレーターはPythonでcursesが書けると知って喜んで書いたものです。
問題をファイルに保存して第一引数として与えて下さい。
キーはh,j,k,lと"."とqとuです。
特徴は無限アンドゥ可能で、いつでも初期画面まで戻れます。
#!/usr/bin/env python import curses, sys, traceback # Global Timer TIME_LIMIT = 0 MAP = [] monsters = [] dots = [] pacman = None timer = 0 # first we must create a window object; it will fill the whole screen screen = curses.initscr() class PacMan: def __init__(self, x, y): self.x = x self.y = y self.eaten_dots = {} self.history = [] self.keys = [] self.isAlive = True def left(self): tmpX = self.x - 1 if canMove(tmpX, self.y): self.history.append((self.x, self.y)) self.x = tmpX return True else: return False def down(self): tmpY = self.y + 1 if canMove(self.x, tmpY): self.history.append((self.x, self.y)) self.y = tmpY return True else: return False def up(self): tmpY = self.y - 1 if canMove(self.x, tmpY): self.history.append((self.x, self.y)) self.y = tmpY return True else: return False def right(self): tmpX = self.x + 1 if canMove(tmpX, self.y): self.history.append((self.x, self.y)) self.x = tmpX return True else: return False def wait(self): self.history.append((self.x, self.y)) def eat(self, timer): x = self.x y = self.y dot = (x, y) if dots.count(dot) > 0: self.eaten_dots[timer] = dot dots.remove(dot) def draw(self): px,py = self.history[-1] screen.addch(py, px, " ") screen.addch(self.y, self.x, "@", curses.color_pair(6)) def getPosition(self): x = self.x y = self.y return (x, y) def canMove(x, y): return False if MAP[y][x] == '#' else True def getPacManLocation(): return pacman.getPosition() def getPacManPreviousLocation(): return pacman.history[-1] class Monster: (DEAD_END, AISLE, CROSSING) = range(3) (DOWN, LEFT, UP, RIGHT) = range(4) def __init__(self, x, y): self.x = x self.y = y self.symbol = '*' self.color = curses.color_pair(7) self.dir = Monster.DOWN self.history = [] self.walls = [False, False, False, False] def move(self): raise NotImplementedError def checkSquare(self): x = self.x y = self.y c = 0 self.walls[Monster.DOWN ] = MAP[y+1][x ] == '#' self.walls[Monster.LEFT ] = MAP[y ][x-1] == '#' self.walls[Monster.UP ] = MAP[y-1][x ] == '#' self.walls[Monster.RIGHT] = MAP[y ][x+1] == '#' c = self.walls.count(True) if c == 3: return Monster.DEAD_END elif c == 2: return Monster.AISLE else : return Monster.CROSSING def moveDown(self): self.y += 1 self.dir = Monster.DOWN def moveLeft(self): self.x -= 1 self.dir = Monster.LEFT def moveUp(self): self.y -= 1 self.dir = Monster.UP def moveRight(self): self.x += 1 self.dir = Monster.RIGHT def firstMove(self): x = self.x y = self.y self.checkSquare() self.defaultMove() def turnBack(self): if self.dir == Monster.DOWN: self.dir = Monster.UP self.moveTo(Monster.UP) elif self.dir == Monster.LEFT: self.dir = Monster.RIGHT self.moveTo(Monster.RIGHT) elif self.dir == Monster.UP: self.dir = Monster.DOWN self.moveTo(Monster.DOWN) elif self.dir == Monster.RIGHT: self.dir = Monster.LEFT self.moveTo(Monster.LEFT) else: print "ERROR: Illegal direction in turnBack", self.dir def forward(self): x = self.x y = self.y d = self.dir w = self.walls if w[d] == False: self.moveTo(d) else: tmpd = d + 1 if d < 3 else 0 if w[tmpd] == False: self.moveTo(tmpd) else: tmpd = d - 1 if d > 0 else 3 if w[tmpd] == False: self.moveTo(tmpd) else: print "Error: Can't forward" def moveTo(self, d): self.history.append((self.x, self.y, self.dir)) if d == Monster.DOWN: self.moveDown() elif d == Monster.LEFT: self.moveLeft() elif d == Monster.UP: self.moveUp() elif d == Monster.RIGHT: self.moveRight() def defaultMove(self): if self.walls[Monster.DOWN ] == False: self.moveTo(Monster.DOWN) elif self.walls[Monster.LEFT ] == False: self.moveTo(Monster.LEFT) elif self.walls[Monster.UP ] == False: self.moveTo(Monster.UP) elif self.walls[Monster.RIGHT] == False: self.moveTo(Monster.RIGHT) else: print "ERROR: Can't move in defaultMove" def draw(self): (pacx, pacy) = getPacManLocation() (px, py, dir) = self.history[-1] if not(px == pacx and py == pacy): if dots.count((px,py)) == 0: screen.addch(py, px, ' ') else: screen.addch(py, px, '.', curses.color_pair(6)) screen.addch(self.y, self.x, self.symbol, self.color) def rmonMove(self): # Try relative-right direction tmpd = self.dir + 1 if self.dir < 3 else 0 if self.walls[tmpd] == False: self.moveTo(tmpd) elif self.walls[self.dir] == False: self.moveTo(self.dir) else: tmpd = self.dir - 1 if self.dir > 0 else 3 self.moveTo(tmpd) def lmonMove(self): # Try relative-left direction tmpd = self.dir - 1 if self.dir > 0 else 3 if self.walls[tmpd] == False: self.moveTo(tmpd) elif self.walls[self.dir] == False: self.moveTo(self.dir) else: tmpd = self.dir + 1 if self.dir < 3 else 0 self.moveTo(tmpd) def killedIt(self): (px, py) = getPacManLocation() if self.x == px and self.y == py: return True (lx, ly, dir) = self.history[-1] (ppx, ppy) = getPacManPreviousLocation() if self.x == ppx and self.y == ppy and lx == px and ly == py: return True return False def undo(self): px = self.x py = self.y (x, y, dir) = self.history.pop() self.x = x self.y = y self.dir = dir (pacx, pacy) = getPacManLocation() if not(px == pacx and py == pacy): if dots.count((px,py)) == 0: screen.addch(py, px, ' ') else: screen.addch(py, px, '.', curses.color_pair(6)) screen.addch(self.y, self.x, self.symbol, self.color) class VMon(Monster): def __init__(self, x, y): Monster.__init__(self, x, y) self.symbol = 'V' self.color = curses.color_pair(3) def move(self): s = self.checkSquare() if s == Monster.DEAD_END: self.turnBack() elif s == Monster.AISLE: self.forward() else: (px, py) = getPacManLocation() dy = self.y - py if dy > 0 and self.walls[Monster.UP] == False: self.moveTo(Monster.UP) return elif dy < 0 and self.walls[Monster.DOWN] == False: self.moveTo(Monster.DOWN) return dx = self.x - px if dx > 0 and self.walls[Monster.LEFT] == False: self.moveTo(Monster.LEFT) return elif dx < 0 and self.walls[Monster.RIGHT] == False: self.moveTo(Monster.RIGHT) return self.defaultMove() class HMon(Monster): def __init__(self, x, y): Monster.__init__(self, x, y) self.symbol = 'H' self.color = curses.color_pair(2) def move(self): s = self.checkSquare() if s == Monster.DEAD_END: self.turnBack() elif s == Monster.AISLE: self.forward() else: (px, py) = getPacManLocation() dx = self.x - px if dx > 0 and self.walls[Monster.LEFT] == False: self.moveTo(Monster.LEFT) return elif dx < 0 and self.walls[Monster.RIGHT] == False: self.moveTo(Monster.RIGHT) return dy = self.y - py if dy > 0 and self.walls[Monster.UP] == False: self.moveTo(Monster.UP) return elif dy < 0 and self.walls[Monster.DOWN] == False: self.moveTo(Monster.DOWN) return self.defaultMove() class LMon(Monster): def __init__(self, x, y): Monster.__init__(self, x, y) self.symbol = 'L' self.color = curses.color_pair(4) def move(self): s = self.checkSquare() if s == Monster.DEAD_END: self.turnBack() elif s == Monster.AISLE: self.forward() else: self.lmonMove() class RMon(Monster): def __init__(self, x, y): Monster.__init__(self, x, y) self.symbol = 'R' self.color = curses.color_pair(5) def move(self): s = self.checkSquare() if s == Monster.DEAD_END: self.turnBack() elif s == Monster.AISLE: self.forward() else: self.rmonMove() class JMon(Monster): def __init__(self, x, y): Monster.__init__(self, x, y) self.symbol = 'J' self.color = curses.color_pair(7) self.isL = False def move(self): s = self.checkSquare() if s == Monster.DEAD_END: self.turnBack() elif s == Monster.AISLE: self.forward() else: self.isL = not self.isL if self.isL: self.lmonMove() else: self.rmonMove() def undo(self): Monster.undo(self) s = self.checkSquare() if s == Monster.CROSSING: self.isL = not self.isL def init_screen(): # turn off keystroke echo curses.noecho() # keystrokes are honored immediately, rather than waiting for the # user to hit Enter curses.cbreak() # start color display (if it exists; could check with has_colors()) curses.start_color() curses.use_default_colors() # set up a foreground/background color pair (can do many) curses.init_pair(0,curses.COLOR_BLACK, curses.COLOR_BLACK) curses.init_pair(1,curses.COLOR_BLUE, curses.COLOR_BLACK) curses.init_pair(2,curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(3,curses.COLOR_MAGENTA,curses.COLOR_BLACK) curses.init_pair(4,curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(5,curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(6,curses.COLOR_YELLOW, curses.COLOR_BLACK) curses.init_pair(7,curses.COLOR_WHITE, curses.COLOR_BLACK) # clear screen screen.clear() # implement the actions done so far (just the clear()) screen.refresh() # curses.curs_set(0) def restore_screen(): # restore "normal"--i.e. wait until hit Enter--keyboard mode curses.nocbreak() # restore keystroke echoing curses.echo() # required cleanup call curses.endwin() # curses.curs_set(0) def draw_screen(): for row, line in enumerate(MAP): for col, c in enumerate(line): if c == '#': screen.addch(row, col, c, curses.color_pair(1)) elif c == '.': screen.addch(row, col, c, curses.color_pair(6)) elif c == 'H': screen.addch(row, col, c, curses.color_pair(2)) elif c == 'V': screen.addch(row, col, c, curses.color_pair(3)) elif c == 'L': screen.addch(row, col, c, curses.color_pair(4)) elif c == 'R': screen.addch(row, col, c, curses.color_pair(5)) elif c == 'J': screen.addch(row, col, c, curses.color_pair(7)) elif c == '@': screen.addch(row, col, c, curses.color_pair(6)) screen.addstr(len(MAP), 0, "T = 0") def update_info(): screen.addstr(len(MAP), 0, " " * curses.COLS) if pacman.isAlive: screen.addstr(len(MAP), 0, "Left = " + str(TIME_LIMIT - timer)) else: screen.addstr(len(MAP), 0, "Pac-Man is dead.") screen.addstr(len(MAP) + 1, 0, " " * curses.COLS) # screen.addstr(len(MAP) + 1, 0, "".join(pacman.keys)) screen.addstr(len(MAP) + 1, 0, str(len(pacman.keys))) def main(): global TIME_LIMIT f = open(sys.argv[1], 'r') TIME_LIMIT = int(f.readline()) # This is screen width and height. Not used, but have to skip pos = f.readline().split() #x = int(pos[0]) #y = int(pos[1]) init_screen() global pacman, timer # Read maze for lc, line in enumerate(f): line = line[:-1] MAP.append(line) for i,c in enumerate(line): if c == '.': dots.append((i,lc)) elif c == 'V': monsters.append(VMon(i,lc)) elif c == 'H': monsters.append(HMon(i,lc)) elif c == 'L': monsters.append(LMon(i,lc)) elif c == 'R': monsters.append(RMon(i,lc)) elif c == 'J': monsters.append(JMon(i,lc)) elif c == '@': pacman = PacMan(i, lc) draw_screen() while True: # read character from keyboard c = screen.getch() # was returned as an integer (ASCII); make it a character c = chr(c) if (not pacman.isAlive) and c != 'u': continue if c == 'u': if timer == 0: continue pacman.isAlive = True timer -= 1 pacman.keys.pop() space = ' ' if pacman.eaten_dots.has_key(timer): dot = pacman.eaten_dots[timer] del(pacman.eaten_dots[timer]) dots.append(dot) space = '.' (px, py) = pacman.history.pop() screen.addch(pacman.y, pacman.x, space, curses.color_pair(6)) screen.addch(py, px, "@", curses.color_pair(6)) pacman.x = px pacman.y = py for m in monsters: m.undo() update_info() continue if timer == 0: for m in monsters: m.firstMove() else: for m in monsters: m.move() # quit? if c == 'q': message = "Quit" break elif c == 'h': if pacman.left(): pacman.eat(timer) else: for m in monsters: m.undo() continue elif c == 'j': if pacman.down(): pacman.eat(timer) else: for m in monsters: m.undo() continue elif c == 'k': if pacman.up(): pacman.eat(timer) else: for m in monsters: m.undo() continue elif c == 'l': if pacman.right(): pacman.eat(timer) else: for m in monsters: m.undo() continue elif c == '.': pacman.wait() else: continue pacman.keys.append(c) # draw the character pacman.draw() for m in monsters: if m.killedIt(): pacman.isAlive = False m.draw() timer += 1 update_info() if timer >= TIME_LIMIT: message = "TIME OVER" break if len(dots) == 0 and pacman.isAlive: message = "You Win!" break restore_screen() print message print "".join(pacman.keys) print len(pacman.keys) if __name__ == '__main__': # in case of execution error, have a smooth recovery and clear # display of error message (nice example of Python exception # handling); it is recommended that you use this format for all of # your Python curses programs; you can automate all this (and more) # by using the built-in function curses.wrapper(), but we've shown # it done "by hand" here to illustrate the issues involved try: main() except: restore_screen() # print error message re exception traceback.print_exc()
Pythonでcursesを使う方法は以下のチュートリアル(PDF)を参考にさせて頂きました。
http://heather.cs.ucdavis.edu/~matloff/Python/PyCurses.pdf
また本当でしたら以下のUCBで行われているPAC-MAN Projectを参考にして探索プログラムを書く予定でした。しかし体力の限界に陥り諦めた次第です。
http://www-inst.eecs.berkeley.edu/~cs188/pacman/pacman.html
ここはさすがUCBでして、人口知能の授業にパックマンの解法を取り入れているそうです。
偶然にもプログラムは全てPythonで書かれており非常に参考になるサイトです。
Java屋から見たPython
Python初心者の言うことですのでマジに取らないでくださいw
Pythonの良いところ
- とにかくリストの内包表記。最高すぎる。Javaにも欲しい
- enumerate最高。JavaのIteratorは結局indexが欲しくて使わない場合有り
- 文字列がリストなところ
- ネストするリストを多次元配列としてアクセスできる
- dirとhelpでマニュアルがすぐに参照できる。JavaDocよりかなり有利
- リストのインデックスにマイナスが使える。最後の一文字とか超簡単
Pythonの嫌なところ
- ifでもclassでもforでもコロンがいること。絶対忘れてエラーになる
- urllibが2つあって、両方使わなければいけない
- 標準ライブラリとpypiの区別がつかない
- class変数のアクセスにクラス内でもクラス名がいる
- privateとかpublicなどのアクセサがない
- global変数のアクセスにglobal宣言がいる。これが正しい気もするが面倒
- UTFが文字列と別。u''とか面倒
- enumがない
- switch-caseがない
- List.append()が先頭じゃなくて最後に付ける。List.popも最後から取る。consじゃないの?
慣れの問題ですが色々と異なりすぎて疲れたのも確かです。
JavaSE7ではリテラルでリストとか使えるようになるはずなので、割とPythonでなくて良いんでないとか言ったりして。
今回、Windowsでは専用のIDE入れたりして快適でした。でもMacがちょっとか。
逆にActivePythonではcursesが使えなくて、cygwin限定になったりとかもありましたが。
RPDBが全然動かなくて困ったりとか、Pythonのcursesはset_cursが動かんとか色々ありましたけど。
とりあえずもう少しコーディングの体力付けないと駄目だなとは思いました。
次回があったらもうちょっとまともなコードを書きたいです。