TFrCm8$u6?p0vgX|Ci~2tV)7)DXPBH}@*ES2<6OWfci(D{
zV7Q1YI*O!!pubQqm5cZ-;kU1B2DO|XIXHDx(hnKx0xXhEm&AwfAm=-qRf2k
zNY<4IMvjXts?<}S*hRhYv^K&J4suin0pWib*T1LfaSlU4HiC8GjV2k%NtVcEX9l*T
z)q(A38Q6|A1V|%uM5mh|4N2raJUuWbkn$4`WM-A-;@G5+zgi
zjubLqpQxJVvxnCI!BglaIL(AJ4qir*JJ-R}yv6l^m>^q!4OcSvAurMOWVSwBnmb2^
zGEDTL)P1fmrS9*o-vdslXSNTa5+!P`3>RRNIfdLq&4V5M6t09GCZxE?@_Y4|)K#v%D0%~*iKc+eKJX=)*hbUn
zFp~ZvRM=p-pUMmWOTy-*ZnIHm@BASWF5rs(8j@bsg?MLUA)Uu(fW>LUINJF24~Xyh-~>Nm~agNcR+
zE}!v#1mkU{7T09F$p{H80C}s4$THyb`R%38?<^rm9Kz(X=mm|hEX?2|?ojhhh9l^_
zVWEp{DCIP4Fe!z-lf?>T6Vkpzjn!s54M?=5!k0U7j8JJ$M4~6uQLW0{P9oPdX>q^B
zKr_Ol2!C!M?yVRHEKzh0(-BKfq97J@^_M%fZX<~{P~=leU|`4sWwTeV%vax<4XT&t7G#^;ZZ_gInY(LYb9K!Ed~gjAfGDBc253a4
zM|GoZhP`ru*2yOkBmA&drvYVB7nm7O)do1n1?2Z!F#ze9`-4x&;8F#o7!a*i
ze;wVVDv(koy{1`Ca2UZrGhjmJg=3DKgpD*OHj#&|XvocQM@V4z`<`BuPVXC>2Bo|+
zKbzqe*9)-IZbD;Pr(=?Scm7!M9jS(4vGKZ$ak_bT_GIUf}O4dC{BMv_uO
z6sn)%#7;BWO_C2|GX6HYOHIbq0-&fPT!ia)kO8iMTOb8^*nU0XlbNND6KUJe8Iqo4
zsDc9OyeQXmub?ud6Bk%?ucH0tlWuWy)GgA^7j>lA6Gvef*CfFit8s<0I<=2sRL(gq
zBjhX=TvOT#F0u)(2Q-)I0RKH)CLRjhHaP4ZM0(IWng_`Uc0u7)WHNFmEn@+)NlBx)
zC7B*nD6`-mBY8f~g`50OameWhpJb8=LPI1+u@w>$tD?PqEQtouw{RusJns2RU;
zAr)jy&fU$eIX(^8{9z0^IjD^=+?a;>`!CU1ulOKhxlGN0Bz#X`8YJ%@aO~B1HbCyd
zK_;0Ttzl=PbDOjN1N4$XZ^$^7v(9ussRlDoknW|j3FMrG=ZO4+CYuP>xt^%v*1E|b
zc31Cg?TTL0>De#h8E*f#xKe-!gOOl8bb%xOzv`|C96tla7x6TE&v
zib@<$C@3>}0;2H*#UE~w773T@5DyBY3pKZEjHV}yUW(HtwO~`
zW#mozX5rzSNHd1v4!;1~BhlHjXU}B)b1>H=m7CxuaC3B<{{0ln;$ujv^{~~t%(EE_
zopiG*SmaZZX}q=33UgCY1c8Ag?a3#>W{fXsFSSf#F^jeCgYyS5XlkPVN93auNL>F>
zXn>D+C%og{A@7Jc25rD!nTsSFa+XBcQ^)`j#F}%*!C2YNC`0$SFOok}ZjgZeG}`o-
z84_L(v4r3n`uk&CiNwk#N;G7w|2}RKir(TRXO`B*@r`8e2@%7FE8y9i;(MceON;Ip
z3G%Xgi@MzCTSS@Dx9C10@$;nbf^`4p83=`gZV}|35GU1MMm!gBlnA>4ZJ$nquk$K3
z(ps`Fu!lNHnEc5}Zq5!kP@g5<2I+(3)QBGCCb=-=yNQ;seB!RFIe1Xj#1{WlX
zKfz_@M2Tj^NpBPe6$wc@){G}*lIK0#P#}X;Byeuxw9R9b!GPWSGMl!qD;}E2<2mAm
zasvneUP|r+!U-ovAYe#$eePzT>$XU95YAX2#j-v4KH6Qf(D($#H3jx_5F$hhi6pU|
zA3;_piEy~9miX;Bo&;gR9Z|8j7~R6u1iJjT*>1Pf%^6+%9Gu5fnW?I5`gs{;f_&8c
zqV0RqAB~Kk$sO$n=i%V{(XNcf5#@^m=MK3cZv-G8BG(p_95R-1oERR&0|&WWf|VXjB41|#e+Y^TxT1f9Bt*~*42877vr>qXAub1%
z{4&C1%;Ag_;$+O>02Tse%ncxSSh+zQ$|}3C>~2)tUG#x~9L{qg8fOtZMdL!*c8JU+
z(L06Z!eN3QAv&H!MGQ|NI)v+RD3s+0*I7L82xEBR5fvhIr_-s|j;ipe3K7ObgbzcH
zsBlDuBUvPmq$&YAg|H4zVA@$f1nIb^)vRZSHF?AbhXl6E0G%P!Y6`5W1IJ+YuXb1LTR;7Sq*8M`~ZSDSF;xeg(
z9n^$Y!~G2wXf?l!47IXZK8ETdH7_Nm_HcRlg*V#A59@0e1&s-9b@U+1;t|+{U{VH+JU$dw#c!+>j*q
z5WI;4Zaj)9#38@l9iW`>He-jsMU*9klpyXuysm9=JJIq4)+htIwj3EI$|za5dSy14
znwy^0UW$NM&7c=e$*GcZpCG`*h!D~^Dq>M#IM9*Ye+2xa=5i~{Z7EgQ#u;jh74IlV
z`a$=a2hLjLh*r<-a67K<kpgZqx+s89ES8UxINLu-I)SY=v-BfE=!cODvzaIb
za-nA+Lov12mT(vu^V>h0uU~(gCm!Wt3GFF_5-U^%v8sAWo15>W#CvemRlo
zb13uHUt`ThJV|!fGa`{jFq4f$BH{=(nWNoqfmHfyMgmmG>Gn<#u|j4(2V1P$Hj2cu97aBLLO70N!Em
zYBLz^W3|a4%j^`;Iv2_{I9a@Asqxkfbxz5Yyxuv{Em~NaRptZ3dS00wOi&Z-wVJs>
z65K;I+o`A)pOUkTVm6oqMcYn~Sts`1NkDZYCC@;h6*sC3*{rYhH#a%y_LOr!L7|YTI+|PxPU9-^n2||SY}{*
z+IEosw!I4r)3$eU0^GKDVgH%2h<#q$-o-wzZSP{A*S2@jkC}sDW-|eGUZ40CJ}nd@
z^~A~Wl6v|DWN1!602Ez!Rf0k?=B`8(2;W4^m_
zIg}6bgFV}qn7edg6?3ibM4dwaE1CM#e
zkjEx?zOdPb{kpClK#L0?4&-BBuz`1Gc>FCt!YAUL(=N9hI(a55olZj@n=}$$pNa7L
zNE8oaCLE#XOqh(28ef*0=UYjUR8Fh5gDoFrt079;W{}|EduT7Du>V;-pc`D}?Np-?
zHbhg^WIU@to~depH(`J`Y{QlIO|{iY_MWPE%gVyg9ASEmd#U11`OOlbSo$qZFlUkb
z<__96w=;=Y8p7trL5T|-8`N&-uJc;E$gP2<)OKJXClA*E6n|QCO^dF&oTKLk{mz*1>ip5!tTFDxX|OI
zrZ|e3fPWK**7Vr*TCzvduEwKE>tDER832E(APu0RRK2$OuEkOBNV9NARCLSybd4
zay`+%FXL9*;GoH7*hmPF6qOU?KGyXCI`}JG7s1Jp$Uy`#KP*ZpuCWX-ERBbIo?(xk
zrUgR}jRAikUN%W|J}VWT&HRXhtW*&xNF4MVt*I2OWcFx89h(V*DQ>#pZIjy_d9OHv
zjDx;>wXn0k!E={6m(N)Q?9~Q2Y+AMXL|VV@zkQfGu_cgy1|k{3;%8M?q3cK7bXY%<2s$^-69O
zPb|U{aR+iQ7O0^!4B#LEPR6X@JtFzqHJp*@IX10B|4rJ3%>gFg{qC?GCy}fQaR^n1
zl>;H^3DnRot{yHRW@Hh=&$C>7o?)i~gS!B!PVHsGQnf5df{JWls0-4xXCo!hrHr;&R;S=>IYr^hhkN5n7c
zA2wBQ5AS=6@o|=*XINPrXw;43H4dV1E{{!$SUM4rTbZXaJ?EcpR3sDfN)uyv9DIdI
z?$wYZ0)QbQNm>;a(~gjnkd~HTgqu5$H$z0(l13j-pSSV)Fzko7aF8U<{cL+z;1jGw
zR;j|&L3^=6b(Ke$*_#;PSv-~;vs3&<-e&UyGb1=(+vxGI#5$Z^@FPqvB2l-}9rWDy
z!86aHlV2mxa5Byt2fsWDQ(*+Zquxt}!-%fKX~y*;6lK|ar0^(Q=c9$}bv$y`G%h(`
zp!qJ0Mk)}n2VUWaMF_mkgZ7eBA41nzrKgqpHfOD!iC~5oe=fqnO7ld)K9=@%bocvQ
z8ucr+Vu{y1&UU|s$C$b~f@EwQr{o%}$O4^DYcWZYIqI*{510pWCP8$q=a$khDE*Yu
z^Csg+p*@}yovj|tMJIV5OZ=;7_OH0aL&z|kS<0>ttN$rf=~B(>UubBi3g1U}f0{7)pKljzEojv{;@mk7=gLr2_G
zq!E1vdx>1!-l&Mw0MTF$%LmLo!-N)yZ75Rs1Z2;EBpdt^l6=O>-M4xA9@_Glqs&vp
zI=rD{LhKv0n@!M4V^U?KdW
z#0&^zU@pjF01GFTVW!FAqVs8i5PgGzt;%%q(3KbtfgCe@-cgU0dp<(|9_NG-0fWv9L)MIyLa
z_y$fn#3Kv)~_~v*DQ+Z8|^MztaaOn+(fdKG(*;87=<{a(SxU#uWB~g4b`CP
zUe%d=JCaUl1i#AU*O>e|liy(S4JN;dM9WpX;BVtLXQlh*A~HmO0gyV03}4pY`+E{+
zH_9+_>J%@$P}!*N6f!_Lv`7~_z=?aTpa@D~pPGHc>T{qa{`}GFwoUgpkk@hqVs1@z
zJFBo6qlYmlDO(cK0JA+Cno
zb@}UofbuKo*dRmtR6inkgBw>O!qo#K>OPchZZ*Sw9LyH3C|MQ$bL9F=~lTUL{Qj%w;aYg5#U2Nt_2tX(WJCpp$BXHY)(SzVgocuJ@
zGPCrTy(BPd_~p(q7%h86$AUeed>kk#LCbAK|T23*z#ogh`VttsfWg3VVIpe7act4
z8^<{$TzERysEJmiEa5t{$559il90q0y8$yW`0z^c{9^kuLRKdfvRcPHy>wY1_`S^L8^Iskq(p*ezyWulQMeZtD}6iv(@O~P)V*Or
z04bJqB7w@;d|4z(#6f?!2JAe{iTx4Qs;GvZC>1a75Qci(JgJed*x9p$)F)>CEqcaCV+j-&S8rean5j
zsgF`6uW9@Xk^()Q$`PAaVD4#m;~C8@JFLJ`@Y)~u?dT*Usc|By0W!iRpG`_}i+Om2Cp;va=3vO^3luFSY>bd#
z3eX+I76=lLQEQY^={eW^ju%h58y{6iXHzk}`5g~`i`zfu;^*~5=$l#kq4Wp|B-O#)
z(&;Dqcb-$#e8E@_KA@y^?OyZZ=IMbHRHp_qd=0~V9C#l`aE+?I7qB*eq91>ft?2tj
z&RNPzezCrakVPTh%tJmsuHe@R*5J8V+PmCcNgA$&i%ZGrizfx=R(~{T>YISOj
z;CJzCPA?GL>!Xsb-dOrIj;s
zkMPaUT5Cc<7r9Z4IcP)0-an!>gps%>9VyT)o3j!2r%y1U>y~`JCVsQFjSbE&Uh-glnUURy_43?wb#`v*!j;(>VPhG)0(F4`d;ZlG
ze!~xMSXUeP0+<}Q;78f}KTkUb@|w|_PFV#-KDo%`cleloK#aLIsw<>l-ipAhEXX@T_zdp7Is=L*Gg~s>)
zX7kdhSH?b^-mokl!4aJiglTygp^Uw`r*QG){$agw!>483l@Y-nL4L3>S~!Au+%OLG
zuzi1Fce`=)Qo;V-p{)K1?DP#IJZ8P0RqqIv=?%{#>bv6g6^<27p#R6b$8m8yd@!;w
zQpoR0>XCg97KXh_5i3AXCou|NwPERr;%MJ!;jlYeID|JyA1R*1ii&u4SS`zn99A&y
zoMDrE*Yi;e5p#)UbmNW1D2@VoMDl~giekY3j0ZU$l)GPK1iy^79x*{~;1Q{#hs*s#
zc+UXGqsryMJ>7oqTQ(Q-ZpF=3@CUp@udWjXe;5BuWYD{_An!+*lMK@ST9dbvOx|Pi
z@0m!T{2_CK1?RbE^!r_-LQCiEQ?Z|-K8c<{Qo$PoIMmTUa%ANA$V(&7jzs0k$im21
LNo^His#5qrz=s`p
literal 0
HcmV?d00001
diff --git a/search/ghostAgents.py b/search/ghostAgents.py
new file mode 100644
index 0000000..c3afe1f
--- /dev/null
+++ b/search/ghostAgents.py
@@ -0,0 +1,81 @@
+# ghostAgents.py
+# --------------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+from game import Agent
+from game import Actions
+from game import Directions
+import random
+from util import manhattanDistance
+import util
+
+class GhostAgent( Agent ):
+ def __init__( self, index ):
+ self.index = index
+
+ def getAction( self, state ):
+ dist = self.getDistribution(state)
+ if len(dist) == 0:
+ return Directions.STOP
+ else:
+ return util.chooseFromDistribution( dist )
+
+ def getDistribution(self, state):
+ "Returns a Counter encoding a distribution over actions from the provided state."
+ util.raiseNotDefined()
+
+class RandomGhost( GhostAgent ):
+ "A ghost that chooses a legal action uniformly at random."
+ def getDistribution( self, state ):
+ dist = util.Counter()
+ for a in state.getLegalActions( self.index ): dist[a] = 1.0
+ dist.normalize()
+ return dist
+
+class DirectionalGhost( GhostAgent ):
+ "A ghost that prefers to rush Pacman, or flee when scared."
+ def __init__( self, index, prob_attack=0.8, prob_scaredFlee=0.8 ):
+ self.index = index
+ self.prob_attack = prob_attack
+ self.prob_scaredFlee = prob_scaredFlee
+
+ def getDistribution( self, state ):
+ # Read variables from state
+ ghostState = state.getGhostState( self.index )
+ legalActions = state.getLegalActions( self.index )
+ pos = state.getGhostPosition( self.index )
+ isScared = ghostState.scaredTimer > 0
+
+ speed = 1
+ if isScared: speed = 0.5
+
+ actionVectors = [Actions.directionToVector( a, speed ) for a in legalActions]
+ newPositions = [( pos[0]+a[0], pos[1]+a[1] ) for a in actionVectors]
+ pacmanPosition = state.getPacmanPosition()
+
+ # Select best actions given the state
+ distancesToPacman = [manhattanDistance( pos, pacmanPosition ) for pos in newPositions]
+ if isScared:
+ bestScore = max( distancesToPacman )
+ bestProb = self.prob_scaredFlee
+ else:
+ bestScore = min( distancesToPacman )
+ bestProb = self.prob_attack
+ bestActions = [action for action, distance in zip( legalActions, distancesToPacman ) if distance == bestScore]
+
+ # Construct distribution
+ dist = util.Counter()
+ for a in bestActions: dist[a] = bestProb / len(bestActions)
+ for a in legalActions: dist[a] += ( 1-bestProb ) / len(legalActions)
+ dist.normalize()
+ return dist
diff --git a/search/ghostAgents.pyc b/search/ghostAgents.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c46287ff7785de7b285052a0260cb16bd87273cf
GIT binary patch
literal 3341
zcmbtW-EJF26h5=-pEz;iB#^c#5-g>qR#gHQl?qivNgEX*p)^`YL|CEL#yfV_wRe-9
zNt;&oRS@q07d!{tam!n9%N-IA0N**|pO(9nO=diEX6DTK`OZ1x|GhYW@0Z{9+cf@s
z{C*xkuD3hGNsN@JU^i>OsN%$3)HArA!70mzPiH57SU~Wb!y$T
z%+t0_veY=jJP6xKt{rX15m!JQMCnmvZIo^&27Oyw-umTHW~}g=8i%iWfMz~Gr-^L>
zlRyI)1BT*(&lciAfxNqfzeUkKAQY=r_!5^;}>=g+gq(9O>C=m8DqoDNr`MM
zBu_=Q&oF>sJ(2KS(a0kUQ9Z&KDn9inuaott=Tig1^@`)QMojPsv)M_|QN4uD*3fme
zWxM9d;VC=A@^yWkhEw$#dyjWTPptRtB`mj(vdrj5c{X_Uq*yZ)zHAJ*%4#_mgZ-PE
zrs8CDP`S#C*;u4%YE_lJsrT6TVxc7rEG(oLw+c3KYMaNPhuWUzsR^RsVRo8Yod-H?
zXK|8tL1Hl{RtU0ZSd1JLgAOze?2!(R^Xyp?>o^eQHg?3I;R4^trp%+n=$*`N>rRsD
z*sZcbLWa~En;>L`-$!$(@ak;dF=Wzcpj#~oh*oQm#ixBtLyoPGC6c4Fi)C~{Y=#VR
z_PSwBN~+>l%9d3QqcqM25{7L|<(ozzgIG@@@YV1`)G@Nmr|7l<2?LlmvVj8?`=+nE
zQGaaw;51D-Sw85$2(TxYD>uaHEEczi%xw$Z)ai(cv+EqeJx^lA=iu1>Zka}iehHSL
zPn#$2(LUm)R}h?FG!Bn0SmFEYzL?oLm+d)5%p_*MW+BJ4rP*aE+^^=#n&Z0>$
zi0?x|C0i$&dE=svU>Mv)Go1cNRn~sH95DE@LoF)KUL+1o&8dz}r7W_a6kn_?&%FoZtw5mWG+L;mr0LAdYk0(YXn1
z7UZYqDA=7L~5n@k)3jx5+MWR3>6nT$EB^nkf
zZ?ZEmPEicN)<>*dp;4JDb`LwsG%V4%M^8LDiD)z@o93|T7H=8~%XRDm=k?1x^+=}p
zx!iHbexOlBBr0>Tjpl_#1uWKBFr+dZ8_rKI`JF}!BABNTRKo?4zbc_TPoqUj*9Zyd
zHF}ll5Z*3|XK};>_jl<4N-oi;Mnn8pr99qL!zIz>rW!4iU7}u1gj%7qYcyQOv8$rj
zA_3@_!+2}M6*j}>$rH7IcH3F#x@;0UoU{(5hl_NDk4U;%yX$YBoU47D?5!|=g;7I5
z;|g%Xn1jUp{c*o8k;_#An2Gmc$Ue_Bs9lb$064XI1l+zYOWL72%A(tpU7+AE<~mz
zf(dP`FDf!#hGs8w8cH@k)W$a2S+3<)p6w#2E!Q!3jnKL7%d3*D$(trwo$q?{Xl6z4
zpqWq5k++KH%Bre)$e>j5Zm7Ge>R&@Pt*WY5MWo;Hs|o-@yT&_KPhgZPDRdr@N
z6G}!G%`@v@@e$g%pqEswSm%-=kF_oy6d@)gU~;cOHkd2D4hf7Jc@~6R975*z|3nf$
ZY`W*m=lpIlTw|6M|5dqpmui>h{sk>5r)&TK
literal 0
HcmV?d00001
diff --git a/search/grading.py b/search/grading.py
new file mode 100644
index 0000000..b63c877
--- /dev/null
+++ b/search/grading.py
@@ -0,0 +1,323 @@
+# grading.py
+# ----------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+"Common code for autograders"
+
+import cgi
+import time
+import sys
+import json
+import traceback
+import pdb
+from collections import defaultdict
+import util
+
+class Grades:
+ "A data structure for project grades, along with formatting code to display them"
+ def __init__(self, projectName, questionsAndMaxesList,
+ gsOutput=False, edxOutput=False, muteOutput=False):
+ """
+ Defines the grading scheme for a project
+ projectName: project name
+ questionsAndMaxesDict: a list of (question name, max points per question)
+ """
+ self.questions = [el[0] for el in questionsAndMaxesList]
+ self.maxes = dict(questionsAndMaxesList)
+ self.points = Counter()
+ self.messages = dict([(q, []) for q in self.questions])
+ self.project = projectName
+ self.start = time.localtime()[1:6]
+ self.sane = True # Sanity checks
+ self.currentQuestion = None # Which question we're grading
+ self.edxOutput = edxOutput
+ self.gsOutput = gsOutput # GradeScope output
+ self.mute = muteOutput
+ self.prereqs = defaultdict(set)
+
+ #print 'Autograder transcript for %s' % self.project
+ print 'Starting on %d-%d at %d:%02d:%02d' % self.start
+
+ def addPrereq(self, question, prereq):
+ self.prereqs[question].add(prereq)
+
+ def grade(self, gradingModule, exceptionMap = {}, bonusPic = False):
+ """
+ Grades each question
+ gradingModule: the module with all the grading functions (pass in with sys.modules[__name__])
+ """
+
+ completedQuestions = set([])
+ for q in self.questions:
+ print '\nQuestion %s' % q
+ print '=' * (9 + len(q))
+ print
+ self.currentQuestion = q
+
+ incompleted = self.prereqs[q].difference(completedQuestions)
+ if len(incompleted) > 0:
+ prereq = incompleted.pop()
+ print \
+"""*** NOTE: Make sure to complete Question %s before working on Question %s,
+*** because Question %s builds upon your answer for Question %s.
+""" % (prereq, q, q, prereq)
+ continue
+
+ if self.mute: util.mutePrint()
+ try:
+ util.TimeoutFunction(getattr(gradingModule, q),1800)(self) # Call the question's function
+ #TimeoutFunction(getattr(gradingModule, q),1200)(self) # Call the question's function
+ except Exception, inst:
+ self.addExceptionMessage(q, inst, traceback)
+ self.addErrorHints(exceptionMap, inst, q[1])
+ except:
+ self.fail('FAIL: Terminated with a string exception.')
+ finally:
+ if self.mute: util.unmutePrint()
+
+ if self.points[q] >= self.maxes[q]:
+ completedQuestions.add(q)
+
+ print '\n### Question %s: %d/%d ###\n' % (q, self.points[q], self.maxes[q])
+
+
+ print '\nFinished at %d:%02d:%02d' % time.localtime()[3:6]
+ print "\nProvisional grades\n=================="
+
+ for q in self.questions:
+ print 'Question %s: %d/%d' % (q, self.points[q], self.maxes[q])
+ print '------------------'
+ print 'Total: %d/%d' % (self.points.totalCount(), sum(self.maxes.values()))
+ if bonusPic and self.points.totalCount() == 25:
+ print """
+
+ ALL HAIL GRANDPAC.
+ LONG LIVE THE GHOSTBUSTING KING.
+
+ --- ---- ---
+ | \ / + \ / |
+ | + \--/ \--/ + |
+ | + + |
+ | + + + |
+ @@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ \ / @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ V \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ \ / @@@@@@@@@@@@@@@@@@@@@@@@@@
+ V @@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@
+ /\ @@@@@@@@@@@@@@@@@@@@@@
+ / \ @@@@@@@@@@@@@@@@@@@@@@@@@
+ /\ / @@@@@@@@@@@@@@@@@@@@@@@@@@@
+ / \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ / @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@
+
+"""
+ print """
+Your grades are NOT yet registered. To register your grades, make sure
+to follow your instructor's guidelines to receive credit on your project.
+"""
+
+ if self.edxOutput:
+ self.produceOutput()
+ if self.gsOutput:
+ self.produceGradeScopeOutput()
+
+ def addExceptionMessage(self, q, inst, traceback):
+ """
+ Method to format the exception message, this is more complicated because
+ we need to cgi.escape the traceback but wrap the exception in a tag
+ """
+ self.fail('FAIL: Exception raised: %s' % inst)
+ self.addMessage('')
+ for line in traceback.format_exc().split('\n'):
+ self.addMessage(line)
+
+ def addErrorHints(self, exceptionMap, errorInstance, questionNum):
+ typeOf = str(type(errorInstance))
+ questionName = 'q' + questionNum
+ errorHint = ''
+
+ # question specific error hints
+ if exceptionMap.get(questionName):
+ questionMap = exceptionMap.get(questionName)
+ if (questionMap.get(typeOf)):
+ errorHint = questionMap.get(typeOf)
+ # fall back to general error messages if a question specific
+ # one does not exist
+ if (exceptionMap.get(typeOf)):
+ errorHint = exceptionMap.get(typeOf)
+
+ # dont include the HTML if we have no error hint
+ if not errorHint:
+ return ''
+
+ for line in errorHint.split('\n'):
+ self.addMessage(line)
+
+ def produceGradeScopeOutput(self):
+ out_dct = {}
+
+ # total of entire submission
+ total_possible = sum(self.maxes.values())
+ total_score = sum(self.points.values())
+ out_dct['score'] = total_score
+ out_dct['max_score'] = total_possible
+ out_dct['output'] = "Total score (%d / %d)" % (total_score, total_possible)
+
+ # individual tests
+ tests_out = []
+ for name in self.questions:
+ test_out = {}
+ # test name
+ test_out['name'] = name
+ # test score
+ test_out['score'] = self.points[name]
+ test_out['max_score'] = self.maxes[name]
+ # others
+ is_correct = self.points[name] >= self.maxes[name]
+ test_out['output'] = " Question {num} ({points}/{max}) {correct}".format(
+ num=(name[1] if len(name) == 2 else name),
+ points=test_out['score'],
+ max=test_out['max_score'],
+ correct=('X' if not is_correct else ''),
+ )
+ test_out['tags'] = []
+ tests_out.append(test_out)
+ out_dct['tests'] = tests_out
+
+ # file output
+ with open('gradescope_response.json', 'w') as outfile:
+ json.dump(out_dct, outfile)
+ return
+
+ def produceOutput(self):
+ edxOutput = open('edx_response.html', 'w')
+ edxOutput.write("")
+
+ # first sum
+ total_possible = sum(self.maxes.values())
+ total_score = sum(self.points.values())
+ checkOrX = '
'
+ if (total_score >= total_possible):
+ checkOrX = '
'
+ header = """
+
+ Total score ({total_score} / {total_possible})
+
+ """.format(total_score = total_score,
+ total_possible = total_possible,
+ checkOrX = checkOrX
+ )
+ edxOutput.write(header)
+
+ for q in self.questions:
+ if len(q) == 2:
+ name = q[1]
+ else:
+ name = q
+ checkOrX = '
'
+ if (self.points[q] >= self.maxes[q]):
+ checkOrX = '
'
+ #messages = '\n
\n'.join(self.messages[q])
+ messages = "
%s
" % '\n'.join(self.messages[q])
+ output = """
+
+
+
+ Question {q} ({points}/{max}) {checkOrX}
+
+
+ {messages}
+
+
+
+ """.format(q = name,
+ max = self.maxes[q],
+ messages = messages,
+ checkOrX = checkOrX,
+ points = self.points[q]
+ )
+ # print "*** output for Question %s " % q[1]
+ # print output
+ edxOutput.write(output)
+ edxOutput.write("
")
+ edxOutput.close()
+ edxOutput = open('edx_grade', 'w')
+ edxOutput.write(str(self.points.totalCount()))
+ edxOutput.close()
+
+ def fail(self, message, raw=False):
+ "Sets sanity check bit to false and outputs a message"
+ self.sane = False
+ self.assignZeroCredit()
+ self.addMessage(message, raw)
+
+ def assignZeroCredit(self):
+ self.points[self.currentQuestion] = 0
+
+ def addPoints(self, amt):
+ self.points[self.currentQuestion] += amt
+
+ def deductPoints(self, amt):
+ self.points[self.currentQuestion] -= amt
+
+ def assignFullCredit(self, message="", raw=False):
+ self.points[self.currentQuestion] = self.maxes[self.currentQuestion]
+ if message != "":
+ self.addMessage(message, raw)
+
+ def addMessage(self, message, raw=False):
+ if not raw:
+ # We assume raw messages, formatted for HTML, are printed separately
+ if self.mute: util.unmutePrint()
+ print '*** ' + message
+ if self.mute: util.mutePrint()
+ message = cgi.escape(message)
+ self.messages[self.currentQuestion].append(message)
+
+ def addMessageToEmail(self, message):
+ print "WARNING**** addMessageToEmail is deprecated %s" % message
+ for line in message.split('\n'):
+ pass
+ #print '%%% ' + line + ' %%%'
+ #self.messages[self.currentQuestion].append(line)
+
+
+
+
+
+class Counter(dict):
+ """
+ Dict with default 0
+ """
+ def __getitem__(self, idx):
+ try:
+ return dict.__getitem__(self, idx)
+ except KeyError:
+ return 0
+
+ def totalCount(self):
+ """
+ Returns the sum of counts for all keys.
+ """
+ return sum(self.values())
+
diff --git a/search/graphicsDisplay.py b/search/graphicsDisplay.py
new file mode 100644
index 0000000..1bfe1b3
--- /dev/null
+++ b/search/graphicsDisplay.py
@@ -0,0 +1,679 @@
+# graphicsDisplay.py
+# ------------------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+from graphicsUtils import *
+import math, time
+from game import Directions
+
+###########################
+# GRAPHICS DISPLAY CODE #
+###########################
+
+# Most code by Dan Klein and John Denero written or rewritten for cs188, UC Berkeley.
+# Some code from a Pacman implementation by LiveWires, and used / modified with permission.
+
+DEFAULT_GRID_SIZE = 30.0
+INFO_PANE_HEIGHT = 35
+BACKGROUND_COLOR = formatColor(0,0,0)
+WALL_COLOR = formatColor(0.0/255.0, 51.0/255.0, 255.0/255.0)
+INFO_PANE_COLOR = formatColor(.4,.4,0)
+SCORE_COLOR = formatColor(.9, .9, .9)
+PACMAN_OUTLINE_WIDTH = 2
+PACMAN_CAPTURE_OUTLINE_WIDTH = 4
+
+GHOST_COLORS = []
+GHOST_COLORS.append(formatColor(.9,0,0)) # Red
+GHOST_COLORS.append(formatColor(0,.3,.9)) # Blue
+GHOST_COLORS.append(formatColor(.98,.41,.07)) # Orange
+GHOST_COLORS.append(formatColor(.1,.75,.7)) # Green
+GHOST_COLORS.append(formatColor(1.0,0.6,0.0)) # Yellow
+GHOST_COLORS.append(formatColor(.4,0.13,0.91)) # Purple
+
+TEAM_COLORS = GHOST_COLORS[:2]
+
+GHOST_SHAPE = [
+ ( 0, 0.3 ),
+ ( 0.25, 0.75 ),
+ ( 0.5, 0.3 ),
+ ( 0.75, 0.75 ),
+ ( 0.75, -0.5 ),
+ ( 0.5, -0.75 ),
+ (-0.5, -0.75 ),
+ (-0.75, -0.5 ),
+ (-0.75, 0.75 ),
+ (-0.5, 0.3 ),
+ (-0.25, 0.75 )
+ ]
+GHOST_SIZE = 0.65
+SCARED_COLOR = formatColor(1,1,1)
+
+GHOST_VEC_COLORS = map(colorToVector, GHOST_COLORS)
+
+PACMAN_COLOR = formatColor(255.0/255.0,255.0/255.0,61.0/255)
+PACMAN_SCALE = 0.5
+#pacman_speed = 0.25
+
+# Food
+FOOD_COLOR = formatColor(1,1,1)
+FOOD_SIZE = 0.1
+
+# Laser
+LASER_COLOR = formatColor(1,0,0)
+LASER_SIZE = 0.02
+
+# Capsule graphics
+CAPSULE_COLOR = formatColor(1,1,1)
+CAPSULE_SIZE = 0.25
+
+# Drawing walls
+WALL_RADIUS = 0.15
+
+class InfoPane:
+ def __init__(self, layout, gridSize):
+ self.gridSize = gridSize
+ self.width = (layout.width) * gridSize
+ self.base = (layout.height + 1) * gridSize
+ self.height = INFO_PANE_HEIGHT
+ self.fontSize = 24
+ self.textColor = PACMAN_COLOR
+ self.drawPane()
+
+ def toScreen(self, pos, y = None):
+ """
+ Translates a point relative from the bottom left of the info pane.
+ """
+ if y == None:
+ x,y = pos
+ else:
+ x = pos
+
+ x = self.gridSize + x # Margin
+ y = self.base + y
+ return x,y
+
+ def drawPane(self):
+ self.scoreText = text( self.toScreen(0, 0 ), self.textColor, "SCORE: 0", "Times", self.fontSize, "bold")
+
+ def initializeGhostDistances(self, distances):
+ self.ghostDistanceText = []
+
+ size = 20
+ if self.width < 240:
+ size = 12
+ if self.width < 160:
+ size = 10
+
+ for i, d in enumerate(distances):
+ t = text( self.toScreen(self.width/2 + self.width/8 * i, 0), GHOST_COLORS[i+1], d, "Times", size, "bold")
+ self.ghostDistanceText.append(t)
+
+ def updateScore(self, score):
+ changeText(self.scoreText, "SCORE: % 4d" % score)
+
+ def setTeam(self, isBlue):
+ text = "RED TEAM"
+ if isBlue: text = "BLUE TEAM"
+ self.teamText = text( self.toScreen(300, 0 ), self.textColor, text, "Times", self.fontSize, "bold")
+
+ def updateGhostDistances(self, distances):
+ if len(distances) == 0: return
+ if 'ghostDistanceText' not in dir(self): self.initializeGhostDistances(distances)
+ else:
+ for i, d in enumerate(distances):
+ changeText(self.ghostDistanceText[i], d)
+
+ def drawGhost(self):
+ pass
+
+ def drawPacman(self):
+ pass
+
+ def drawWarning(self):
+ pass
+
+ def clearIcon(self):
+ pass
+
+ def updateMessage(self, message):
+ pass
+
+ def clearMessage(self):
+ pass
+
+
+class PacmanGraphics:
+ def __init__(self, zoom=1.0, frameTime=0.0, capture=False):
+ self.have_window = 0
+ self.currentGhostImages = {}
+ self.pacmanImage = None
+ self.zoom = zoom
+ self.gridSize = DEFAULT_GRID_SIZE * zoom
+ self.capture = capture
+ self.frameTime = frameTime
+
+ def checkNullDisplay(self):
+ return False
+
+ def initialize(self, state, isBlue = False):
+ self.isBlue = isBlue
+ self.startGraphics(state)
+
+ # self.drawDistributions(state)
+ self.distributionImages = None # Initialized lazily
+ self.drawStaticObjects(state)
+ self.drawAgentObjects(state)
+
+ # Information
+ self.previousState = state
+
+ def startGraphics(self, state):
+ self.layout = state.layout
+ layout = self.layout
+ self.width = layout.width
+ self.height = layout.height
+ self.make_window(self.width, self.height)
+ self.infoPane = InfoPane(layout, self.gridSize)
+ self.currentState = layout
+
+ def drawDistributions(self, state):
+ walls = state.layout.walls
+ dist = []
+ for x in range(walls.width):
+ distx = []
+ dist.append(distx)
+ for y in range(walls.height):
+ ( screen_x, screen_y ) = self.to_screen( (x, y) )
+ block = square( (screen_x, screen_y),
+ 0.5 * self.gridSize,
+ color = BACKGROUND_COLOR,
+ filled = 1, behind=2)
+ distx.append(block)
+ self.distributionImages = dist
+
+ def drawStaticObjects(self, state):
+ layout = self.layout
+ self.drawWalls(layout.walls)
+ self.food = self.drawFood(layout.food)
+ self.capsules = self.drawCapsules(layout.capsules)
+ refresh()
+
+ def drawAgentObjects(self, state):
+ self.agentImages = [] # (agentState, image)
+ for index, agent in enumerate(state.agentStates):
+ if agent.isPacman:
+ image = self.drawPacman(agent, index)
+ self.agentImages.append( (agent, image) )
+ else:
+ image = self.drawGhost(agent, index)
+ self.agentImages.append( (agent, image) )
+ refresh()
+
+ def swapImages(self, agentIndex, newState):
+ """
+ Changes an image from a ghost to a pacman or vis versa (for capture)
+ """
+ prevState, prevImage = self.agentImages[agentIndex]
+ for item in prevImage: remove_from_screen(item)
+ if newState.isPacman:
+ image = self.drawPacman(newState, agentIndex)
+ self.agentImages[agentIndex] = (newState, image )
+ else:
+ image = self.drawGhost(newState, agentIndex)
+ self.agentImages[agentIndex] = (newState, image )
+ refresh()
+
+ def update(self, newState):
+ agentIndex = newState._agentMoved
+ agentState = newState.agentStates[agentIndex]
+
+ if self.agentImages[agentIndex][0].isPacman != agentState.isPacman: self.swapImages(agentIndex, agentState)
+ prevState, prevImage = self.agentImages[agentIndex]
+ if agentState.isPacman:
+ self.animatePacman(agentState, prevState, prevImage)
+ else:
+ self.moveGhost(agentState, agentIndex, prevState, prevImage)
+ self.agentImages[agentIndex] = (agentState, prevImage)
+
+ if newState._foodEaten != None:
+ self.removeFood(newState._foodEaten, self.food)
+ if newState._capsuleEaten != None:
+ self.removeCapsule(newState._capsuleEaten, self.capsules)
+ self.infoPane.updateScore(newState.score)
+ if 'ghostDistances' in dir(newState):
+ self.infoPane.updateGhostDistances(newState.ghostDistances)
+
+ def make_window(self, width, height):
+ grid_width = (width-1) * self.gridSize
+ grid_height = (height-1) * self.gridSize
+ screen_width = 2*self.gridSize + grid_width
+ screen_height = 2*self.gridSize + grid_height + INFO_PANE_HEIGHT
+
+ begin_graphics(screen_width,
+ screen_height,
+ BACKGROUND_COLOR,
+ "CS188 Pacman")
+
+ def drawPacman(self, pacman, index):
+ position = self.getPosition(pacman)
+ screen_point = self.to_screen(position)
+ endpoints = self.getEndpoints(self.getDirection(pacman))
+
+ width = PACMAN_OUTLINE_WIDTH
+ outlineColor = PACMAN_COLOR
+ fillColor = PACMAN_COLOR
+
+ if self.capture:
+ outlineColor = TEAM_COLORS[index % 2]
+ fillColor = GHOST_COLORS[index]
+ width = PACMAN_CAPTURE_OUTLINE_WIDTH
+
+ return [circle(screen_point, PACMAN_SCALE * self.gridSize,
+ fillColor = fillColor, outlineColor = outlineColor,
+ endpoints = endpoints,
+ width = width)]
+
+ def getEndpoints(self, direction, position=(0,0)):
+ x, y = position
+ pos = x - int(x) + y - int(y)
+ width = 30 + 80 * math.sin(math.pi* pos)
+
+ delta = width / 2
+ if (direction == 'West'):
+ endpoints = (180+delta, 180-delta)
+ elif (direction == 'North'):
+ endpoints = (90+delta, 90-delta)
+ elif (direction == 'South'):
+ endpoints = (270+delta, 270-delta)
+ else:
+ endpoints = (0+delta, 0-delta)
+ return endpoints
+
+ def movePacman(self, position, direction, image):
+ screenPosition = self.to_screen(position)
+ endpoints = self.getEndpoints( direction, position )
+ r = PACMAN_SCALE * self.gridSize
+ moveCircle(image[0], screenPosition, r, endpoints)
+ refresh()
+
+ def animatePacman(self, pacman, prevPacman, image):
+ if self.frameTime < 0:
+ print 'Press any key to step forward, "q" to play'
+ keys = wait_for_keys()
+ if 'q' in keys:
+ self.frameTime = 0.1
+ if self.frameTime > 0.01 or self.frameTime < 0:
+ start = time.time()
+ fx, fy = self.getPosition(prevPacman)
+ px, py = self.getPosition(pacman)
+ frames = 4.0
+ for i in range(1,int(frames) + 1):
+ pos = px*i/frames + fx*(frames-i)/frames, py*i/frames + fy*(frames-i)/frames
+ self.movePacman(pos, self.getDirection(pacman), image)
+ refresh()
+ sleep(abs(self.frameTime) / frames)
+ else:
+ self.movePacman(self.getPosition(pacman), self.getDirection(pacman), image)
+ refresh()
+
+ def getGhostColor(self, ghost, ghostIndex):
+ if ghost.scaredTimer > 0:
+ return SCARED_COLOR
+ else:
+ return GHOST_COLORS[ghostIndex]
+
+ def drawGhost(self, ghost, agentIndex):
+ pos = self.getPosition(ghost)
+ dir = self.getDirection(ghost)
+ (screen_x, screen_y) = (self.to_screen(pos) )
+ coords = []
+ for (x, y) in GHOST_SHAPE:
+ coords.append((x*self.gridSize*GHOST_SIZE + screen_x, y*self.gridSize*GHOST_SIZE + screen_y))
+
+ colour = self.getGhostColor(ghost, agentIndex)
+ body = polygon(coords, colour, filled = 1)
+ WHITE = formatColor(1.0, 1.0, 1.0)
+ BLACK = formatColor(0.0, 0.0, 0.0)
+
+ dx = 0
+ dy = 0
+ if dir == 'North':
+ dy = -0.2
+ if dir == 'South':
+ dy = 0.2
+ if dir == 'East':
+ dx = 0.2
+ if dir == 'West':
+ dx = -0.2
+ leftEye = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE)
+ rightEye = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE)
+ leftPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK)
+ rightPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK)
+ ghostImageParts = []
+ ghostImageParts.append(body)
+ ghostImageParts.append(leftEye)
+ ghostImageParts.append(rightEye)
+ ghostImageParts.append(leftPupil)
+ ghostImageParts.append(rightPupil)
+
+ return ghostImageParts
+
+ def moveEyes(self, pos, dir, eyes):
+ (screen_x, screen_y) = (self.to_screen(pos) )
+ dx = 0
+ dy = 0
+ if dir == 'North':
+ dy = -0.2
+ if dir == 'South':
+ dy = 0.2
+ if dir == 'East':
+ dx = 0.2
+ if dir == 'West':
+ dx = -0.2
+ moveCircle(eyes[0],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2)
+ moveCircle(eyes[1],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2)
+ moveCircle(eyes[2],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08)
+ moveCircle(eyes[3],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08)
+
+ def moveGhost(self, ghost, ghostIndex, prevGhost, ghostImageParts):
+ old_x, old_y = self.to_screen(self.getPosition(prevGhost))
+ new_x, new_y = self.to_screen(self.getPosition(ghost))
+ delta = new_x - old_x, new_y - old_y
+
+ for ghostImagePart in ghostImageParts:
+ move_by(ghostImagePart, delta)
+ refresh()
+
+ if ghost.scaredTimer > 0:
+ color = SCARED_COLOR
+ else:
+ color = GHOST_COLORS[ghostIndex]
+ edit(ghostImageParts[0], ('fill', color), ('outline', color))
+ self.moveEyes(self.getPosition(ghost), self.getDirection(ghost), ghostImageParts[-4:])
+ refresh()
+
+ def getPosition(self, agentState):
+ if agentState.configuration == None: return (-1000, -1000)
+ return agentState.getPosition()
+
+ def getDirection(self, agentState):
+ if agentState.configuration == None: return Directions.STOP
+ return agentState.configuration.getDirection()
+
+ def finish(self):
+ end_graphics()
+
+ def to_screen(self, point):
+ ( x, y ) = point
+ #y = self.height - y
+ x = (x + 1)*self.gridSize
+ y = (self.height - y)*self.gridSize
+ return ( x, y )
+
+ # Fixes some TK issue with off-center circles
+ def to_screen2(self, point):
+ ( x, y ) = point
+ #y = self.height - y
+ x = (x + 1)*self.gridSize
+ y = (self.height - y)*self.gridSize
+ return ( x, y )
+
+ def drawWalls(self, wallMatrix):
+ wallColor = WALL_COLOR
+ for xNum, x in enumerate(wallMatrix):
+ if self.capture and (xNum * 2) < wallMatrix.width: wallColor = TEAM_COLORS[0]
+ if self.capture and (xNum * 2) >= wallMatrix.width: wallColor = TEAM_COLORS[1]
+
+ for yNum, cell in enumerate(x):
+ if cell: # There's a wall here
+ pos = (xNum, yNum)
+ screen = self.to_screen(pos)
+ screen2 = self.to_screen2(pos)
+
+ # draw each quadrant of the square based on adjacent walls
+ wIsWall = self.isWall(xNum-1, yNum, wallMatrix)
+ eIsWall = self.isWall(xNum+1, yNum, wallMatrix)
+ nIsWall = self.isWall(xNum, yNum+1, wallMatrix)
+ sIsWall = self.isWall(xNum, yNum-1, wallMatrix)
+ nwIsWall = self.isWall(xNum-1, yNum+1, wallMatrix)
+ swIsWall = self.isWall(xNum-1, yNum-1, wallMatrix)
+ neIsWall = self.isWall(xNum+1, yNum+1, wallMatrix)
+ seIsWall = self.isWall(xNum+1, yNum-1, wallMatrix)
+
+ # NE quadrant
+ if (not nIsWall) and (not eIsWall):
+ # inner circle
+ circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (0,91), 'arc')
+ if (nIsWall) and (not eIsWall):
+ # vertical line
+ line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor)
+ if (not nIsWall) and (eIsWall):
+ # horizontal line
+ line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor)
+ if (nIsWall) and (eIsWall) and (not neIsWall):
+ # outer circle
+ circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (180,271), 'arc')
+ line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor)
+ line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5))), wallColor)
+
+ # NW quadrant
+ if (not nIsWall) and (not wIsWall):
+ # inner circle
+ circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (90,181), 'arc')
+ if (nIsWall) and (not wIsWall):
+ # vertical line
+ line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor)
+ if (not nIsWall) and (wIsWall):
+ # horizontal line
+ line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-1, self.gridSize*(-1)*WALL_RADIUS)), wallColor)
+ if (nIsWall) and (wIsWall) and (not nwIsWall):
+ # outer circle
+ circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (270,361), 'arc')
+ line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(-1)*WALL_RADIUS)), wallColor)
+ line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5))), wallColor)
+
+ # SE quadrant
+ if (not sIsWall) and (not eIsWall):
+ # inner circle
+ circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (270,361), 'arc')
+ if (sIsWall) and (not eIsWall):
+ # vertical line
+ line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor)
+ if (not sIsWall) and (eIsWall):
+ # horizontal line
+ line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(1)*WALL_RADIUS)), wallColor)
+ if (sIsWall) and (eIsWall) and (not seIsWall):
+ # outer circle
+ circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (90,181), 'arc')
+ line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5, self.gridSize*(1)*WALL_RADIUS)), wallColor)
+ line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5))), wallColor)
+
+ # SW quadrant
+ if (not sIsWall) and (not wIsWall):
+ # inner circle
+ circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (180,271), 'arc')
+ if (sIsWall) and (not wIsWall):
+ # vertical line
+ line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor)
+ if (not sIsWall) and (wIsWall):
+ # horizontal line
+ line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-1, self.gridSize*(1)*WALL_RADIUS)), wallColor)
+ if (sIsWall) and (wIsWall) and (not swIsWall):
+ # outer circle
+ circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (0,91), 'arc')
+ line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(1)*WALL_RADIUS)), wallColor)
+ line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5))), wallColor)
+
+ def isWall(self, x, y, walls):
+ if x < 0 or y < 0:
+ return False
+ if x >= walls.width or y >= walls.height:
+ return False
+ return walls[x][y]
+
+ def drawFood(self, foodMatrix ):
+ foodImages = []
+ color = FOOD_COLOR
+ for xNum, x in enumerate(foodMatrix):
+ if self.capture and (xNum * 2) <= foodMatrix.width: color = TEAM_COLORS[0]
+ if self.capture and (xNum * 2) > foodMatrix.width: color = TEAM_COLORS[1]
+ imageRow = []
+ foodImages.append(imageRow)
+ for yNum, cell in enumerate(x):
+ if cell: # There's food here
+ screen = self.to_screen((xNum, yNum ))
+ dot = circle( screen,
+ FOOD_SIZE * self.gridSize,
+ outlineColor = color, fillColor = color,
+ width = 1)
+ imageRow.append(dot)
+ else:
+ imageRow.append(None)
+ return foodImages
+
+ def drawCapsules(self, capsules ):
+ capsuleImages = {}
+ for capsule in capsules:
+ ( screen_x, screen_y ) = self.to_screen(capsule)
+ dot = circle( (screen_x, screen_y),
+ CAPSULE_SIZE * self.gridSize,
+ outlineColor = CAPSULE_COLOR,
+ fillColor = CAPSULE_COLOR,
+ width = 1)
+ capsuleImages[capsule] = dot
+ return capsuleImages
+
+ def removeFood(self, cell, foodImages ):
+ x, y = cell
+ remove_from_screen(foodImages[x][y])
+
+ def removeCapsule(self, cell, capsuleImages ):
+ x, y = cell
+ remove_from_screen(capsuleImages[(x, y)])
+
+ def drawExpandedCells(self, cells):
+ """
+ Draws an overlay of expanded grid positions for search agents
+ """
+ n = float(len(cells))
+ baseColor = [1.0, 0.0, 0.0]
+ self.clearExpandedCells()
+ self.expandedCells = []
+ for k, cell in enumerate(cells):
+ screenPos = self.to_screen( cell)
+ cellColor = formatColor(*[(n-k) * c * .5 / n + .25 for c in baseColor])
+ block = square(screenPos,
+ 0.5 * self.gridSize,
+ color = cellColor,
+ filled = 1, behind=2)
+ self.expandedCells.append(block)
+ if self.frameTime < 0:
+ refresh()
+
+ def clearExpandedCells(self):
+ if 'expandedCells' in dir(self) and len(self.expandedCells) > 0:
+ for cell in self.expandedCells:
+ remove_from_screen(cell)
+
+
+ def updateDistributions(self, distributions):
+ "Draws an agent's belief distributions"
+ # copy all distributions so we don't change their state
+ distributions = map(lambda x: x.copy(), distributions)
+ if self.distributionImages == None:
+ self.drawDistributions(self.previousState)
+ for x in range(len(self.distributionImages)):
+ for y in range(len(self.distributionImages[0])):
+ image = self.distributionImages[x][y]
+ weights = [dist[ (x,y) ] for dist in distributions]
+
+ if sum(weights) != 0:
+ pass
+ # Fog of war
+ color = [0.0,0.0,0.0]
+ colors = GHOST_VEC_COLORS[1:] # With Pacman
+ if self.capture: colors = GHOST_VEC_COLORS
+ for weight, gcolor in zip(weights, colors):
+ color = [min(1.0, c + 0.95 * g * weight ** .3) for c,g in zip(color, gcolor)]
+ changeColor(image, formatColor(*color))
+ refresh()
+
+class FirstPersonPacmanGraphics(PacmanGraphics):
+ def __init__(self, zoom = 1.0, showGhosts = True, capture = False, frameTime=0):
+ PacmanGraphics.__init__(self, zoom, frameTime=frameTime)
+ self.showGhosts = showGhosts
+ self.capture = capture
+
+ def initialize(self, state, isBlue = False):
+
+ self.isBlue = isBlue
+ PacmanGraphics.startGraphics(self, state)
+ # Initialize distribution images
+ walls = state.layout.walls
+ dist = []
+ self.layout = state.layout
+
+ # Draw the rest
+ self.distributionImages = None # initialize lazily
+ self.drawStaticObjects(state)
+ self.drawAgentObjects(state)
+
+ # Information
+ self.previousState = state
+
+ def lookAhead(self, config, state):
+ if config.getDirection() == 'Stop':
+ return
+ else:
+ pass
+ # Draw relevant ghosts
+ allGhosts = state.getGhostStates()
+ visibleGhosts = state.getVisibleGhosts()
+ for i, ghost in enumerate(allGhosts):
+ if ghost in visibleGhosts:
+ self.drawGhost(ghost, i)
+ else:
+ self.currentGhostImages[i] = None
+
+ def getGhostColor(self, ghost, ghostIndex):
+ return GHOST_COLORS[ghostIndex]
+
+ def getPosition(self, ghostState):
+ if not self.showGhosts and not ghostState.isPacman and ghostState.getPosition()[1] > 1:
+ return (-1000, -1000)
+ else:
+ return PacmanGraphics.getPosition(self, ghostState)
+
+def add(x, y):
+ return (x[0] + y[0], x[1] + y[1])
+
+
+# Saving graphical output
+# -----------------------
+# Note: to make an animated gif from this postscript output, try the command:
+# convert -delay 7 -loop 1 -compress lzw -layers optimize frame* out.gif
+# convert is part of imagemagick (freeware)
+
+SAVE_POSTSCRIPT = False
+POSTSCRIPT_OUTPUT_DIR = 'frames'
+FRAME_NUMBER = 0
+import os
+
+def saveFrame():
+ "Saves the current graphical output as a postscript file"
+ global SAVE_POSTSCRIPT, FRAME_NUMBER, POSTSCRIPT_OUTPUT_DIR
+ if not SAVE_POSTSCRIPT: return
+ if not os.path.exists(POSTSCRIPT_OUTPUT_DIR): os.mkdir(POSTSCRIPT_OUTPUT_DIR)
+ name = os.path.join(POSTSCRIPT_OUTPUT_DIR, 'frame_%08d.ps' % FRAME_NUMBER)
+ FRAME_NUMBER += 1
+ writePostscript(name) # writes the current canvas
diff --git a/search/graphicsDisplay.pyc b/search/graphicsDisplay.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..403b55df0d43d71e80d93d4223e7b4f8c316c20f
GIT binary patch
literal 24599
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%0DD@%VACnHrxh}=#P@rToMneYZ6pI1h
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
NF5ROSWD)K5e*mGK?`Z%4
literal 0
HcmV?d00001
diff --git a/search/graphicsUtils.py b/search/graphicsUtils.py
new file mode 100644
index 0000000..b80d3d2
--- /dev/null
+++ b/search/graphicsUtils.py
@@ -0,0 +1,402 @@
+# graphicsUtils.py
+# ----------------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+import sys
+import math
+import random
+import string
+import time
+import types
+import Tkinter
+import os.path
+
+_Windows = sys.platform == 'win32' # True if on Win95/98/NT
+
+_root_window = None # The root window for graphics output
+_canvas = None # The canvas which holds graphics
+_canvas_xs = None # Size of canvas object
+_canvas_ys = None
+_canvas_x = None # Current position on canvas
+_canvas_y = None
+_canvas_col = None # Current colour (set to black below)
+_canvas_tsize = 12
+_canvas_tserifs = 0
+
+def formatColor(r, g, b):
+ return '#%02x%02x%02x' % (int(r * 255), int(g * 255), int(b * 255))
+
+def colorToVector(color):
+ return map(lambda x: int(x, 16) / 256.0, [color[1:3], color[3:5], color[5:7]])
+
+if _Windows:
+ _canvas_tfonts = ['times new roman', 'lucida console']
+else:
+ _canvas_tfonts = ['times', 'lucidasans-24']
+ pass # XXX need defaults here
+
+def sleep(secs):
+ global _root_window
+ if _root_window == None:
+ time.sleep(secs)
+ else:
+ _root_window.update_idletasks()
+ _root_window.after(int(1000 * secs), _root_window.quit)
+ _root_window.mainloop()
+
+def begin_graphics(width=640, height=480, color=formatColor(0, 0, 0), title=None):
+
+ global _root_window, _canvas, _canvas_x, _canvas_y, _canvas_xs, _canvas_ys, _bg_color
+
+ # Check for duplicate call
+ if _root_window is not None:
+ # Lose the window.
+ _root_window.destroy()
+
+ # Save the canvas size parameters
+ _canvas_xs, _canvas_ys = width - 1, height - 1
+ _canvas_x, _canvas_y = 0, _canvas_ys
+ _bg_color = color
+
+ # Create the root window
+ _root_window = Tkinter.Tk()
+ _root_window.protocol('WM_DELETE_WINDOW', _destroy_window)
+ _root_window.title(title or 'Graphics Window')
+ _root_window.resizable(0, 0)
+
+ # Create the canvas object
+ try:
+ _canvas = Tkinter.Canvas(_root_window, width=width, height=height)
+ _canvas.pack()
+ draw_background()
+ _canvas.update()
+ except:
+ _root_window = None
+ raise
+
+ # Bind to key-down and key-up events
+ _root_window.bind( "", _keypress )
+ _root_window.bind( "", _keyrelease )
+ _root_window.bind( "", _clear_keys )
+ _root_window.bind( "", _clear_keys )
+ _root_window.bind( "", _leftclick )
+ _root_window.bind( "", _rightclick )
+ _root_window.bind( "", _rightclick )
+ _root_window.bind( "", _ctrl_leftclick)
+ _clear_keys()
+
+_leftclick_loc = None
+_rightclick_loc = None
+_ctrl_leftclick_loc = None
+
+def _leftclick(event):
+ global _leftclick_loc
+ _leftclick_loc = (event.x, event.y)
+
+def _rightclick(event):
+ global _rightclick_loc
+ _rightclick_loc = (event.x, event.y)
+
+def _ctrl_leftclick(event):
+ global _ctrl_leftclick_loc
+ _ctrl_leftclick_loc = (event.x, event.y)
+
+def wait_for_click():
+ while True:
+ global _leftclick_loc
+ global _rightclick_loc
+ global _ctrl_leftclick_loc
+ if _leftclick_loc != None:
+ val = _leftclick_loc
+ _leftclick_loc = None
+ return val, 'left'
+ if _rightclick_loc != None:
+ val = _rightclick_loc
+ _rightclick_loc = None
+ return val, 'right'
+ if _ctrl_leftclick_loc != None:
+ val = _ctrl_leftclick_loc
+ _ctrl_leftclick_loc = None
+ return val, 'ctrl_left'
+ sleep(0.05)
+
+def draw_background():
+ corners = [(0,0), (0, _canvas_ys), (_canvas_xs, _canvas_ys), (_canvas_xs, 0)]
+ polygon(corners, _bg_color, fillColor=_bg_color, filled=True, smoothed=False)
+
+def _destroy_window(event=None):
+ sys.exit(0)
+# global _root_window
+# _root_window.destroy()
+# _root_window = None
+ #print "DESTROY"
+
+def end_graphics():
+ global _root_window, _canvas, _mouse_enabled
+ try:
+ try:
+ sleep(1)
+ if _root_window != None:
+ _root_window.destroy()
+ except SystemExit, e:
+ print 'Ending graphics raised an exception:', e
+ finally:
+ _root_window = None
+ _canvas = None
+ _mouse_enabled = 0
+ _clear_keys()
+
+def clear_screen(background=None):
+ global _canvas_x, _canvas_y
+ _canvas.delete('all')
+ draw_background()
+ _canvas_x, _canvas_y = 0, _canvas_ys
+
+def polygon(coords, outlineColor, fillColor=None, filled=1, smoothed=1, behind=0, width=1):
+ c = []
+ for coord in coords:
+ c.append(coord[0])
+ c.append(coord[1])
+ if fillColor == None: fillColor = outlineColor
+ if filled == 0: fillColor = ""
+ poly = _canvas.create_polygon(c, outline=outlineColor, fill=fillColor, smooth=smoothed, width=width)
+ if behind > 0:
+ _canvas.tag_lower(poly, behind) # Higher should be more visible
+ return poly
+
+def square(pos, r, color, filled=1, behind=0):
+ x, y = pos
+ coords = [(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)]
+ return polygon(coords, color, color, filled, 0, behind=behind)
+
+def circle(pos, r, outlineColor, fillColor, endpoints=None, style='pieslice', width=2):
+ x, y = pos
+ x0, x1 = x - r - 1, x + r
+ y0, y1 = y - r - 1, y + r
+ if endpoints == None:
+ e = [0, 359]
+ else:
+ e = list(endpoints)
+ while e[0] > e[1]: e[1] = e[1] + 360
+
+ return _canvas.create_arc(x0, y0, x1, y1, outline=outlineColor, fill=fillColor,
+ extent=e[1] - e[0], start=e[0], style=style, width=width)
+
+def image(pos, file="../../blueghost.gif"):
+ x, y = pos
+ # img = PhotoImage(file=file)
+ return _canvas.create_image(x, y, image = Tkinter.PhotoImage(file=file), anchor = Tkinter.NW)
+
+
+def refresh():
+ _canvas.update_idletasks()
+
+def moveCircle(id, pos, r, endpoints=None):
+ global _canvas_x, _canvas_y
+
+ x, y = pos
+# x0, x1 = x - r, x + r + 1
+# y0, y1 = y - r, y + r + 1
+ x0, x1 = x - r - 1, x + r
+ y0, y1 = y - r - 1, y + r
+ if endpoints == None:
+ e = [0, 359]
+ else:
+ e = list(endpoints)
+ while e[0] > e[1]: e[1] = e[1] + 360
+
+ if os.path.isfile('flag'):
+ edit(id, ('extent', e[1] - e[0]))
+ else:
+ edit(id, ('start', e[0]), ('extent', e[1] - e[0]))
+ move_to(id, x0, y0)
+
+def edit(id, *args):
+ _canvas.itemconfigure(id, **dict(args))
+
+def text(pos, color, contents, font='Helvetica', size=12, style='normal', anchor="nw"):
+ global _canvas_x, _canvas_y
+ x, y = pos
+ font = (font, str(size), style)
+ return _canvas.create_text(x, y, fill=color, text=contents, font=font, anchor=anchor)
+
+def changeText(id, newText, font=None, size=12, style='normal'):
+ _canvas.itemconfigure(id, text=newText)
+ if font != None:
+ _canvas.itemconfigure(id, font=(font, '-%d' % size, style))
+
+def changeColor(id, newColor):
+ _canvas.itemconfigure(id, fill=newColor)
+
+def line(here, there, color=formatColor(0, 0, 0), width=2):
+ x0, y0 = here[0], here[1]
+ x1, y1 = there[0], there[1]
+ return _canvas.create_line(x0, y0, x1, y1, fill=color, width=width)
+
+##############################################################################
+### Keypress handling ########################################################
+##############################################################################
+
+# We bind to key-down and key-up events.
+
+_keysdown = {}
+_keyswaiting = {}
+# This holds an unprocessed key release. We delay key releases by up to
+# one call to keys_pressed() to get round a problem with auto repeat.
+_got_release = None
+
+def _keypress(event):
+ global _got_release
+ #remap_arrows(event)
+ _keysdown[event.keysym] = 1
+ _keyswaiting[event.keysym] = 1
+# print event.char, event.keycode
+ _got_release = None
+
+def _keyrelease(event):
+ global _got_release
+ #remap_arrows(event)
+ try:
+ del _keysdown[event.keysym]
+ except:
+ pass
+ _got_release = 1
+
+def remap_arrows(event):
+ # TURN ARROW PRESSES INTO LETTERS (SHOULD BE IN KEYBOARD AGENT)
+ if event.char in ['a', 's', 'd', 'w']:
+ return
+ if event.keycode in [37, 101]: # LEFT ARROW (win / x)
+ event.char = 'a'
+ if event.keycode in [38, 99]: # UP ARROW
+ event.char = 'w'
+ if event.keycode in [39, 102]: # RIGHT ARROW
+ event.char = 'd'
+ if event.keycode in [40, 104]: # DOWN ARROW
+ event.char = 's'
+
+def _clear_keys(event=None):
+ global _keysdown, _got_release, _keyswaiting
+ _keysdown = {}
+ _keyswaiting = {}
+ _got_release = None
+
+def keys_pressed(d_o_e=Tkinter.tkinter.dooneevent,
+ d_w=Tkinter.tkinter.DONT_WAIT):
+ d_o_e(d_w)
+ if _got_release:
+ d_o_e(d_w)
+ return _keysdown.keys()
+
+def keys_waiting():
+ global _keyswaiting
+ keys = _keyswaiting.keys()
+ _keyswaiting = {}
+ return keys
+
+# Block for a list of keys...
+
+def wait_for_keys():
+ keys = []
+ while keys == []:
+ keys = keys_pressed()
+ sleep(0.05)
+ return keys
+
+def remove_from_screen(x,
+ d_o_e=Tkinter.tkinter.dooneevent,
+ d_w=Tkinter.tkinter.DONT_WAIT):
+ _canvas.delete(x)
+ d_o_e(d_w)
+
+def _adjust_coords(coord_list, x, y):
+ for i in range(0, len(coord_list), 2):
+ coord_list[i] = coord_list[i] + x
+ coord_list[i + 1] = coord_list[i + 1] + y
+ return coord_list
+
+def move_to(object, x, y=None,
+ d_o_e=Tkinter.tkinter.dooneevent,
+ d_w=Tkinter.tkinter.DONT_WAIT):
+ if y is None:
+ try: x, y = x
+ except: raise 'incomprehensible coordinates'
+
+ horiz = True
+ newCoords = []
+ current_x, current_y = _canvas.coords(object)[0:2] # first point
+ for coord in _canvas.coords(object):
+ if horiz:
+ inc = x - current_x
+ else:
+ inc = y - current_y
+ horiz = not horiz
+
+ newCoords.append(coord + inc)
+
+ _canvas.coords(object, *newCoords)
+ d_o_e(d_w)
+
+def move_by(object, x, y=None,
+ d_o_e=Tkinter.tkinter.dooneevent,
+ d_w=Tkinter.tkinter.DONT_WAIT, lift=False):
+ if y is None:
+ try: x, y = x
+ except: raise Exception, 'incomprehensible coordinates'
+
+ horiz = True
+ newCoords = []
+ for coord in _canvas.coords(object):
+ if horiz:
+ inc = x
+ else:
+ inc = y
+ horiz = not horiz
+
+ newCoords.append(coord + inc)
+
+ _canvas.coords(object, *newCoords)
+ d_o_e(d_w)
+ if lift:
+ _canvas.tag_raise(object)
+
+def writePostscript(filename):
+ "Writes the current canvas to a postscript file."
+ psfile = file(filename, 'w')
+ psfile.write(_canvas.postscript(pageanchor='sw',
+ y='0.c',
+ x='0.c'))
+ psfile.close()
+
+ghost_shape = [
+ (0, - 0.5),
+ (0.25, - 0.75),
+ (0.5, - 0.5),
+ (0.75, - 0.75),
+ (0.75, 0.5),
+ (0.5, 0.75),
+ (- 0.5, 0.75),
+ (- 0.75, 0.5),
+ (- 0.75, - 0.75),
+ (- 0.5, - 0.5),
+ (- 0.25, - 0.75)
+ ]
+
+if __name__ == '__main__':
+ begin_graphics()
+ clear_screen()
+ ghost_shape = [(x * 10 + 20, y * 10 + 20) for x, y in ghost_shape]
+ g = polygon(ghost_shape, formatColor(1, 1, 1))
+ move_to(g, (50, 50))
+ circle((150, 150), 20, formatColor(0.7, 0.3, 0.0), endpoints=[15, - 15])
+ sleep(2)
diff --git a/search/graphicsUtils.pyc b/search/graphicsUtils.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8cdd0a86e86758a4fa05d7a98dcd806e73b000fe
GIT binary patch
literal 13218
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
Dc}u;j
literal 0
HcmV?d00001
diff --git a/search/keyboardAgents.py b/search/keyboardAgents.py
new file mode 100644
index 0000000..c7d9fcf
--- /dev/null
+++ b/search/keyboardAgents.py
@@ -0,0 +1,84 @@
+# keyboardAgents.py
+# -----------------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+from game import Agent
+from game import Directions
+import random
+
+class KeyboardAgent(Agent):
+ """
+ An agent controlled by the keyboard.
+ """
+ # NOTE: Arrow keys also work.
+ WEST_KEY = 'a'
+ EAST_KEY = 'd'
+ NORTH_KEY = 'w'
+ SOUTH_KEY = 's'
+ STOP_KEY = 'q'
+
+ def __init__( self, index = 0 ):
+
+ self.lastMove = Directions.STOP
+ self.index = index
+ self.keys = []
+
+ def getAction( self, state):
+ from graphicsUtils import keys_waiting
+ from graphicsUtils import keys_pressed
+ keys = keys_waiting() + keys_pressed()
+ if keys != []:
+ self.keys = keys
+
+ legal = state.getLegalActions(self.index)
+ move = self.getMove(legal)
+
+ if move == Directions.STOP:
+ # Try to move in the same direction as before
+ if self.lastMove in legal:
+ move = self.lastMove
+
+ if (self.STOP_KEY in self.keys) and Directions.STOP in legal: move = Directions.STOP
+
+ if move not in legal:
+ move = random.choice(legal)
+
+ self.lastMove = move
+ return move
+
+ def getMove(self, legal):
+ move = Directions.STOP
+ if (self.WEST_KEY in self.keys or 'Left' in self.keys) and Directions.WEST in legal: move = Directions.WEST
+ if (self.EAST_KEY in self.keys or 'Right' in self.keys) and Directions.EAST in legal: move = Directions.EAST
+ if (self.NORTH_KEY in self.keys or 'Up' in self.keys) and Directions.NORTH in legal: move = Directions.NORTH
+ if (self.SOUTH_KEY in self.keys or 'Down' in self.keys) and Directions.SOUTH in legal: move = Directions.SOUTH
+ return move
+
+class KeyboardAgent2(KeyboardAgent):
+ """
+ A second agent controlled by the keyboard.
+ """
+ # NOTE: Arrow keys also work.
+ WEST_KEY = 'j'
+ EAST_KEY = "l"
+ NORTH_KEY = 'i'
+ SOUTH_KEY = 'k'
+ STOP_KEY = 'u'
+
+ def getMove(self, legal):
+ move = Directions.STOP
+ if (self.WEST_KEY in self.keys) and Directions.WEST in legal: move = Directions.WEST
+ if (self.EAST_KEY in self.keys) and Directions.EAST in legal: move = Directions.EAST
+ if (self.NORTH_KEY in self.keys) and Directions.NORTH in legal: move = Directions.NORTH
+ if (self.SOUTH_KEY in self.keys) and Directions.SOUTH in legal: move = Directions.SOUTH
+ return move
diff --git a/search/keyboardAgents.pyc b/search/keyboardAgents.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9129cea5d061ecbff4c01cdab45f27aa1a456f28
GIT binary patch
literal 2784
zcmcIl-EJF26h6D_tnJjLC?Eni;FiAyiKs%rML~$PiBw2&(K=C8E7HpGZk)9pJKdQO
zA~_eReE_cd06YaZNFd$=i5K98D=rXx-&wEMLFz>mSZ7YoH*?OMGc(_r@&35FeCvmw
z9`t1PdHDYsn%RYj@#n}$`Mg>{KN7
zC8=m{b>6!qu_x`Ih5+f`_yPx-U4mHeCu5t#Wx$OzOL{h)j7`g41>QJrygS(dOJFaxs&
zvE0PBK5llIU9&eC+iWr#C2@1_v}q5L=5UtQni^WJrmHemd7{#&e3W8PdQ7=!cc7aa
z5LRU1$W$b9WtuCV^hJBH0Kt}V>Q=y=3U$va(AwMgzp~uRQP!0tokM{=H@m-U2v))1RuUMaMyIDIr)o@Xij#C>&
zufp5-oXu@Gbw}4$B|_7+{SF03F(Zy6XCw|Vhy!A|a^{IMbxD}1N4a`dk!gi1A9|AA
zrOr+9WDE;O1_}pD@)%PsacJPnG>1@pu~iw=WavuvR7dL^9r`6a^X1V~oejRrYU8QF
zFEihneF0(5&>Ce}mFzdMS7gvAgU&{gBx3nEC+>S|f!hsWoH{v=Mv)
z5+&N&d}w)CS$7;y4pr?POwwKw&^u&G${%C9Hu-mC5^uz?N~J@@xfF|-85WYS;SB)O
zgb?R>{WYA1yW(7P@q@fB4bW@Foe|7~-JD>50p!I4YLO4Q)H5~jl6&mTk9bopK_N#^
zynt}zA;K(YRPMV^(w4s8sxN4e`xdbDt(L~-dlJ0#{ZV~ug>L~%UofXg()`McY7VnM
z)fYs~;}&q{>w<4Qn3f*Oy=33&0fuS+z*_Fn&XJC6OisoD2~=`JY4KpQy-ix=0DDp}?}d{N@!^z=ev+U)uBKlG8=|Uc(}D;#{Yu?0KD= 0:
+ curdir = os.path.abspath('.')
+ os.chdir('..')
+ layout = getLayout(name, back -1)
+ os.chdir(curdir)
+ return layout
+
+def tryToLoad(fullname):
+ if(not os.path.exists(fullname)): return None
+ f = open(fullname)
+ try: return Layout([line.strip() for line in f])
+ finally: f.close()
diff --git a/search/layout.pyc b/search/layout.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5276e80d331e8247983126da44be397990091836
GIT binary patch
literal 6269
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 self.getNumAgents():
+ raise Exception("Invalid index passed to getGhostState")
+ return self.data.agentStates[agentIndex]
+
+ def getGhostPosition( self, agentIndex ):
+ if agentIndex == 0:
+ raise Exception("Pacman's index passed to getGhostPosition")
+ return self.data.agentStates[agentIndex].getPosition()
+
+ def getGhostPositions(self):
+ return [s.getPosition() for s in self.getGhostStates()]
+
+ def getNumAgents( self ):
+ return len( self.data.agentStates )
+
+ def getScore( self ):
+ return float(self.data.score)
+
+ def getCapsules(self):
+ """
+ Returns a list of positions (x,y) of the remaining capsules.
+ """
+ return self.data.capsules
+
+ def getNumFood( self ):
+ return self.data.food.count()
+
+ def getFood(self):
+ """
+ Returns a Grid of boolean food indicator variables.
+
+ Grids can be accessed via list notation, so to check
+ if there is food at (x,y), just call
+
+ currentFood = state.getFood()
+ if currentFood[x][y] == True: ...
+ """
+ return self.data.food
+
+ def getWalls(self):
+ """
+ Returns a Grid of boolean wall indicator variables.
+
+ Grids can be accessed via list notation, so to check
+ if there is a wall at (x,y), just call
+
+ walls = state.getWalls()
+ if walls[x][y] == True: ...
+ """
+ return self.data.layout.walls
+
+ def hasFood(self, x, y):
+ return self.data.food[x][y]
+
+ def hasWall(self, x, y):
+ return self.data.layout.walls[x][y]
+
+ def isLose( self ):
+ return self.data._lose
+
+ def isWin( self ):
+ return self.data._win
+
+ #############################################
+ # Helper methods: #
+ # You shouldn't need to call these directly #
+ #############################################
+
+ def __init__( self, prevState = None ):
+ """
+ Generates a new state by copying information from its predecessor.
+ """
+ if prevState != None: # Initial state
+ self.data = GameStateData(prevState.data)
+ else:
+ self.data = GameStateData()
+
+ def deepCopy( self ):
+ state = GameState( self )
+ state.data = self.data.deepCopy()
+ return state
+
+ def __eq__( self, other ):
+ """
+ Allows two states to be compared.
+ """
+ return hasattr(other, 'data') and self.data == other.data
+
+ def __hash__( self ):
+ """
+ Allows states to be keys of dictionaries.
+ """
+ return hash( self.data )
+
+ def __str__( self ):
+
+ return str(self.data)
+
+ def initialize( self, layout, numGhostAgents=1000 ):
+ """
+ Creates an initial game state from a layout array (see layout.py).
+ """
+ self.data.initialize(layout, numGhostAgents)
+
+############################################################################
+# THE HIDDEN SECRETS OF PACMAN #
+# #
+# You shouldn't need to look through the code in this section of the file. #
+############################################################################
+
+SCARED_TIME = 40 # Moves ghosts are scared
+COLLISION_TOLERANCE = 0.7 # How close ghosts must be to Pacman to kill
+TIME_PENALTY = 1 # Number of points lost each round
+
+class ClassicGameRules:
+ """
+ These game rules manage the control flow of a game, deciding when
+ and how the game starts and ends.
+ """
+ def __init__(self, timeout=30):
+ self.timeout = timeout
+
+ def newGame( self, layout, pacmanAgent, ghostAgents, display, quiet = False, catchExceptions=False):
+ agents = [pacmanAgent] + ghostAgents[:layout.getNumGhosts()]
+ initState = GameState()
+ initState.initialize( layout, len(ghostAgents) )
+ game = Game(agents, display, self, catchExceptions=catchExceptions)
+ game.state = initState
+ self.initialState = initState.deepCopy()
+ self.quiet = quiet
+ return game
+
+ def process(self, state, game):
+ """
+ Checks to see whether it is time to end the game.
+ """
+ if state.isWin(): self.win(state, game)
+ if state.isLose(): self.lose(state, game)
+
+ def win( self, state, game ):
+ if not self.quiet: print "Pacman emerges victorious! Score: %d" % state.data.score
+ game.gameOver = True
+
+ def lose( self, state, game ):
+ if not self.quiet: print "Pacman died! Score: %d" % state.data.score
+ game.gameOver = True
+
+ def getProgress(self, game):
+ return float(game.state.getNumFood()) / self.initialState.getNumFood()
+
+ def agentCrash(self, game, agentIndex):
+ if agentIndex == 0:
+ print "Pacman crashed"
+ else:
+ print "A ghost crashed"
+
+ def getMaxTotalTime(self, agentIndex):
+ return self.timeout
+
+ def getMaxStartupTime(self, agentIndex):
+ return self.timeout
+
+ def getMoveWarningTime(self, agentIndex):
+ return self.timeout
+
+ def getMoveTimeout(self, agentIndex):
+ return self.timeout
+
+ def getMaxTimeWarnings(self, agentIndex):
+ return 0
+
+class PacmanRules:
+ """
+ These functions govern how pacman interacts with his environment under
+ the classic game rules.
+ """
+ PACMAN_SPEED=1
+
+ def getLegalActions( state ):
+ """
+ Returns a list of possible actions.
+ """
+ return Actions.getPossibleActions( state.getPacmanState().configuration, state.data.layout.walls )
+ getLegalActions = staticmethod( getLegalActions )
+
+ def applyAction( state, action ):
+ """
+ Edits the state to reflect the results of the action.
+ """
+ legal = PacmanRules.getLegalActions( state )
+ if action not in legal:
+ raise Exception("Illegal action " + str(action))
+
+ pacmanState = state.data.agentStates[0]
+
+ # Update Configuration
+ vector = Actions.directionToVector( action, PacmanRules.PACMAN_SPEED )
+ pacmanState.configuration = pacmanState.configuration.generateSuccessor( vector )
+
+ # Eat
+ next = pacmanState.configuration.getPosition()
+ nearest = nearestPoint( next )
+ if manhattanDistance( nearest, next ) <= 0.5 :
+ # Remove food
+ PacmanRules.consume( nearest, state )
+ applyAction = staticmethod( applyAction )
+
+ def consume( position, state ):
+ x,y = position
+ # Eat food
+ if state.data.food[x][y]:
+ state.data.scoreChange += 10
+ state.data.food = state.data.food.copy()
+ state.data.food[x][y] = False
+ state.data._foodEaten = position
+ # TODO: cache numFood?
+ numFood = state.getNumFood()
+ if numFood == 0 and not state.data._lose:
+ state.data.scoreChange += 500
+ state.data._win = True
+ # Eat capsule
+ if( position in state.getCapsules() ):
+ state.data.capsules.remove( position )
+ state.data._capsuleEaten = position
+ # Reset all ghosts' scared timers
+ for index in range( 1, len( state.data.agentStates ) ):
+ state.data.agentStates[index].scaredTimer = SCARED_TIME
+ consume = staticmethod( consume )
+
+class GhostRules:
+ """
+ These functions dictate how ghosts interact with their environment.
+ """
+ GHOST_SPEED=1.0
+ def getLegalActions( state, ghostIndex ):
+ """
+ Ghosts cannot stop, and cannot turn around unless they
+ reach a dead end, but can turn 90 degrees at intersections.
+ """
+ conf = state.getGhostState( ghostIndex ).configuration
+ possibleActions = Actions.getPossibleActions( conf, state.data.layout.walls )
+ reverse = Actions.reverseDirection( conf.direction )
+ if Directions.STOP in possibleActions:
+ possibleActions.remove( Directions.STOP )
+ if reverse in possibleActions and len( possibleActions ) > 1:
+ possibleActions.remove( reverse )
+ return possibleActions
+ getLegalActions = staticmethod( getLegalActions )
+
+ def applyAction( state, action, ghostIndex):
+
+ legal = GhostRules.getLegalActions( state, ghostIndex )
+ if action not in legal:
+ raise Exception("Illegal ghost action " + str(action))
+
+ ghostState = state.data.agentStates[ghostIndex]
+ speed = GhostRules.GHOST_SPEED
+ if ghostState.scaredTimer > 0: speed /= 2.0
+ vector = Actions.directionToVector( action, speed )
+ ghostState.configuration = ghostState.configuration.generateSuccessor( vector )
+ applyAction = staticmethod( applyAction )
+
+ def decrementTimer( ghostState):
+ timer = ghostState.scaredTimer
+ if timer == 1:
+ ghostState.configuration.pos = nearestPoint( ghostState.configuration.pos )
+ ghostState.scaredTimer = max( 0, timer - 1 )
+ decrementTimer = staticmethod( decrementTimer )
+
+ def checkDeath( state, agentIndex):
+ pacmanPosition = state.getPacmanPosition()
+ if agentIndex == 0: # Pacman just moved; Anyone can kill him
+ for index in range( 1, len( state.data.agentStates ) ):
+ ghostState = state.data.agentStates[index]
+ ghostPosition = ghostState.configuration.getPosition()
+ if GhostRules.canKill( pacmanPosition, ghostPosition ):
+ GhostRules.collide( state, ghostState, index )
+ else:
+ ghostState = state.data.agentStates[agentIndex]
+ ghostPosition = ghostState.configuration.getPosition()
+ if GhostRules.canKill( pacmanPosition, ghostPosition ):
+ GhostRules.collide( state, ghostState, agentIndex )
+ checkDeath = staticmethod( checkDeath )
+
+ def collide( state, ghostState, agentIndex):
+ if ghostState.scaredTimer > 0:
+ state.data.scoreChange += 200
+ GhostRules.placeGhost(state, ghostState)
+ ghostState.scaredTimer = 0
+ # Added for first-person
+ state.data._eaten[agentIndex] = True
+ else:
+ if not state.data._win:
+ state.data.scoreChange -= 500
+ state.data._lose = True
+ collide = staticmethod( collide )
+
+ def canKill( pacmanPosition, ghostPosition ):
+ return manhattanDistance( ghostPosition, pacmanPosition ) <= COLLISION_TOLERANCE
+ canKill = staticmethod( canKill )
+
+ def placeGhost(state, ghostState):
+ ghostState.configuration = ghostState.start
+ placeGhost = staticmethod( placeGhost )
+
+#############################
+# FRAMEWORK TO START A GAME #
+#############################
+
+def default(str):
+ return str + ' [Default: %default]'
+
+def parseAgentArgs(str):
+ if str == None: return {}
+ pieces = str.split(',')
+ opts = {}
+ for p in pieces:
+ if '=' in p:
+ key, val = p.split('=')
+ else:
+ key,val = p, 1
+ opts[key] = val
+ return opts
+
+def readCommand( argv ):
+ """
+ Processes the command used to run pacman from the command line.
+ """
+ from optparse import OptionParser
+ usageStr = """
+ USAGE: python pacman.py
+ EXAMPLES: (1) python pacman.py
+ - starts an interactive game
+ (2) python pacman.py --layout smallClassic --zoom 2
+ OR python pacman.py -l smallClassic -z 2
+ - starts an interactive game on a smaller board, zoomed in
+ """
+ parser = OptionParser(usageStr)
+
+ parser.add_option('-n', '--numGames', dest='numGames', type='int',
+ help=default('the number of GAMES to play'), metavar='GAMES', default=1)
+ parser.add_option('-l', '--layout', dest='layout',
+ help=default('the LAYOUT_FILE from which to load the map layout'),
+ metavar='LAYOUT_FILE', default='mediumClassic')
+ parser.add_option('-p', '--pacman', dest='pacman',
+ help=default('the agent TYPE in the pacmanAgents module to use'),
+ metavar='TYPE', default='KeyboardAgent')
+ parser.add_option('-t', '--textGraphics', action='store_true', dest='textGraphics',
+ help='Display output as text only', default=False)
+ parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics',
+ help='Generate minimal output and no graphics', default=False)
+ parser.add_option('-g', '--ghosts', dest='ghost',
+ help=default('the ghost agent TYPE in the ghostAgents module to use'),
+ metavar = 'TYPE', default='RandomGhost')
+ parser.add_option('-k', '--numghosts', type='int', dest='numGhosts',
+ help=default('The maximum number of ghosts to use'), default=4)
+ parser.add_option('-z', '--zoom', type='float', dest='zoom',
+ help=default('Zoom the size of the graphics window'), default=1.0)
+ parser.add_option('-f', '--fixRandomSeed', action='store_true', dest='fixRandomSeed',
+ help='Fixes the random seed to always play the same game', default=False)
+ parser.add_option('-r', '--recordActions', action='store_true', dest='record',
+ help='Writes game histories to a file (named by the time they were played)', default=False)
+ parser.add_option('--replay', dest='gameToReplay',
+ help='A recorded game file (pickle) to replay', default=None)
+ parser.add_option('-a','--agentArgs',dest='agentArgs',
+ help='Comma separated values sent to agent. e.g. "opt1=val1,opt2,opt3=val3"')
+ parser.add_option('-x', '--numTraining', dest='numTraining', type='int',
+ help=default('How many episodes are training (suppresses output)'), default=0)
+ parser.add_option('--frameTime', dest='frameTime', type='float',
+ help=default('Time to delay between frames; <0 means keyboard'), default=0.1)
+ parser.add_option('-c', '--catchExceptions', action='store_true', dest='catchExceptions',
+ help='Turns on exception handling and timeouts during games', default=False)
+ parser.add_option('--timeout', dest='timeout', type='int',
+ help=default('Maximum length of time an agent can spend computing in a single game'), default=30)
+
+ options, otherjunk = parser.parse_args(argv)
+ if len(otherjunk) != 0:
+ raise Exception('Command line input not understood: ' + str(otherjunk))
+ args = dict()
+
+ # Fix the random seed
+ if options.fixRandomSeed: random.seed('cs188')
+
+ # Choose a layout
+ args['layout'] = layout.getLayout( options.layout )
+ if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found")
+
+ # Choose a Pacman agent
+ noKeyboard = options.gameToReplay == None and (options.textGraphics or options.quietGraphics)
+ pacmanType = loadAgent(options.pacman, noKeyboard)
+ agentOpts = parseAgentArgs(options.agentArgs)
+ if options.numTraining > 0:
+ args['numTraining'] = options.numTraining
+ if 'numTraining' not in agentOpts: agentOpts['numTraining'] = options.numTraining
+ pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs
+ args['pacman'] = pacman
+
+ # Don't display training games
+ if 'numTrain' in agentOpts:
+ options.numQuiet = int(agentOpts['numTrain'])
+ options.numIgnore = int(agentOpts['numTrain'])
+
+ # Choose a ghost agent
+ ghostType = loadAgent(options.ghost, noKeyboard)
+ args['ghosts'] = [ghostType( i+1 ) for i in range( options.numGhosts )]
+
+ # Choose a display format
+ if options.quietGraphics:
+ import textDisplay
+ args['display'] = textDisplay.NullGraphics()
+ elif options.textGraphics:
+ import textDisplay
+ textDisplay.SLEEP_TIME = options.frameTime
+ args['display'] = textDisplay.PacmanGraphics()
+ else:
+ import graphicsDisplay
+ args['display'] = graphicsDisplay.PacmanGraphics(options.zoom, frameTime = options.frameTime)
+ args['numGames'] = options.numGames
+ args['record'] = options.record
+ args['catchExceptions'] = options.catchExceptions
+ args['timeout'] = options.timeout
+
+ # Special case: recorded games don't use the runGames method or args structure
+ if options.gameToReplay != None:
+ print 'Replaying recorded game %s.' % options.gameToReplay
+ import cPickle
+ f = open(options.gameToReplay)
+ try: recorded = cPickle.load(f)
+ finally: f.close()
+ recorded['display'] = args['display']
+ replayGame(**recorded)
+ sys.exit(0)
+
+ return args
+
+def loadAgent(pacman, nographics):
+ # Looks through all pythonPath Directories for the right module,
+ pythonPathStr = os.path.expandvars("$PYTHONPATH")
+ if pythonPathStr.find(';') == -1:
+ pythonPathDirs = pythonPathStr.split(':')
+ else:
+ pythonPathDirs = pythonPathStr.split(';')
+ pythonPathDirs.append('.')
+
+ for moduleDir in pythonPathDirs:
+ if not os.path.isdir(moduleDir): continue
+ moduleNames = [f for f in os.listdir(moduleDir) if f.endswith('gents.py')]
+ for modulename in moduleNames:
+ try:
+ module = __import__(modulename[:-3])
+ except ImportError:
+ continue
+ if pacman in dir(module):
+ if nographics and modulename == 'keyboardAgents.py':
+ raise Exception('Using the keyboard requires graphics (not text display)')
+ return getattr(module, pacman)
+ raise Exception('The agent ' + pacman + ' is not specified in any *Agents.py.')
+
+def replayGame( layout, actions, display ):
+ import pacmanAgents, ghostAgents
+ rules = ClassicGameRules()
+ agents = [pacmanAgents.GreedyAgent()] + [ghostAgents.RandomGhost(i+1) for i in range(layout.getNumGhosts())]
+ game = rules.newGame( layout, agents[0], agents[1:], display )
+ state = game.state
+ display.initialize(state.data)
+
+ for action in actions:
+ # Execute the action
+ state = state.generateSuccessor( *action )
+ # Change the display
+ display.update( state.data )
+ # Allow for game specific conditions (winning, losing, etc.)
+ rules.process(state, game)
+
+ display.finish()
+
+def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0, catchExceptions=False, timeout=30 ):
+ import __main__
+ __main__.__dict__['_display'] = display
+
+ rules = ClassicGameRules(timeout)
+ games = []
+
+ for i in range( numGames ):
+ beQuiet = i < numTraining
+ if beQuiet:
+ # Suppress output and graphics
+ import textDisplay
+ gameDisplay = textDisplay.NullGraphics()
+ rules.quiet = True
+ else:
+ gameDisplay = display
+ rules.quiet = False
+ game = rules.newGame( layout, pacman, ghosts, gameDisplay, beQuiet, catchExceptions)
+ game.run()
+ if not beQuiet: games.append(game)
+
+ if record:
+ import time, cPickle
+ fname = ('recorded-game-%d' % (i + 1)) + '-'.join([str(t) for t in time.localtime()[1:6]])
+ f = file(fname, 'w')
+ components = {'layout': layout, 'actions': game.moveHistory}
+ cPickle.dump(components, f)
+ f.close()
+
+ if (numGames-numTraining) > 0:
+ scores = [game.state.getScore() for game in games]
+ wins = [game.state.isWin() for game in games]
+ winRate = wins.count(True)/ float(len(wins))
+ print 'Average Score:', sum(scores) / float(len(scores))
+ print 'Scores: ', ', '.join([str(score) for score in scores])
+ print 'Win Rate: %d/%d (%.2f)' % (wins.count(True), len(wins), winRate)
+ print 'Record: ', ', '.join([ ['Loss', 'Win'][int(w)] for w in wins])
+
+ return games
+
+if __name__ == '__main__':
+ """
+ The main function called when pacman.py is run
+ from the command line:
+
+ > python pacman.py
+
+ See the usage string for more details.
+
+ > python pacman.py --help
+ """
+ args = readCommand( sys.argv[1:] ) # Get game components based on input
+ runGames( **args )
+
+ # import cProfile
+ # cProfile.run("runGames( **args )")
+ pass
diff --git a/search/pacman.pyc b/search/pacman.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bd60d8a36258c43425d46a2041db2f6ccdcaa2a0
GIT binary patch
literal 25577
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
literal 0
HcmV?d00001
diff --git a/search/projectParams.py b/search/projectParams.py
new file mode 100644
index 0000000..dc3e9d1
--- /dev/null
+++ b/search/projectParams.py
@@ -0,0 +1,18 @@
+# projectParams.py
+# ----------------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+STUDENT_CODE_DEFAULT = 'searchAgents.py,search.py'
+PROJECT_TEST_CLASSES = 'searchTestClasses.py'
+PROJECT_NAME = 'Project 1: Search'
+BONUS_PIC = False
diff --git a/search/search.py b/search/search.py
new file mode 100644
index 0000000..c5c196d
--- /dev/null
+++ b/search/search.py
@@ -0,0 +1,191 @@
+# search.py
+# ---------
+# Licensing Information: You are free to use or extend these projects for
+# educational purposes provided that (1) you do not distribute or publish
+# solutions, (2) you retain this notice, and (3) you provide clear
+# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
+#
+# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
+# The core projects and autograders were primarily created by John DeNero
+# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
+# Student side autograding was added by Brad Miller, Nick Hay, and
+# Pieter Abbeel (pabbeel@cs.berkeley.edu).
+
+
+"""
+In search.py, you will implement generic search algorithms which are called by
+Pacman agents (in searchAgents.py).
+"""
+
+import util
+
+class SearchProblem:
+ """
+ This class outlines the structure of a search problem, but doesn't implement
+ any of the methods (in object-oriented terminology: an abstract class).
+
+ You do not need to change anything in this class, ever.
+ """
+
+ def getStartState(self):
+ """
+ Returns the start state for the search problem.
+ """
+ util.raiseNotDefined()
+
+ def isGoalState(self, state):
+ """
+ state: Search state
+
+ Returns True if and only if the state is a valid goal state.
+ """
+ util.raiseNotDefined()
+
+ def getSuccessors(self, state):
+ """
+ state: Search state
+
+ For a given state, this should return a list of triples, (successor,
+ action, stepCost), where 'successor' is a successor to the current
+ state, 'action' is the action required to get there, and 'stepCost' is
+ the incremental cost of expanding to that successor.
+ """
+ util.raiseNotDefined()
+
+ def getCostOfActions(self, actions):
+ """
+ actions: A list of actions to take
+
+ This method returns the total cost of a particular sequence of actions.
+ The sequence must be composed of legal moves.
+ """
+ util.raiseNotDefined()
+
+
+def tinyMazeSearch(problem):
+ """
+ Returns a sequence of moves that solves tinyMaze. For any other maze, the
+ sequence of moves will be incorrect, so only use this for tinyMaze.
+ """
+ from game import Directions
+ s = Directions.SOUTH
+ w = Directions.WEST
+ return [s, s, w, s, w, w, s, w]
+
+def depthFirstSearch(problem):
+ """
+ Search the deepest nodes in the search tree first.
+
+ Your search algorithm needs to return a list of actions that reaches the
+ goal. Make sure to implement a graph search algorithm.
+
+ To get started, you might want to try some of these simple commands to
+ understand the search problem that is being passed in:
+
+ print "Start:", problem.getStartState()
+ print "Is the start a goal?", problem.isGoalState(problem.getStartState())
+ print "Start's successors:", problem.getSuccessors(problem.getStartState())
+ """
+ "*** YOUR CODE HERE ***"
+# start state
+ startState = problem.getStartState()
+# have exit
+ exitState = []
+#use stack to dfs
+ States = util.Stack()
+ States.push((startState,[]))
+#repeat a circle to confirm if it is successful
+ while (not States.isEmpty()) and (not problem.isGoalState(startState)):
+ State,Actions = States.pop()
+ if State not in exitState:
+ exitState.append(State)
+ Successor = problem.getSuccessors(State)
+ for Node in Successor:
+ Coordinates = Node[0]
+ Direction = Node[1]
+ if not Coordinates in exitState:
+ States.push((Coordinates,Actions + [Direction]))
+ startState = Coordinates
+ return Actions + [Direction]
+ util.raiseNotDefined()
+
+def breadthFirstSearch(problem):
+ """Search the shallowest nodes in the search tree first."""
+ "*** YOUR CODE HERE ***"
+ startState = problem.getStartState()
+ exitState = []
+ States = util.Queue()
+ States.push((startState,[]))
+ while (not States.isEmpty()) and (not problem.isGoalState(startState)):
+ State, Actions = States.pop()
+ if State not in exitState:
+ Successor = problem.getSuccessors(State)
+ exitState.append(State)
+ for Node in Successor:
+ Coordinates = Node[0]
+ Direction = Node[1]
+ if Coordinates not in exitState:
+ States.push((Coordinates,Actions+[Direction]))
+ startState = Coordinates
+ return Actions + [Direction]
+ util.raiseNotDefined()
+
+def uniformCostSearch(problem):
+ """Search the node of least total cost first."""
+ "*** YOUR CODE HERE ***"
+ startState = problem.getStartState()
+ exitState = []
+ States = util.PriorityQueue()
+ States.push((startState, []),0)
+ while (not States.isEmpty()) and (not problem.isGoalState(startState)):
+ State, Actions = States.pop()
+ if State not in exitState:
+ Successor = problem.getSuccessors(State)
+ exitState.append(State)
+ for Node in Successor:
+ Coordinates = Node[0]
+ Direction = Node[1]
+ if Coordinates not in exitState:
+ newAction = Actions + [Direction]
+ States.push((Coordinates, newAction),problem.getCostOfActions(newAction))
+ startState = Coordinates
+ return Actions + [Direction]
+ util.raiseNotDefined()
+
+def nullHeuristic(state, problem=None):
+ """
+ A heuristic function estimates the cost from the current state to the nearest
+ goal in the provided SearchProblem. This heuristic is trivial.
+ """
+ return 0
+
+def aStarSearch(problem, heuristic=nullHeuristic):
+ """Search the node that has the lowest combined cost and heuristic first."""
+ "*** YOUR CODE HERE ***"
+ startState = problem.getStartState()
+ exitState = []
+ States = util.PriorityQueue()
+ h_n = heuristic(startState,problem)
+ States.push((startState, []), h_n)
+ while (not States.isEmpty()) and (not problem.isGoalState(startState)):
+ State, Actions = States.pop()
+ if State not in exitState:
+ Successor = problem.getSuccessors(State)
+ exitState.append(State)
+ for Node in Successor:
+ Coordinates = Node[0]
+ Direction = Node[1]
+ if Coordinates not in exitState:
+ newAction = Actions + [Direction]
+ newCost = problem.getCostOfActions(newAction) + heuristic(Coordinates,problem)
+ States.push((Coordinates, newAction), newCost)
+ startState = Coordinates
+ return Actions + [Direction]
+ util.raiseNotDefined()
+
+
+# Abbreviations
+bfs = breadthFirstSearch
+dfs = depthFirstSearch
+astar = aStarSearch
+ucs = uniformCostSearch
diff --git a/search/search.pyc b/search/search.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3fa9074baaa14d62c97435f31d993b421f58b3be
GIT binary patch
literal 6082
zcmb_g&u<(_6|SDK$DZ++WH*p(mR%^a1W&-5!wR&Lg%(V*VFPS7+ct{UWM$gj<(W=;
zx+mS$wg=g#EdKx!CpaPg0=RPIUsyOIf#ATE0}>#?_r2=r87GnBSU8!Qs_Lp&uilUE
zeLc;8EO$P=`bHS4>aU6KZ{t%Op^22*LhGrhp%PDRq0>~+l8WZkCrUk5>Z7fOism`k
z!h@D{=2WyGop}{4N~gvBQCoci5sS(!s;DFVwlec-tE0@E+FDYkt+u+#wA9uz*KhQ?
zRKud_+)j02f;=2tAB|V_I4kvjoFqCPjuJC8snvaxnmi7xRXRxeSsvTLu+aO1I2`C8
zH#!WG#6)^$+_@Ws!ywfGcG*Jr;)(QinZOy>u6N@9;_r@K#_=0+^xZt$!D+RjJUsah
zHGB(=fdOC~w794@u}5QKkLJW4Vz;f9@;7?(-1{dq9gV-uL0srC35r5zrA^}06xt4q
zE^J~|Xm%SkkHTm4&r9XoPZhhb}f;^aOqu1d4IvUwRgZKuwPA5hPatl)g*67_VcZLzC
z=*klADDJx>vg{mWl{QZ7Idt+MF3g?G-ZZ-~Y}BJRvZ64_ZVv+`O>q^yn``&iZ{Oc2
z#ZLEK)E)mqd`MXIjoq+N42?Bkz}AAdP;()__~9`pUU-NF^@X*&;F@;f=0?u^v-a4`
zOQU1NLK^8TO~&lIK%sTufI#mBNgU~Z79>u{lg9C>m`@GGR(=ybE8)nSoXH+b5D^#O
z#gSr-FJtJe(K@{~egL&jYmHlofMJ2lv08h&eR@y-4x8#bR>mpT^m^?sXD=i_tQNV<+Qth#%D0PXwztz@XtuX)M+U>IR>`gQlVkN)0`A
zTJV7tkSV5zm?S_L5m)=W79wNz^N?fliFIi$Yy;Ub?oBk;QM!4Egzllgn^Zfv?$bWByl+(Ke=VcG6aeRX;_
zSt+iSp01LtQzE^i=FfX={1cZ^Wx{~C>_6xnq9O~YgTMNUzJeBT+GF&^Kkys8hex}Z
zgijBCORqhcz(*0h@8U<`8?7$2jc@C_!%5uB_H%?HF_FU6XUFwYMFf<3KPz+!99k
z*38Zsj?tS?zbB*}6DLQn6w~rpJgG-r$xfCRBSTcowCpi+9JF%iGTR2>L&@w>Squb&
z!nGvMdn*!JS^^P7|4=dUNi&!6SE3H$(Yh(;3t@(w<9
z@N@e)@BtPa
z|0?G`&*n8Yue0I%jsHb9n$4Hk(A{SWpqH_62Y4493!xEaT?jS1UJIdf!E+(R0CFMJ
zoed!dc3r{FBNtyNgiuo+H&DcWKO04GJSx$&i2dutDEjBgQ53o;`qA^F=!>pm
zQXSS>s)Ul)VWp(X)2jA!SJmErs;XfvUO!z``zp*d6IU!`j@Sk$Ycssr6|$LNqJ3v@
zjx^?O9`kpV@o9pJ=;b0y1QFm~D6#~oQnT;i?M!jTGs`pvbsLgUJ1hJYlLcQ;RTX9z
zpAlxu-W7*cObvbr^*8V-$nB;-S^NScDPQY)V9FeCoA?oGw@ifyY9wzwB