From f564df47d1f71d1864cd826bf741feb74d766527 Mon Sep 17 00:00:00 2001 From: pabaill Date: Sat, 2 Nov 2024 00:09:37 -0700 Subject: [PATCH 1/7] Initial working branch for project --- learn_ataax.py | 9 +++++++++ tests/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 174 bytes tests/__pycache__/test_counters.cpython-39.pyc | Bin 0 -> 1017 bytes tests/__pycache__/test_draws.cpython-39.pyc | Bin 0 -> 854 bytes tests/__pycache__/test_fen.cpython-39.pyc | Bin 0 -> 2076 bytes tests/__pycache__/test_gameover.cpython-39.pyc | Bin 0 -> 1471 bytes tests/__pycache__/test_hash.cpython-39.pyc | Bin 0 -> 1434 bytes tests/__pycache__/test_history.cpython-39.pyc | Bin 0 -> 932 bytes tests/__pycache__/test_is_legal.cpython-39.pyc | Bin 0 -> 4896 bytes tests/__pycache__/test_makeundo.cpython-39.pyc | Bin 0 -> 1118 bytes tests/__pycache__/test_movetype.cpython-39.pyc | Bin 0 -> 777 bytes tests/__pycache__/test_nullmove.cpython-39.pyc | Bin 0 -> 925 bytes tests/__pycache__/test_pass.cpython-39.pyc | Bin 0 -> 1403 bytes tests/__pycache__/test_perft.cpython-39.pyc | Bin 0 -> 1777 bytes tests/__pycache__/test_pgn.cpython-39.pyc | Bin 0 -> 2562 bytes tests/__pycache__/test_players.cpython-39.pyc | Bin 0 -> 1706 bytes .../__pycache__/test_predict_hash.cpython-39.pyc | Bin 0 -> 1121 bytes tests/__pycache__/test_result.cpython-39.pyc | Bin 0 -> 3292 bytes tests/__pycache__/test_san.cpython-39.pyc | Bin 0 -> 5333 bytes tests/__pycache__/test_score.cpython-39.pyc | Bin 0 -> 1049 bytes tests/__pycache__/test_set_get.cpython-39.pyc | Bin 0 -> 937 bytes 21 files changed, 9 insertions(+) create mode 100644 learn_ataax.py create mode 100644 tests/__pycache__/__init__.cpython-39.pyc create mode 100644 tests/__pycache__/test_counters.cpython-39.pyc create mode 100644 tests/__pycache__/test_draws.cpython-39.pyc create mode 100644 tests/__pycache__/test_fen.cpython-39.pyc create mode 100644 tests/__pycache__/test_gameover.cpython-39.pyc create mode 100644 tests/__pycache__/test_hash.cpython-39.pyc create mode 100644 tests/__pycache__/test_history.cpython-39.pyc create mode 100644 tests/__pycache__/test_is_legal.cpython-39.pyc create mode 100644 tests/__pycache__/test_makeundo.cpython-39.pyc create mode 100644 tests/__pycache__/test_movetype.cpython-39.pyc create mode 100644 tests/__pycache__/test_nullmove.cpython-39.pyc create mode 100644 tests/__pycache__/test_pass.cpython-39.pyc create mode 100644 tests/__pycache__/test_perft.cpython-39.pyc create mode 100644 tests/__pycache__/test_pgn.cpython-39.pyc create mode 100644 tests/__pycache__/test_players.cpython-39.pyc create mode 100644 tests/__pycache__/test_predict_hash.cpython-39.pyc create mode 100644 tests/__pycache__/test_result.cpython-39.pyc create mode 100644 tests/__pycache__/test_san.cpython-39.pyc create mode 100644 tests/__pycache__/test_score.cpython-39.pyc create mode 100644 tests/__pycache__/test_set_get.cpython-39.pyc diff --git a/learn_ataax.py b/learn_ataax.py new file mode 100644 index 0000000..2362375 --- /dev/null +++ b/learn_ataax.py @@ -0,0 +1,9 @@ +import ataxx + + +def main(): + board = ataxx.Board() + print(board) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tests/__pycache__/__init__.cpython-39.pyc b/tests/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cad5ceec2898fbf33135875753b03c6470a2ce9 GIT binary patch literal 174 zcmYe~<>g`k0*8~T=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o11_*(xTqIJKxa zrXV9TCo{%BFV&?evn(~nCAB!aB)=fWIatBS*doTUB(b7GA)qKfD>bl3H9+91|a(nU`4-AFo$Xd5gm)H$SB`C)EyQ*=HbT0092~ET8}Y literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_counters.cpython-39.pyc b/tests/__pycache__/test_counters.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2086dda45e2acf1600cdca0552934a595b6660e6 GIT binary patch literal 1017 zcmY*X&2G~`5Z+y{6F2=)g@B4%4uF&ch5k{55DHBtPAy0+60(e}ZPrPXICi@0RB7d$ z=!2x(xbhaf!d^M$4G<@0)@|jEwV(H!-`&{}%gZ$a()|6byXp|~2T55tkR~ks96%CD zW8xQo>eG)zGU;3q=|r^8zB|4n=@Du0Irx&pHey*AkR~ks5FjExmBeR~N_Isc(!ofx zcpT~MAj(ctsoNC%ZlwyF1z0Uu`WHYK4)cQoGK-EyZqc<^u~@a}0eVxKkr|Z>*L2Eq zx=+3}183??`P9uwpUs@y0ZS!kGoDwjDJ40XxjE}saz0=sUd`QtpY4_ML6ptnU6Yb; zMb-*mN#J^mhYiPP-A#oTnHyqnz?OWEau=T*X*c96e-iFK(tY%m2ShI3(H5(^e zmdtOW*vWR0rBZmX&g-HoMqI8KnF9W5Kv06O)N?_fnyx;Roq? zWW0__hoKgU@rGg$4N+GUT1P57R^!O5oQk-E+OQp`?SWb8jN`b(c>=sqHC#t=$G921 zvo`JtR`9Fnr!(bqOyYA4H5`>ciFyPl{`a-@HuwUybTB&Y#l7HD678$rc@*qNdXS}~ zpmkK=+hEW)rS{M#fIgW9^6ozMG5f>J<29@j$ zOYj(VI1Tug8aE!byup zf(S^6U%cSMYa*y{ZisLs^y#(ZI|7bL-Cd$B>2xh!Js7`;wT+AXY`MU5HkVm?clnTlD){52Ie^%^|l_1#O zdMEygJuUaK{H2|SvK{(v)QFnC%NrbN)QlR)H+iF8HXhIT<)!gnj<^!WQ#_5N+2C4B zmA&GLmWD-qC`T7knR~ssmrcVVf>0>_!ITTT6E#7zAsd zuy^O!!9`(Vm}2W;Xv!frEhdTOD`9v(;Yp!UcF*!=R>*xTv$MCGtu4bK$8}fPf()Ca hab|NFX0x|A&LICQJC%O|8TPD5{oH<}wjmiX`Wq|d*B}4@ literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_fen.cpython-39.pyc b/tests/__pycache__/test_fen.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e53699933e80e2acab666104f83323bc72abba05 GIT binary patch literal 2076 zcmbtV&2HO95Z)!1BIQU}j^u)o2U9CZ+v9|K0+uJ9^&TuX1Ygo=L_@oB_Whr<5ZgBPs8IDnyE z19ah%f6xgX(?jyx;lzl^1-&E_b4)Ibv3X&RjY~N4Eg&Vij9rp(QDQA5XEjdX3g%IR zO&^T*qOBM6U$i%JNA7cXd-{2%*lBJzcR)Rx(IC+-awUvnd6ER5bZoa6hIFMR)#Zsn3c+zHIpi&dftl!ba z6_Fbdv+41{H{L7orM%&3FYI~048)=Ay%XM{P;cXC=p7upJG(Ev@9}u|R~fw#o!A?` z2R;T(eJ3vlf|N$Q#WZXOJhZ&jo7W^S@5-IOpJ+{X9Cl#vpf@=rA%NKmOKH5Ds=vvvT9AUm^@nHaK3eg z#CfTD;BHPL11h2J0c~yraqNE)=gx@RSP56g*yBt-tJ2x5D@|fUNecD6sK~4up< zq{Khdl6P@=58+xEYdVZWD8gP4egOswqdO1cKg`YpxVaL*d{ZHOg-*8vjtZU5{qIh< z=wj~EP95JL1byNA>6-8NBYqy@y5{?5=RufhBvzVyfUt@18Nwo|^a@i*;+GWDK_3rC tuRFJ$x|ZgDCUwpSy%_T^buhUO0%-2ItIS>Me4E|pJN&RJbPPU?e*p?-*w+96 literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_gameover.cpython-39.pyc b/tests/__pycache__/test_gameover.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24844094d54c239382295ac6ec2c3522ef580abb GIT binary patch literal 1471 zcma)6-A)rh6rS0ix|9|W%3oq)y}*QvQVJqMj6qBEN;CqAY1V93W+;Vax9n`m(zI6) zo&zp@6n%ub@Ww0S8|aN^X4q1pRi~M6=bZDM@0^)t#?5Ba2*%pynd&bSp>M+I9tId| zFxf)@f(Z6dMSXDvzd}SK`WYfR#rxW+UeO8OM6%I1XVPG ziFSq{Qx}td@({gt2Q~SSj7D<_&Kksx_y2wXw1Sk?CHM z(!5CO6DmO{7eDUosZ;xwSJlo1J-Ii$ihD2F(xV^>vv2c6l?uu=vD&F51bz4TF8U6WR3>xcGiS z_Grsm5}l;Ax%vsu3V+7~Zx&*!07y&W|NQ+hrZPB@U#PaBn?ljGmdlAa6J_XhoQdQcNYu^pLp`b6UxNG!qT2KLLDq_HT+s6%5h6H eP&2Jk;6n`^2Yj12P3LurLAF7cksw?7Pw^6IAssf2rK7>JPxLAu;Tkphnv)*-Q z)~y@ar&MbD7jU(?^~iq#{{TpHMI3VC#=+vid$Tw-0x{P7_RX7lAM<{19ImgI0LSi6 zSGzw7fM02`I#36@ICT>tf{4Y?&cCe9aLr>raM})o`w%&icn*<}?2$Ne+HS-iK+Qcx zJ80FI+319EXB3B-40@sNbx6NDI4*W^>PrX`$a|YdEaK0h?c~1OB687Z!ITfA&c2jc zFO77E;rZooQJ}epQ-6*?4!Ru83DF#}5EZ+;E2eD1_Tk(2eLm$=CxaQA@Hv}`3C#FJ z%$zw)oFmjQcwCJD!+Nd7yW^d7`_|bn-5FQM)sL!;m|})c|G0VW;^^ucEUx6|np=&n zCZ1k?&(1F{H`26`(%!A@8)Fn2;~iS8xcmLH?>@c%;cs7*Ve#HFMoq#R@C2<8v!a*WVcYgLLXq znhs8V8{q}KV263{c(0&~o%ucco9^>denz$P5-EYO zyks-L{$O*+_ykT^-X9Ydp`<^+9qbx)om`5#gj9adW!)D1U${p0|iBWVGbC) zX@fg0MXh{FP%A2Wm#R!aDIsg&K&DTmGUZry!#Eh=LK|-o9!V077$s3!a}<@)xRD%Y zJtJu6H8*QSYCz>v74k@|s<#Q~vDxcwpaAR~-(-SQ}gW%O=ot zH;;K0WiM2)7c$-`>1ULwS+|W|KTaR2KGr!Wjndl-@#&Dwf4Mi_-8`#%M7yS{VGLH` Fe*wNSQp5lN literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_history.cpython-39.pyc b/tests/__pycache__/test_history.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a4da035257353a3b08c9db3e75c3121c33e0161 GIT binary patch literal 932 zcmYjP!EVz)5Z(3Kj+?rds)E7+^}-nyTdAsvwXLtD4R+oSr{(3t4&ItK~L0eo14ng%k z7(oQhNYwmkMC;gzocBaHg540oBt2(K7P*2Rlb(AEIb<+I+ZG3cLr}c~MiS(S96^P1 zLn0;^X4=gYsm%vz#)Z&B3j6M*0}g5*RR0EJ;806?M85u9&=FZUhOQjptm%SPY{k|@ zpBlGvmQ=6_QKx`;YqD^Szv@&j?D7B!DsN3GshrhDOy|DJDl-D2^Pt6{oBL*VvTU>kH62!gE-Zt+EIpbb~1EcERGguN~6 zDV~p{^|;}em)3h%a3yRo;!{~%NM%_jbGw~rW$ZLwY z_`3rSeh~E#4*T~@|5f}Mm~~u^(=3fY=JH6T7cxGQdSZ$)?jP?Rym%SE#a8w{sp4D? zO4nZ;6o|>1Pq}eby=70(13Q~3!QCH5Jw&9-`0TQgCmJ2ro<_n+;w!_21yQYwRw7h63jw6eaWm literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_is_legal.cpython-39.pyc b/tests/__pycache__/test_is_legal.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec5ce0687f8ae8787f2347f3cb090677235ba0a3 GIT binary patch literal 4896 zcma)=Pj4I76~$-Bk<7|%|bv&%>6SD0;AS$Ee}&;5;9Np=jE#=X3J@7y!@oqJ~}y1aC0E70rK zKR;>z@j(#$%RZcaMfz|{wzwwe0vAq$z5YGi3){dAz6tjRe+b;rMK1yu`S8K;`EW0C z;l1GM#&^mI?*979APBnXx?X#Oa=bUFWc9ckIGL9<`rPWhjI}4LW9`YjtdX^{GSQx_ zmN}W1HHr50UZ&lkO0_3*GB0ant*p$HC#z*n=4Fknm6f^nWVOu6e6H*1y_J=P_GGop z$-JzQwZ&dkj_WZ#?i81adDUj?^3~XBS3Wkcy5()RTJI{Z$I?OG<8^L}@rJL#*Wl~1 zPHVgJZY<^GrI*FRE5;kY1Mk4Q6MUm}PqlvBDoe5Oit$#h2k*iAagUd#QNt<9)No#TQ&Dg! zBRvz-q)hBwWrErXYA05YR)iEL1B2IH5LIMVWL0EU30+9&LP8f3t4c`lx_=b+xw?m< z8ipE%8ipE%I-xrW-AU+9LU$6nlhB>SP9X+(j9Co$o>}*2 zQ>IKp$|R&rLTWV&lY_zQ$rn{*Rb*9URVkB@G6^Y@kXoHWg4Z)sai6Q_W>mva!%)Le z!%(NpK*|iH%s|Qvq|89d45W4nF~DQYV!-#zUa^DO!R%mmFuRl)NST3@8AzFdlo?2w zfzYU&wi!TA#o|{Ck1>k@-!tpGBx+!8 zU~XV;VAi@gvmN4>VX3CeD=~HG*LdGOy zOhRTg3uE7CnZD}`BVUnKkyVjZWlTcGBxFoNW_1b)-g1S+>$@_lVW?rKVW?rKGiD%T z1~O(KV+Jy2AY%qHJB1kFF=jE~duDwPM-FBOvxC{e>@sE`V+Jy2AY%qHW*}n*GSf#4 z@EEfg@IAA><0B8VhuOpIVfGm_fQE`~22fJ5%>a5T7QbS6j9Co$p4t9>Xkcz&ZeVU; z*1Ams3d@T}9=tIKi8qFp+?L#yT&>t7prpKVLvBNEL$219C2w8eye*g( zObbRU!pNK2I#Cyug`K)Atn#uz+X8J1v}Lzqw_>*{P_;nS0#(7(U}`Wmn7Tm80woKS zEKssQN$?K51Mk4Q0`&^iD^RaMy#n>Xd+;8-2k#3MqjJTj81*YQ#lSb<8}JQyt(#Vy zqGh*bw`Er=rjn|y?MK1cmwp}eKQZ1@;Df!;1^Syibb}Yc-p~#8Ln7)fe&H9(&;9cL z%q{BhO!i3e1=(%c;_q_$O%i?+9xL4qUj)nGPVhWD9<0JU!I$&n;WB(VSPfr=$B~O{ ze-*tPzUna>ZsT}!H4rX8zOcHm+ISkw@2`TFkuV#p3$MagVHm77-DVLSZ$AD^JDX>B zScz7fOJzO}zZw|&@kcID`4{e9egD}9N7-z*_}{--cC>x8eSLfU?BjkT-Wl)2+FrjK zU4}@Y!F+zV&;7~zy1bvHytddQKUpJp`q%FIU9@8reUkf5*t^+|{y#QgZ?cV5 z*V)?M!uGwep6z!!k-c_RhrM?DkMI0^qQHA=q3k_hxA67V{!-^x*BZXQ3ijL`XSeHy z?4I3mKjn^F1z%o14wu0LySsFs{B7_!x)*#KTpe~B<+40F>Y~qQPklFP=Cg;BMS1w` zpc`Df-i3#A{hvdC`_Er)|91b+3qN1%Ke~S~J=p)_p}#Xfc_{CSt*`xj2_qOBY zH~XI&;r5^Avj@Ij?mzlk&xFGruCl+>Lt=rS94sbN-aWm3NoU3H7N8WCDV4^x=;Nqi`#{5=MF-g_pyv!IiCT|LxClgVNE&`&1a z)ciV2Y?GFPJ2Z{>ML+!##X7zfwgva{&v2Z@s78&R3xzWzCG;-i;$lvTW1->$5uZj}`4s$aRsk5?E!gT8kPamEna=2x?voEcW=2frbZR7Y z#-?m;Bt%_JS&wm}Pb6@2Ga)k*PAehczcaIdFHEh3QZgm;h0J4W_F1Z7b2}mbSRghf zqg}igliuRIn2`Vb#-({VLxikyc%wDYE+s^Mhcm?)UFC8x`WaH06KDxLtXUVUldWiD z`|lTRO{$aXv+Cx>qs-8#Z`K=NzB$n$N*x~O9h&v#9hW;XZjH!oZ`{UM+umqKsA^7- zq7*f<1g^irpQu%|<;C7)qODhvC%Lve-atfWLh8!NI0y#7x_%J(eZ9~Tv3nvyT?$0U z3tTiQZ4bP@Kvow$rG$)+c`R0X&qG?&F9WbtgZT1Mm^!j&hQ)_XIM`Qc4By~Dy1&gfElk3&vga$sm4VWzFYMK z2%)xZ)1t9VZC0j53MXA*_kk|63N16Rv5U3b2&~@?bO;k-yKV^WbzNO_p?`cFAYXRf z(bx+zi+l)BX^lDZ0ChNmFz!SlW7AZwSrVsR+vBhsBc8mMikL>rgZ`jzE)e!kVl-{< QX812~P!(2bLn*fL2Wm?qZvX%Q literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_movetype.cpython-39.pyc b/tests/__pycache__/test_movetype.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b767b8bc921b09be6ababc732fc815f72e58c62e GIT binary patch literal 777 zcmY*X&2G~`5T5bc)TAjOfjEGWA|#MzH$saw}hympmD z$%#Hl!i`7a#(A%tcm+<(I3hJ;&A0Qj^W)hGwzeuj)c)~e@Dl-ku~H_Rls2(`NgzRD z1ijUXJ$wh!lHvxWPjo%NaHQEh zQ966CvhzghJ~gx^holYS4zcbM45*oJIL8@w;Y)LFWw5}RwZyrYiG{TUvObyHGgye3 zy|9-+=q%wS!d{mV{1+AmHJ$*RdOLq3xU$Qr@ji*mn#%5!;(InTulby-*S=rfY zwElCiV{aWS?e7$^^*hE1vS2(m&f6qNrP++sAc*{{nqLn9oKq-qqD8YTU@$&F8 vY8G59^tzo2(u|wOVaBzL%hfvp{WxDM<=~;DoXEI`tJ1G|yELbC(Y5{pi(|ua literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_nullmove.cpython-39.pyc b/tests/__pycache__/test_nullmove.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44bca19e44138b48fdeed63fb4b5671a83a66ca4 GIT binary patch literal 925 zcmZWoPjAyO6t`oiO$(hkKnJ&8KwVDKI|NG;UUk)KZQK%9JVIQ`B0!$D= z6XKUA_31kz9KkM$V3M9XOXf2{k4Tqqz?Te1$g2eSCDwhoNa9mLd`D2>ToQ<67-{bu zOKlFNnaqVA(MmLy*?>KOt$zT^$%+_AyJBlNR|vFSYd&?>l>TpbpjcR7XSa5KgRrE6 zm2rUOu1P_!PbYU)wHvQ(99`AdWaSCIrU5Tl!3(#jfmc;qFTA1wTBtE+dHruiInTXH z{zmRXW_OpEM&4M`(oYZ=MQynG4Ww`emOlf!qMZ#&-KK3uT1#b))k0b~GST_D<%jb# zX?eOx63etv)_psVl(60`n#vj4>L=2KW0_i4XGv@gPNbpkqNR3`1I-1ZBK!Lx1hH?#J({7UUp$ysK3>?kW9CM z5!!+E(DA6p?m2DRW;=9;etlGVQG5SH4&l9dVVFiU8HTnQhO@a?BzV6YhF=y@Qd-n5 zU~hY>FifcMLE{gi@#4{~+~vvx$$E=4Hki(OSim5HQJ`A|1IMHg$a=5J)UWaTYJ`L) FoIfA|@gV>J literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_pass.cpython-39.pyc b/tests/__pycache__/test_pass.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21869da29cdfb495ad10447e7f03eae8d75335e2 GIT binary patch literal 1403 zcmb7EOK;Oa5Z?78anh!QLWPPDR4p1Bb}SGTm*O*0EFDsocmp zwZDQ>!i}GTg!ln_<-$K1z7}A*Tl8>KFWvC3*kc?=ojOkE|wUII=Lp@Yu{gMtdF&UvvACp); zg$PPul^GNNi}YkzF|nR~h*kf`#CCfUiMcu}u9A?PWJkuBOk>f5xtgp9t283k&neo@ zJ}?4Dw7fsK7j1df?djufMWv`zE7e~Q9wnajO1-iU{&b#3qyZb1jfoSr?drdP2Wj0+ z&-1D&ObD8Td2SE+XS`7qRW~Q#CEd;SCb@NpMyXa3na&=OWkb2cgvii!j=DmqU~S<9j9Zyb@{H}Ip^js4^Bg`XEqK> z>l;tam)LOWo$sCS!_e$qz;EnUs>#T1(iN{|7R=LX= zzzfR9>k6;G02PDEby@S#B#ge>36V+|NZzpFa4>A91|FP`g@o}up?-nyHNbq_#9zmK BV8Q?Z literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_perft.cpython-39.pyc b/tests/__pycache__/test_perft.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0dd1971e990c277b93df631b3a061319a36cb145 GIT binary patch literal 1777 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 literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_predict_hash.cpython-39.pyc b/tests/__pycache__/test_predict_hash.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da79755dc46433aed1e2134ee272251ebc748dc0 GIT binary patch literal 1121 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 JyZ)LVeG3H2I)MNH literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_score.cpython-39.pyc b/tests/__pycache__/test_score.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..640fe2215482821758eb47129d7eeed24dbb6f88 GIT binary patch literal 1049 zcmb7D&2G~`5Z+ze!F7_h5>dDykpm#*kcK3bB1BOjkvI{M+Fl|f%Vf7{+SHrwI>@z> z6Mc~M$fI!LzE@6p0S;VX)+Rqvd+AvF?ab`VeB;%upU*o8r1|4XpBM=J(#E=&U^HRL zrvMaDJVf1e$6fp$Q9_L?L=A>d$v2~GP<(*O<{V;Cr>AjU2pCORvH-wP7gN+F6jO4A zAk)y9DtpLe_<@BdoXQ@CxP@4tWMQ>n$pAnn_JKY@GeIlC47~?_n{EI)iJndL9L1n-EtJEQ8u`i<*0gX!I|Do3Qs;hwetJs{I})2<{W)sAa*rTax}%f9 zaNvFnSX&IfGPlj-S;$9j>!4I`yma4cy3!}XPgyT?N0%^pK_%(IO$ZY766&4NrE;`0 zHT6WwhX9CV@Qv@cna^Pd$HldQ-dQDg;8$(W3;c8DdCKv;b56%Yt>--NV(bso6R{2D zlOI}xE$!2fNk2}h6&ojZ*%TSDlsygxq2^MyW^eg$4?1kEhQ1@A3n}|`O8rL9l+-0{ GY?FV%Z4TT3 literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_set_get.cpython-39.pyc b/tests/__pycache__/test_set_get.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3af652e07adfabf4ebf8aa7c17eee1e7a399174 GIT binary patch literal 937 zcmZ`%L2DC16rMM;+iYXnLlx;sdQlqCAbJrgr8TKlw6)MkaoMu0nMs;6;d+&R1CR$i1GF%(q@3y`HV?W54T@D%> zDEc0PWD;WLPj~QPn@KLk1(QO-F+Uf+kg(6n&KU2q-3H<8;%IE3=vxSi`5>9kB}jh3 zFj7#Yy-`=%>?m`TNZmj}*J}>7c@%-74MGdae1*^KBWq#`q~U#HHFgd|FzgbfGlC({ zp~eoM2Ye`oj$y|fMWB%GHXZb>4&9tz&gCL^a(5(v>Kd7jyEH=O&82gV4e%hqs47d=E>+GUqM+Mf6HNXP;fM zjQT7K%PS8pG%aLT;5*%ZM^7BT4ysRsw_0U7NRQfaJ9yJowXFR?1vRBlOp*rG{gp?L zp9GsGIz3(4%aUW&FhM%NnRXvUbQl;MvYue5l?hwQRMLShuElL_8c8QzFCc@TDD3S1 z%!5=Y?mA*EP8w0H*DHU*tgAYy8I)T?au^&^<`pOCnZi A?f?J) literal 0 HcmV?d00001 From a45048deb39b7c68a9867c2b2b0718efe792c8ae Mon Sep 17 00:00:00 2001 From: pabaill Date: Tue, 5 Nov 2024 21:42:59 -0800 Subject: [PATCH 2/7] Alpha Beta Agent Sim --- learn_ataax.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/learn_ataax.py b/learn_ataax.py index 2362375..5eb79ad 100644 --- a/learn_ataax.py +++ b/learn_ataax.py @@ -1,9 +1,106 @@ import ataxx +import sys +import ataxx.players + +def play_solo(): + fen = input("FEN: ") + if fen == "": + fen = "startpos" + board = ataxx.Board(fen) + + while not board.gameover(): + print("\n\n\n") + print(F"FEN: {board.get_fen()}") + print(board) + try: + print(f'Legal moves: {[(m.to_x, m.to_y) for m in board.legal_moves()]}') + move_string = input("Move: ") + move = ataxx.Move.from_san(move_string) + if board.is_legal(move): + board.makemove(move) + else: + print(F"Illegal move: {move}") + except KeyboardInterrupt: + print("") + break + + print(F"Result: {board.result()}") + +def alphabeta(board, alpha, beta, depth, root=True): + if depth == 0: + black, white, _, _ = board.count() + if board.turn == ataxx.BLACK: + return black - white + else: + return white - black + + best_move = None + + for move in board.legal_moves(): + board.makemove(move) + score = -alphabeta(board, -beta, -alpha, depth-1, root=False) + + if score > alpha: + alpha = score + best_move = move + if score >= beta: + score = beta + board.undo() + break + + board.undo() + + if root: + return best_move + else: + return alpha + +# Two alpha-beta players play against each other +def play_alphabeta(depth=2, opponent='alphabeta'): + board = ataxx.Board("startpos") + turn_counter = 1 + + while not board.gameover(): + try: + if turn_counter % 2 == 1: + move = alphabeta(board, float('-inf'), float('inf'), depth) + else: + if opponent == 'alphabeta': + move = opponent(board, float('-inf'), float('inf'), depth) + else: + move = opponent(board) + if board.is_legal(move): + board.makemove(move) + else: + print(F"Illegal move: {move}") + except KeyboardInterrupt: + print("") + break + # print(board) + # next = input("NEXT:") + turn_counter += 1 + + print(F"Result: {board.result()}") + return board.result() + def main(): - board = ataxx.Board() - print(board) + if len(sys.argv) == 0: + print("Available modes: solo") + mode = sys.argv[1] + if mode == 'solo': + play_solo() + if mode == 'alphabeta': + wincount = 0 + n_games = 10 + for i in range(n_games): + result = play_alphabeta(opponent=ataxx.players.random_move) + if result == '1-0': + wincount+=1 + print(wincount / n_games) + + if __name__ == '__main__': - main() \ No newline at end of file + main() From 6bcba5dfdc10329da9394f3bf3ba9ca3946e33db Mon Sep 17 00:00:00 2001 From: pabaill Date: Fri, 8 Nov 2024 15:06:40 -0800 Subject: [PATCH 3/7] initial arbitrary size board --- ataxx/__init__.py | 154 +++++++++++++++++++++++++--------------------- ataxx/zobrist.py | 71 ++++++++------------- learn_ataax.py | 27 +++++--- 3 files changed, 129 insertions(+), 123 deletions(-) diff --git a/ataxx/__init__.py b/ataxx/__init__.py index 5b9a81d..643b6af 100644 --- a/ataxx/__init__.py +++ b/ataxx/__init__.py @@ -14,6 +14,12 @@ FEN_4SIDES = "x5o/7/3-3/2-1-2/3-3/7/o5x x 0 1" FEN_EMPTY = "7/7/7/7/7/7/7 x 0 1" +# Additional Parameters +FEN_CENTERX = "x-3-o/1-3-1/2-1-2/3-3/2-1-2/1-3-1/o-3-x x 0 1" +FEN_ISLAND = "x5o/3-3/2-1-2/1-3-1/2-1-2/3-3/o5x x 0 1" + +BOARD_DIM = 7 + class Move: def __init__(self, fr_x, fr_y, to_x, to_y): self.fr_x = fr_x @@ -27,23 +33,23 @@ def from_san(cls, san): if san == "0000": return cls.null() elif len(san) == 2: - if san[0] not in "abcdefg": - raise Exception(F"ValueError {san}") - elif san[1] not in "1234567": - raise Exception(F"ValueError {san}") + # if san[0] not in "abcdefg": + # raise Exception(F"ValueError {san}") + # elif san[1] not in "1234567": + # raise Exception(F"ValueError {san}") to_x = ord(san[0]) - ord('a') to_y = ord(san[1]) - ord('1') return cls(to_x, to_y, to_x, to_y) elif len(san) == 4: - if san[0] not in "abcdefg": - raise Exception(F"ValueError {san}") - elif san[1] not in "1234567": - raise Exception(F"ValueError {san}") - elif san[2] not in "abcdefg": - raise Exception(F"ValueError {san}") - elif san[3] not in "1234567": - raise Exception(F"ValueError {san}") + # if san[0] not in "abcdefg": + # raise Exception(F"ValueError {san}") + # elif san[1] not in "1234567": + # raise Exception(F"ValueError {san}") + # elif san[2] not in "abcdefg": + # raise Exception(F"ValueError {san}") + # elif san[3] not in "1234567": + # raise Exception(F"ValueError {san}") fr_x = ord(san[0]) - ord('a') fr_y = ord(san[1]) - ord('1') @@ -93,9 +99,10 @@ def __str__(self): return F"{chr(ord('a')+self.fr_x)}{self.fr_y+1}{chr(ord('a')+self.to_x)}{self.to_y+1}" class Board: - def __init__(self, fen=FEN_STARTPOS): - self._board = [[GAP for x in range(7+4)] for y in range(7+4)] - self._counts = [0, 0, 0, 49] + def __init__(self, fen=FEN_STARTPOS, board_dim=BOARD_DIM): + self.board_dim = board_dim + self._board = [[GAP for x in range(self.board_dim+4)] for y in range(self.board_dim+4)] + self._counts = [0, 0, 0, self.board_dim ** 2] self.set_fen(fen) def get(self, x, y): @@ -140,11 +147,12 @@ def count(self): return self.num_black(), self.num_white(), self.num_gaps(), self.num_empty() def __str__(self): - board = " a b c d e f g\n" - board += " ╔═╦═╦═╦═╦═╦═╦═╗\n" - for y in range(6, -1, -1): - board += chr(y+49) + '║' - for x in range(0, 7): + board = " " + " ".join(chr(ord('a') + x) for x in range(self.board_dim)) + "\n" + board += " ╔" + "═╦" * (self.board_dim - 1) + "═╗\n" + + for y in range(self.board_dim - 1, -1, -1): + board += chr(y + 49) + '║' + for x in range(self.board_dim): if self.get(x, y) == BLACK: board += 'X' elif self.get(x, y) == WHITE: @@ -156,26 +164,29 @@ def __str__(self): else: board += "?" board += '║' - board += chr(y+49) + '\n' + board += chr(y + 49) + '\n' + if y > 0: - board += ' ╠═╬═╬═╬═╬═╬═╬═╣\n' - board += " ╚═╩═╩═╩═╩═╩═╩═╝\n" - board += " a b c d e f g\n" + board += ' ╠' + "═╬" * (self.board_dim - 1) + "═╣\n" + + board += " ╚" + "═╩" * (self.board_dim - 1) + "═╝\n" + board += " " + " ".join(chr(ord('a') + x) for x in range(self.board_dim)) + "\n" + if self.turn == BLACK: board += "Turn: X" elif self.turn == WHITE: board += "Turn: O" else: board += "Turn: ?" + return board - def get_fen(self): """Return a fen string for the current position""" fen = '' - for y in range(6, -1, -1): + for y in range(self.board_dim - 1, -1, -1): empty = 0 - for x in range(7): + for x in range(self.board_dim): if self.get(x, y) != EMPTY and empty > 0: fen += str(empty) empty = 0 @@ -218,28 +229,34 @@ def set_fen(self, fen): fen = FEN_STARTPOS elif fen == "empty": fen = FEN_EMPTY + elif fen == "island": + fen = FEN_ISLAND + elif fen == "foursides": + fen = FEN_4SIDES + elif fen == "centerx": + fen = FEN_CENTERX parts = fen.split() - if len(parts) < 1 or len(parts) > 4: - return False - if parts[0].count('/') != 6: - return False - if len(parts[0]) < len("7/7/7/7/7/7/7"): - return False - if len(parts[0]) > len("xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx"): - return False + # if len(parts) < 1 or len(parts) > 4: + # return False + # if parts[0].count('/') != 6: + # return False + # if len(parts[0]) < len("7/7/7/7/7/7/7"): + # return False + # if len(parts[0]) > len("xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx/xxxxxxx"): + # return False # Clear board - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): self.set(x, y, EMPTY) self.turn = BLACK self.halfmove_clock = 0 self.fullmove_clock = 1 self.history = [] self._halfmove_stack = [] - self._counts = [0, 0, 0, 49] + self._counts = [0, 0, 0, self.board_dim ** 2] # Add side to move if len(parts) < 2: @@ -256,7 +273,7 @@ def set_fen(self, fen): # Set board sq = 0 for c in parts[0]: - x, y = sq%7, 7 - sq//7 - 1 + x, y = sq%self.board_dim, self.board_dim - sq//self.board_dim - 1 if c in "1234567": sq = sq + int(c) @@ -279,9 +296,8 @@ def set_fen(self, fen): return False # We need to have parsed the right number of squares - if sq != 7 * 7: - return False - + # if sq != self.board_dim ** 2: + # return False # Set turn if parts[1] in "bBxX": self.turn = BLACK @@ -305,7 +321,7 @@ def set_fen(self, fen): # Save fen self._start_fen = ' '.join(parts) - self.hash = calculate_hash(self) + self.hash = calculate_hash(self, self.board_dim) return True @@ -331,10 +347,10 @@ def makemove(self, move): return self.set(move.to_x, move.to_y, self.turn) - self.hash ^= get_sq_hash(move.to_x, move.to_y, self.turn) + self.hash ^= get_sq_hash(move.to_x, move.to_y, self.turn, self.board_dim) if move.is_double(): - self.hash ^= get_sq_hash(move.fr_x, move.fr_y, self.turn) + self.hash ^= get_sq_hash(move.fr_x, move.fr_y, self.turn, self.board_dim) self.set(move.fr_x, move.fr_y, EMPTY) for idx, (dx, dy) in enumerate(SINGLES): @@ -344,8 +360,8 @@ def makemove(self, move): self.set(x, y, self.turn) self._counts[self.turn] += 1 self._counts[opponent] -= 1 - self.hash ^= get_sq_hash(x, y, opponent) - self.hash ^= get_sq_hash(x, y, self.turn) + self.hash ^= get_sq_hash(x, y, opponent, self.board_dim) + self.hash ^= get_sq_hash(x, y, self.turn, self.board_dim) else: move.flipped[idx] = False @@ -379,13 +395,13 @@ def undo(self): return # Remove the piece we placed - self.hash ^= get_sq_hash(move.to_x, move.to_y, self.get(move.to_x, move.to_y)) + self.hash ^= get_sq_hash(move.to_x, move.to_y, self.get(move.to_x, move.to_y), self.board_dim) self._counts[us] -= 1 self.set(move.to_x, move.to_y, EMPTY) # Restore the piece we removed if move.is_double(): - self.hash ^= get_sq_hash(move.fr_x, move.fr_y, us) + self.hash ^= get_sq_hash(move.fr_x, move.fr_y, us, self.board_dim) self._counts[us] += 1 self.set(move.fr_x, move.fr_y, us) @@ -396,8 +412,8 @@ def undo(self): self.set(move.to_x + dx, move.to_y + dy, them) self._counts[us] -= 1 self._counts[them] += 1 - self.hash ^= get_sq_hash(move.to_x + dx, move.to_y + dy, us) - self.hash ^= get_sq_hash(move.to_x + dx, move.to_y + dy, them) + self.hash ^= get_sq_hash(move.to_x + dx, move.to_y + dy, us, self.board_dim) + self.hash ^= get_sq_hash(move.to_x + dx, move.to_y + dy, them, self.board_dim) def predict_hash(self, move): """Calculate the hash after a move is played without applying the move""" @@ -415,16 +431,16 @@ def predict_hash(self, move): if move == Move.null(): return hash - hash ^= get_sq_hash(move.to_x, move.to_y, self.turn) + hash ^= get_sq_hash(move.to_x, move.to_y, self.turn, self.board_dim) if move.is_double(): - hash ^= get_sq_hash(move.fr_x, move.fr_y, self.turn) + hash ^= get_sq_hash(move.fr_x, move.fr_y, self.turn, self.board_dim) for dx, dy in SINGLES: x, y = move.to_x + dx, move.to_y + dy if self.get(x, y) == opponent: - hash ^= get_sq_hash(x, y, opponent) - hash ^= get_sq_hash(x, y, self.turn) + hash ^= get_sq_hash(x, y, opponent, self.board_dim) + hash ^= get_sq_hash(x, y, self.turn, self.board_dim) return hash @@ -453,8 +469,8 @@ def legal_moves(self): return [] movelist = [] - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): # Singles if self.get(x, y) == EMPTY: for dx, dy in SINGLES: @@ -471,8 +487,8 @@ def legal_moves(self): if movelist == []: # If the opponent can move, we have to pass opponent = WHITE if self.turn == BLACK else BLACK - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): if self.get(x, y) == opponent: # Singles for dx, dy in SINGLES: @@ -495,8 +511,8 @@ def must_pass(self): bool:Whether the side to move must pass """ - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): if self.get(x, y) == self.turn: # Singles for dx, dy in SINGLES: @@ -526,10 +542,10 @@ def is_legal(self, move): if self.must_pass(): return move == Move.null() - if move.fr_x < 0 or move.fr_y > 6: - return False - if move.to_x < 0 or move.to_y > 6: - return False + # if move.fr_x < 0 or move.fr_y > 6: + # return False + # if move.to_x < 0 or move.to_y > 6: + # return False if move.is_single(): # To square must be empty @@ -598,8 +614,8 @@ def gameover(self): return True # No moves left - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): if self.get(x, y) in [BLACK, WHITE]: # Singles for dx, dy in SINGLES: @@ -620,8 +636,8 @@ def result(self): has_moves: bool = False # No moves left - for x in range(7): - for y in range(7): + for x in range(self.board_dim): + for y in range(self.board_dim): piece = self.get(x, y) if piece == BLACK: diff --git a/ataxx/zobrist.py b/ataxx/zobrist.py index 9573aab..442292c 100644 --- a/ataxx/zobrist.py +++ b/ataxx/zobrist.py @@ -1,65 +1,44 @@ import ataxx +import random + turn = 0x2e98304a94e1000d +# Maximum size of the board, assuming `board_dim` could go up to 10 for example +MAX_BOARD_DIM = 99 + +# Generate random hashes for each piece position +def generate_piece_hashes(board_dim): + return [random.getrandbits(64) for _ in range(board_dim * board_dim)] + +# Piece array will now dynamically generate hashes based on the board size piece = [ - [ - 0xddd67db865dc92f9, 0x31ad7f3d49884764, 0xfc810e82600d77ed, - 0xa329bc2fe9a585c2, 0x0dd7013c7b5f9ee0, 0xcbfb18e330c5152b, - 0x5ca13c8237e969f0, 0xcfe82be3298f4860, 0xd74ee79ab8cd59d4, - 0x76c9804b3dd3dd9a, 0x62fe43ac3416344b, 0x84f44cfc5640f1fb, - 0xee80f44f274d194f, 0x9e132307eaa1062a, 0x8ef3b83e05104b8c, - 0x7458cb4e38a56b1b, 0x496ae857824032b5, 0x297892ab4aed9139, - 0x2c63a6ed1e5c503b, 0xb806e46b057da75c, 0x8e3ee3fc5ea21f4d, - 0x7bb71073c6b32631, 0xa34cbc35fea7986d, 0x2cf34121f29c2073, - 0x3ff14ac1cfb3ac44, 0x9a1f60c67467b9eb, 0x4f69347f2d665427, - 0x4d51d73c213217bc, 0x6b3089c84d5d78e3, 0xa2923e3c0bbc0f50, - 0xe4931d122c14c947, 0xa1b03c639fe421a7, 0x2789a4dc1574310c, - 0x4e3f96a633e0ede0, 0xe4f29bf5ff2869df, 0x72e7fe1c77af10b3, - 0x245e4d0677acbd90, 0x5eb16a0a6cff1f55, 0x26e93216b330c067, - 0x0eced566d7522ad3, 0xdc64bc04aa39e421, 0x401987ae3cb114db, - 0xd0d0b88ece5f0c16, 0x13275209f4ddff5a, 0xffb20d8b83a2ce28, - 0x8f2100bf98b54217, 0x3769a2d70b7209e7, 0x61b3cca215f1a975, - 0x8d1158e421453a0f, - ], - [ - 0xd33fd8453c18380c, 0xd7949af7fa5e24ca, 0xa75e294be7913781, - 0x3b615f1e3322be8c, 0xe4c885ecb48d6187, 0x9b92f432a8d105f3, - 0xbff867477fb93a23, 0x5ff3e0b5e6e72ab4, 0xe60144f2900bc655, - 0xf29a0de00bdc3aee, 0xde9e042c06230fd8, 0x4264ec62f70ba708, - 0x5f175b53ebb138c7, 0x439e71025499179e, 0xcf39b10d6a8437fd, - 0x0fcf1fc30f9e0de4, 0x6a502645f6a31fef, 0xd47dd00cf21ddfdd, - 0x7e4ca0ec0c2e7f68, 0x37401f0941e5a469, 0x3efddb557fd01cb4, - 0x846bfb50b6965c90, 0xc0fa4a424c735605, 0xe5fbff674c562239, - 0x3826959008ef40f0, 0x4a712b5964a4b7a1, 0x68f594a0740c456f, - 0x1ee9e39d56bd32e6, 0x08ebd76592898d31, 0x3df7c91613fb946d, - 0xef3e760a57d5a399, 0x6ef3128154e16b88, 0x15e27065e3d4c108, - 0xd5fe096a16b5eed2, 0xb2964fa8f1bddad1, 0x3ebb6f3af8a61dc5, - 0x9776dc9ebc5243d2, 0x4660bff8b53c4a78, 0x73507ecb48163932, - 0x05967644e76ae2f8, 0x9c53ce9f0fdcb066, 0xcf6e214c6acea558, - 0x53ee7540169475d8, 0xc8a49004b87946b8, 0x1d75d48ff9dc94b2, - 0xec4f8821305bbd96, 0x43ed7506a2bd6b16, 0xf0eb5d0784e3eb03, - 0xe578cac94b342a86, - ], - ] + generate_piece_hashes(MAX_BOARD_DIM), # For BLACK + generate_piece_hashes(MAX_BOARD_DIM), # For WHITE +] + +# You can adjust the above `MAX_BOARD_DIM` based on your needs or pass `board_dim` dynamically. + -def calculate_hash(b): +def calculate_hash(b, board_dim): key = 0 if b.turn == ataxx.BLACK: key ^= turn - for y in range(7): - for x in range(7): + for y in range(board_dim): + for x in range(board_dim): if b.get(x, y) == ataxx.BLACK: - key ^= piece[0][y * 7 + x] + # For BLACK pieces, use piece[0] + key ^= piece[0][y * board_dim + x] elif b.get(x, y) == ataxx.WHITE: - key ^= piece[1][y * 7 + x] + # For WHITE pieces, use piece[1] + key ^= piece[1][y * board_dim + x] return key def get_turn_hash(side): return turn -def get_sq_hash(x, y, side): - return piece[side][y * 7 + x] +def get_sq_hash(x, y, side, board_dim): + return piece[side][y * board_dim + x] diff --git a/learn_ataax.py b/learn_ataax.py index 5eb79ad..b2b749d 100644 --- a/learn_ataax.py +++ b/learn_ataax.py @@ -2,11 +2,15 @@ import sys import ataxx.players +BLACK, WHITE, GAP, EMPTY = 0, 1, 2, 3 + def play_solo(): fen = input("FEN: ") + board_dim = int(input("BOARD SIZE: ")) if fen == "": fen = "startpos" - board = ataxx.Board(fen) + board = ataxx.Board(fen, board_dim=board_dim) + print(board) while not board.gameover(): print("\n\n\n") @@ -26,6 +30,10 @@ def play_solo(): print(F"Result: {board.result()}") +# T +def eval_function(board: ataxx.Board): + return 0 + def alphabeta(board, alpha, beta, depth, root=True): if depth == 0: black, white, _, _ = board.count() @@ -56,19 +64,20 @@ def alphabeta(board, alpha, beta, depth, root=True): return alpha # Two alpha-beta players play against each other -def play_alphabeta(depth=2, opponent='alphabeta'): - board = ataxx.Board("startpos") +def play_alphabeta(depth=2, opponent='alphabeta', board="startpos", board_dim=7): + board = ataxx.Board(board, board_dim=board_dim) turn_counter = 1 while not board.gameover(): try: if turn_counter % 2 == 1: - move = alphabeta(board, float('-inf'), float('inf'), depth) - else: + # Opponent goes first because if we go first we can win easily if opponent == 'alphabeta': - move = opponent(board, float('-inf'), float('inf'), depth) + move = ataxx.players.alphabeta(board, float('-inf'), float('inf'), depth) else: move = opponent(board) + else: + move = alphabeta(board, float('-inf'), float('inf'), depth) if board.is_legal(move): board.makemove(move) else: @@ -81,6 +90,7 @@ def play_alphabeta(depth=2, opponent='alphabeta'): turn_counter += 1 print(F"Result: {board.result()}") + # print(board) return board.result() @@ -92,10 +102,11 @@ def main(): if mode == 'solo': play_solo() if mode == 'alphabeta': + board_size = int(input("BOARD SIZE: ")) wincount = 0 - n_games = 10 + n_games = 1 for i in range(n_games): - result = play_alphabeta(opponent=ataxx.players.random_move) + result = play_alphabeta(opponent='alphabeta', board="island", board_dim=board_size) if result == '1-0': wincount+=1 print(wincount / n_games) From 7f972eb059589a339960d8e6176de44012e13ef9 Mon Sep 17 00:00:00 2001 From: pabaill Date: Wed, 20 Nov 2024 21:24:53 -0800 Subject: [PATCH 4/7] Hierarchial Softmax Agent --- __pycache__/hsm.cpython-39.pyc | Bin 0 -> 9656 bytes endgame.txt | 794 +++++++++++++++++++++++++++++++++ hsm.py | 344 ++++++++++++++ learn_ataax.py | 190 +++++++- 4 files changed, 1313 insertions(+), 15 deletions(-) create mode 100644 __pycache__/hsm.cpython-39.pyc create mode 100644 endgame.txt create mode 100644 hsm.py diff --git a/__pycache__/hsm.cpython-39.pyc b/__pycache__/hsm.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bf58ced6917f6636251476ed18d150e634da2b2 GIT binary patch literal 9656 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 literal 0 HcmV?d00001 diff --git a/endgame.txt b/endgame.txt new file mode 100644 index 0000000..b1d49dc --- /dev/null +++ b/endgame.txt @@ -0,0 +1,794 @@ +oooooo1/ooxxxo1/xxxxx2/oxoxx2/1xoxx2/7/6x o 2 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x3oo1/4xx1/3-x2/2-1-x1/1xx-x2/xxxxxx1/xxoxxx1 o 2 18 +1-3-1/1-xx1-x/ox-x-xx/xoo-oxx/x1-o-xx/1-3-x/1-3-x o 2 18 +xx5/x4xx/3-1xx/2-o-oo/1oo-xx1/1oooxxx/1oooxxx o 3 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x1oxxx1/x1oxxxx/3-xxx/2-1-oo/3-ooo/o3xoo/o3xxx o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oxxxo2/oxxxxxo/ooo-ooo/xx-1-o1/3-3/6x/o5x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +6o/7/xxo4/xxox3/xxoxo2/oxxxo2/oxx2o1 o 0 18 +6o/7/1oo4/xoxx3/ooxxxx1/xoxxxxo/ooooxxx o 0 18 +xxxxo2/oxxxo2/oxx-3/oo-1-2/1ox-3/1xxo3/ooo4 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +ooo3o/ooo-oo1/2-1-oo/1-3-o/1x-1-xx/1xx-xxx/1oo1x1x o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x3xoo/3-ooo/2-1-oo/1-2x-o/1x-1-xo/1xx-xoo/1oo1xxx o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +2xxxoo/3xxxx/3-xoo/2-1-xx/3-xxx/3xxxx/2oxxxo o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +3oxx1/3oxxx/3-oox/2-1-oo/3-ooo/3xooo/o3oo1 o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +ooooo2/oox-x2/ox-o-2/x-xx1-1/xx-o-2/xxx-2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xx2oox/3-xxx/2-1-ox/1-1oo-x/2-o-xx/3-xxx/o3xxx o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oo4o/xxo3o/xxo-3/xx-1-2/xxo-x2/xxooxx1/xxoox2 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +ox3oo/oxx-3/xx-1-2/x-2o-o/2-1-ox/xx1-xxx/xxxxxxx o 0 18 +x4x1/3-xxx/2-o-o1/1-xoo-x/1x-o-2/xxx-3/xxxx2x o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +6o/1xxo3/xx1o3/xxxxx2/xxxxx2/xxxx3/xxxo2x o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x6/xx1-3/xo-x-x1/x-oxx-1/xo-x-2/xx1-x2/oxxx3 o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oxxxooo/xxxxooo/ox1-ooo/xx-o-oo/1x1-3/7/o5x o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xx2xx1/ooo-xx1/oo-1-2/o-3-1/oo-1-2/xxx-3/xxx2xx o 3 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oooxxxo/oxxxxxo/xxo-o2/ox-x-2/oxx-3/7/6x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x3xxx/x2-xoo/2-1-oo/1-2o-o/2-1-ox/2x-xxx/2xxxxx o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x3o2/5o1/3-1oo/2-1-xx/x2-xxx/xx1oxxx/x2ooxx o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxo3o/xxoo3/xx1o3/xxx4/xxx4/oooo3/oooo3 o 1 18 +xx5/7/3-2x/xx-x-xx/oox-xox/ooooooo/oooxxxo o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xx4o/xx1-3/1x-1-2/o-3-1/oo-x-xo/oox-xxx/xoooxxx o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +6o/1xx4/oxx4/oxo4/xxxxo2/xxxxo2/x1xx2x o 1 18 +x5o/7/7/1xxxoxx/oooxoxx/ooox1oo/oooxxxx o 1 18 +3oooo/2oooox/2xxoox/2xxxxx/5oo/4oxx/o5x o 1 18 +6o/xxx4/1xx-3/oo-1-2/ooo-xx1/ooooxxx/xoooxxx o 1 18 +1-o2-1/x-oxx-1/xx-x-xo/xxx-1oo/xx-x-xx/o-3-x/o-3-o o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxo/xxxxxxo/xx-x-xo/xxx3o/xx-1-2/6x/6x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x1oo2o/xxxx3/ox-x-2/oox4/1o-x-2/2ox1xx/2xxxxx o 1 18 +x2oo1x/3-xoo/2-x-oo/1-2x-o/2-x-xx/2x-xxx/2ooooo o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox2oo/oox-3/oo-1-2/x-x2-1/ox-x-x1/xxx-xx1/oxx1ooo o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxxxxxx/oxxxooo/xxx-ooo/1x-1-oo/3-1xx/1o5/o5x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxxxxoo/oox-xox/1o-1-ox/1-3-1/xx-1-2/xxx-1x1/oox3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +3ooxx/2xooxx/2xoox1/3oxxo/4oxo/4oxx/o4ox o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +ooox2o/ooox3/oox-3/2-1-x1/3-oxo/3xx1x/o2xxox o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +2x1xxx/2ooxxx/2-o-oo/5oo/2-1-oo/4ooo/o4xx o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-3-o/o-xx1-1/ox-x-2/ooo-o2/oo-o-x1/o-xxo-x/o-xxo-x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oxooooo/xxooooo/1o-x-1x/3xx2/2-1-2/7/o5x o 1 18 +7/7/2oxxx1/oxxxxx1/xxx1xxx/xx1oooo/x4oo o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-xx1-1/1-xxo-x/xx-1-xx/xxx-xxo/xx-x-xo/x-2x-o/o-3-o o 1 18 +1-3-o/1-oo1-o/xx-x-xo/xxx-xxo/xx-x-xo/1-o2-o/1-3-x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooo-3/oo-o-2/x-xxx-1/xx-x-2/xxx-3/xoxx2x o 0 18 +7/xxx1oxx/xxx-oxx/oo-1-xx/oo1-oxx/4xx1/5xx o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +6o/7/o6/x3xoo/xx2xoo/1xxooox/oooooxx o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +ooox2o/xoooxxo/xoo-1xx/xo-1-xx/oo1-1xx/oo5/o6 o 0 18 +1-3-1/x-1xx-1/xx-x-xo/ooo-xoo/oo-x-ox/x-o1x-x/1-3-x o 2 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xx3xx/5xx/2-1-oo/3x1oo/2-x-oo/2xxooo/o2xo1o o 3 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +6o/oo5/oo-1-2/xxxx3/xx-x-x1/o1oooxx/xxxxxxx o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x2xxxo/2oooxo/2ooo1x/2ooxx1/2xxxx1/7/o5x o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +ooooxoo/ooo-ooo/xo-o-xx/1-2o-x/2-1-x1/3-1xx/o4x1 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xo5/1xxoo2/1xxooo1/1xxooo1/2oooo1/1xxoxo1/xx5 o 0 18 +o-3-o/x-x2-1/xx-x-1o/xxo-o2/oo-o-2/x-ooo-1/1-xoo-1 o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1x4o/xxx4/xo-1-2/xoo4/xo-o-2/xxxxx2/xxx1xx1 o 1 18 +xoo3o/xx1-2o/xo-1-2/x-xx1-1/1o-x-2/xxx-o2/oxxxo2 o 2 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +2oxxxx/3xxxo/3-xxx/oo-1-xx/xxo-3/xxx4/6x o 0 18 +1-3-o/1-3-1/oo-1-oo/ooo-1xx/oo-x-xx/o-xxx-1/1-oox-1 o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xxxxx1/xxxxxx1/1xx-x2/oo-1-2/oo1-3/xx5/x5x o 0 18 +xxxxxxx/xxx-1xo/xo-x-xo/1-xxx-o/2-1-2/3-3/o4xx o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x6/xx5/xx1-2o/xx-1-xo/xxx-xxo/xooxxx1/2oox2 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x-x2-1/1-xxo-o/oo-o-oo/ooo-ooo/oo-x-oo/1-3-1/1-3-1 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1o1xooo/xxoxoxx/xx-o-xx/4oxx/2-1-ox/7/o5o o 1 18 +x-xx1-o/o-xx1-1/oo-o-2/ooo-xx1/oo-o-xx/o-xoo-1/1-xoo-1 o 0 18 +x5o/7/2ooo2/xxooox1/oooxxx1/ooxxx2/7 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xx4o/6o/2-1-2/xxxx3/xx-x-x1/ooooo1x/xooooo1 o 1 18 +3ooox/1xxoxx1/2-x-o1/3oxoo/2-o-xx/2xoxxx/3oxxx o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xoxx2o/oooxx2/ooooo2/xxxxx2/xxxoo2/3o3/6x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x-3-o/x-3-x/xx-1-xx/oxx-ooo/ox-x-xx/1-ooo-x/1-oo1-1 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xxoxox/xxxoxoo/oo1-xoo/2-x-oo/3-ooo/5o1/o6 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +ooox2o/oxxx3/xxx-3/oo-1-2/ooo-3/xxox3/xx1x2x o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x3xxo/5oo/2-1-xx/3oxxx/2-o-xx/o2oooo/o2xxox o 3 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1x5/oxx-1xx/ox-1-xx/1-2o-o/o1-x-oo/3-ooo/o2oooo o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x-3-o/o-3-o/ox-1-o1/ox1-xoo/xx-1-x1/x-oxx-o/1-oxx-o o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-ooo-1/o-ooo-x/xx-o-oo/1xx-ooo/1x-1-oo/x-3-o/o-3-x o 0 18 +1-3-o/o-3-1/oo-o-2/xoo-xxx/xo-x-xx/x-xxx-x/o-xxx-1 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-xxx-o/x-xxx-1/xx-x-x1/xxx-xxx/oo-x-2/o-o2-1/1-3-x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x3xxx/1x2xxx/2-o-xx/4oxx/2-1-xx/4oxx/o3oxx o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-ooo-1/1-oox-x/xx-o-xx/xxx-x1x/xo-1-xx/o-3-x/o-3-o o 1 18 +x-3-o/x-x2-1/oo-o-2/oox-o2/xx-x-2/x-xxx-1/x-xxx-1 o 0 18 +3xxxx/2xxoxx/3-xxx/2-1-oo/3-ooo/3ooxx/o2ooxx o 1 18 +x5o/7/2xx3/1xxxo2/oxxxxo1/xxxxxx1/1xooo2 o 0 18 +1oxxoxx/xooooxx/xxx-oxx/1x-1-oo/3-3/1o5/oo4x o 0 18 +ooo3x/ooo-1xx/xx-x-xx/1-o1o-x/oo-1-xx/1o1-1xx/6x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +6o/xx1-3/xx-o-2/o-1oo-1/xx-o-x1/oox-o2/xxxx3 o 2 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +2xxoxx/1xxxoxx/1xxxxxx/2oxxox/3oxo1/7/o6 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x6/4ooo/3xxoo/3xxxx/3xxxx/2ooxxx/o2oxxx o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xx3xx/5xx/4xxx/3o1xx/2xxxoo/1xxxoxx/4xoo o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-xxx-1/o-oxx-o/oo-x-xo/ooo-xxx/oo-x-xx/x-3-x/o-3-x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xx2xxx/x4xo/2-1-xx/5xx/2-o-x1/2o1xx1/3oxxx o 2 18 +x2ooxo/3oxxx/3ooox/3xxxx/3oxxx/3oxx1/o6 o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oo4o/oxx4/xxx-3/xx-1-2/xxx-3/xoooxx1/xoooxxx o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +2oxxxo/2oxxxo/2-o-xx/4ooo/2-x-xx/o3xxx/o6 o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxxx2o/o1xx3/xxo-3/xx-1-1o/3-1oo/2ooooo/o1oo1oo o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +ooxxxxx/oox-xxx/ox-x-x1/1-2x-x/2-1-x1/2x-3/2xx2x o 1 18 +x-3-1/o-3-x/oo-x-xx/oox-xxx/xo-o-xx/x-xxx-o/1-1x1-x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-3-1/1-3-1/xo-x-oo/xox-ooo/xo-x-1o/x-oxx-o/1-1xx-1 o 1 18 +6o/6o/o6/xx1oo2/oxxxox1/oxxx1oo/oxxxooo o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xx2xxo/3-xxo/2-1-xx/1-1oo-x/2-o-ox/1xo-oox/xxx1oox o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxxxxoo/xxxx1xx/xx-x-xx/oxoo3/ox-1-2/o6/5xx o 0 18 +o-1oo-1/o-xxx-1/oo-x-oo/oox-xoo/ox-x-xx/x-x2-o/o-3-x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1o2xx1/o2-xxx/2-1-ox/1-x2-o/2-o-oo/o2-oox/o3oox o 0 18 +5xx/5ox/1xxxx2/ooxxx2/oooxo2/oooxx2/xxxxo2 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xx5/xx5/5xx/xxx2xx/xxxx3/xxxx1xx/ooxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-xx1-1/1-xxo-1/1x-x-oo/xx1-xoo/ox-x-xx/o-x2-x/o-3-x o 2 18 +1-1x1-1/o-xxx-1/oo-o-1x/xxx-oox/xx-x-xx/x-xxx-x/1-xx1-1 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x-3-o/o-3-1/oo-x-oo/1o1-ooo/2-x-oo/1-xxo-x/o-1xo-x o 3 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-1oo-1/o-xox-x/oo-x-xx/oox-xxx/oo-x-oo/x-3-x/o-3-x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xx4o/oox-2o/oo-x-x1/1-1xx-1/2-x-xx/3-oxx/o2oooo o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x5x/4xxo/3xxxx/2ooxxx/3oxxx/4oxx/o6 o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xoo1xx1/xxo-oxx/xx-x-2/x-3-1/oo-1-2/oxx-o2/oxxxo2 o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oooxx1o/ooo1xxo/oo-1-xo/6o/2-1-xx/1o5/o1o4 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +2xoxxx/1xoxxxo/2oxxxo/3xxxo/4xoo/7/o4xx o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xxoooo/1xxooxx/2-o-ox/4oox/2-1-xx/2o2x1/oo4x o 0 18 +x-3-x/x-3-x/xo-1-xx/xxx-1oo/xx-x-o1/x-xxo-1/1-xxo-o o 3 18 +xxx3o/xxx-3/xx-x-2/o-ooo-1/2-o-xx/3-oxx/o2ooox o 0 18 +x5o/3-3/2-1-2/x-1oo-1/xx-x-xx/xxo-xxx/xooxxxx o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oooo2o/xxxo3/xx-o-2/xxxo3/xx-1-2/xxx4/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x5x/x3oox/2-1-xx/5xx/2-o-xx/2xxxxx/2xxxoo o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x2xooo/3xxxo/3xxxo/3xxxo/3xxxo/7/o6 o 0 18 +2xxoo1/2xooox/2xooo1/2oo1x1/3oxx1/o3xx1/o4x1 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-xxx-1/o-oxx-o/oo-x-xo/ooo-xxx/oo-x-xx/o-3-x/o-3-x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xooooxx/oooooxx/ox-o-ox/oxx4/ox-1-2/oo5/6x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +ooooxxo/ooooxxo/xoo-xxx/xx-1-xx/3-3/xx5/x5x o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-3-1/o-3-1/xx-1-2/xxx-oox/xx-x-o1/x-xxx-x/1-1x1-1 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x-xoo-o/x-xoo-1/xx-x-x1/xoo-xx1/xo-1-2/x-o2-1/1-3-x o 1 18 +xxooooo/xxo-oxx/xx-o-o1/x-xxx-1/2-x-2/3-3/o4oo o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x5o/7/2xx3/1xxxox1/xoooxx1/oooooo1/xoooo2 o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oooo2o/ooxx3/oox-3/oo-x-2/oox-3/xxo3x/1x3xx o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-3-1/x-xx1-1/oo-x-1x/ooo-xxx/oo-1-xx/o-3-x/1-3-x o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-3-x/o-xxx-x/oo-x-oo/xoo-xoo/oo-o-xx/1-2x-x/1-3-x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oxxxxx1/oxxxoo1/oxx-o2/xx-1-2/ooo-3/ooox3/ooo3x o 0 18 +6o/1oo4/oxxx3/xxxxx2/oxxxo2/oooxx2/xxxo3 o 0 18 +1-xxo-1/1-xxo-1/xx-1-xo/xxo-xxo/ox-1-xo/o-3-x/1-3-x o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xoxoxxx/xoo-xx1/xx-1-xo/1-2x-o/2-1-xo/3-xxx/oo3xx o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xx4o/xxx3o/xxx-3/oo-1-2/1oo-oxx/2oxxxx/3xx2 o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x6/7/2-1-oo/2ooooo/xx-o-xx/xxoxxxx/1xxoxxx o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +7/7/xxooo2/xxxxxo1/xxxoooo/ooxoooo/xx4x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xx5/6o/3-1xx/2-1-xx/1xx-xxx/xxxoxxo/2xxooo o 2 18 +oooxxxx/oox-xxo/o1-o-oo/1-xxx-o/2-x-2/3-3/o5x o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x4x1/2xxxxx/2xxoox/2ooooo/3xoo1/7/oo5 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +ooxxx2/oooxx2/oo-x-2/ooxx3/xx-x-2/x1x4/xo4x o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xo4o/xoo3o/xxo-3/xx-x-2/xxx-3/oxxxo2/oooo2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +o-1oo-1/o-xxx-o/1x-x-oo/xx1-xxx/xx-1-oo/1-3-x/o-3-x o 2 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xoxooxx/xxxooxx/ooo-ox1/xx-o-2/xxo-3/1xx4/6x o 0 18 +x3ooo/3oxxx/2-o-xx/4xxx/2-1-ox/3xxxx/4xxx o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +ooxoo2/oxxoo2/oxx-3/1x-1-2/xxx-3/1xx4/6x o 2 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +o5o/oo3o1/xxx-3/xx-1-2/xxx-3/oo1xx2/oooxxxx o 2 18 +oo3oo/oox-3/oo-x-2/o-x2-1/ox-1-2/ooo-1xx/ooox2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xox3o/xoxx2o/xo-x-2/xxo1x2/xo-x-2/xoxx3/ooo3x o 1 18 +xoo3o/xxo4/xxx-3/xx-1-2/xxx-3/xxxo3/xooo2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oxoxxxx/oxoooxx/ox-o-xx/7/2-1-2/1ooo3/ooooo2 o 0 18 +x6/3xxo1/3xxox/3oo1x/3xxxx/o2xxxo/o2ooxo o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xxxxoo/1xxxxxx/2-o-xx/4ooo/2-1-oo/5oo/o4xx o 0 18 +1-3-1/1-3-x/x1-x-xx/xxx-oxx/xx-o-oo/1-3-o/1-3-1 o 0 18 +x3xxx/4xxx/2-o-xo/4oxo/2-x-xx/2ooxxx/2ooxxx o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oxx2xo/xxx-xxx/xo-o-ox/1-xoo-x/2-o-oo/3-3/o6 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xxxoxx/oxxxoxx/1oxo1xx/1xooxxx/3o3/7/o4xx o 2 18 +oooo3/xxoox2/xxooox1/xxoxx2/1xoxx2/7/o6 o 1 18 +x3xoo/3-1oo/2-1-oo/1-x2-o/ox-1-1o/ooo-ooo/xooooo1 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xoooo1x/ooo-oxx/oo-o-xx/o-xx1-1/xx-1-2/3-3/6x o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-3-1/o-3-x/2-1-x1/oxx-xxo/ox-x-xo/o-1oo-o/1-1oo-x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oxxxxx1/oxx-xxx/xx-x-xx/1-oo1-1/2-1-2/o2-1x1/oo3xx o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x6/7/2-1-1x/xx3xx/xx-o-xx/xxooooo/xxoooxx o 0 18 +xoooxxo/xxx-xxx/1x-x-xx/1-1oo-1/2-1-2/3-3/o5x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x3oxo/1x1oooo/2-1-xx/5xx/2-1-xx/3oxxx/o2oxxx o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xoxxx2/ooxxx2/oo-x-2/oo1oo2/ox-x-2/oxx4/5xx o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x3xxo/4xxo/3-xx1/2-o-xx/1xx-xxx/xxxoooo/1xxxxoo o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxxoooo/xx1ooo1/xx-x-2/ooxx3/oo-1-2/o5x/6x o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-3-o/x-3-1/xx-x-oo/oo1-ooo/xo-x-oo/x-ooo-o/1-xxx-1 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoooox/1xoooox/2-x-oo/4ooo/2-1-xo/4xxo/o6 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x2xxoo/3oooo/3-xoo/2-1-oo/3-1oo/3oxxx/o2oxxx o 3 18 +1-ooo-1/o-ooo-1/oo-x-x1/ooo-xx1/oo-o-2/o-o2-x/o-3-x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +o-3-1/x-3-1/xx-o-oo/xxx-ooo/ox-o-oo/x-oxx-o/o-xxx-x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxxxo2/xxx-3/xx-1-2/x-o2-1/xo-1-2/oox-1xx/oox3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x3xxx/3-xxo/2-1-xo/1-2o-o/1o-o-ox/oox-xoo/1xxxxox o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +ooxooo1/xx1xoo1/xxo-xxx/2-1-xx/3-1xx/1o5/o6 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx4/xxx4/3-2x/1o-1-xx/ooo-xxx/xxxxooo/ooxxxxo o 2 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x2xooo/3xxxo/3xxxo/3xxxx/2ooxox/3oxox/o3xoo o 0 18 +oooooox/ooo-oo1/ox-o-xx/o-3-x/2-1-2/3-2x/2xxxxx o 1 18 +xxoooox/xxoooox/1x-o-ox/xxo4/xx-1-2/7/o5x o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxxo2o/xxxo3/xxo-3/oo-o-2/oox-3/xxxx1x1/xxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1ooxxxx/oooxooo/1ox-xoo/2-x-oo/3-xxo/o6/o6 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxxxooo/xxx-xxx/xx-x-xx/1-2x-x/2-1-oo/3-3/o5x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +ooooxxx/1oo-xxx/2-1-x1/1-3-x/2-1-ox/3-xx1/o3xx1 o 1 18 +x1xx3/3xx2/3-3/xx-1-x1/xxx-xxx/xxxxxoo/ooxxxoo o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +7/7/x3xo1/xooxxoo/xoooooo/1ooxxxx/x3xxx o 0 18 +xx4o/3-xxo/2-1-xo/x-3-x/xx-x-oo/ooo-ooo/xxoxxoo o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x3xxo/3-xxo/2-x-xo/1-xxo-o/2-x-oo/2x-ooo/2xoooo o 0 18 +x3o2/3oxx1/2xxx2/1xooo2/oxxx3/oxxx3/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x5o/x3xxo/4xx1/4oox/3xxxx/2ooooo/2ooooo o 1 18 +xoxxx2/xxxx3/x1o4/xxx4/xxo4/xxx4/xo4x o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x-xxo-1/x-xxo-1/xo-o-2/ooo-x2/oo-o-2/o-oox-1/1-ooo-x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xooxx2/xooxx2/ox-x-2/xxo4/oo-1-2/ooox3/ooox2x o 0 18 +ooxxoo1/xx1xoo1/xo-x-2/xoxx3/xo-1-2/x6/x5x o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x2oxxx/4ooo/3xoxx/2xxox1/3xox1/o3xx1/o5o o 1 18 +1xx2oo/oxx3o/oo-1-2/oxx4/xx-1-2/xoooxo1/xooooo1 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x3oxx/4oxx/2-x-xx/3xxoo/2-o-ox/2xooox/2xooox o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oxxxooo/ooxxooo/xxx-ooo/1x-1-xx/3-3/7/oo3xx o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x4x1/xx3xx/x1-1-1o/4xxx/2-o-xx/2ooooo/3oooo o 2 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +7/3oxx1/2xxxx1/2x1oo1/2xxxx1/2xxo2/o6 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xoo1oox/xoo-1ox/2-1-xx/1-3-o/2-1-x1/2x-oxx/ooxx1xx o 1 18 +x-1o1-o/o-xox-x/oo-o-ox/oox-xxx/xx-o-xx/x-3-x/x-3-1 o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +x6/7/2-1-oo/3xxoo/xx-x-xx/x1xoooo/xooxooo o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +ooxoooo/oxxxooo/1xx-ooo/2-x-ox/3-3/o6/o5x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +x5o/7/2-1-2/2xxoxx/ox-x-xx/oooooo1/ooooooo o 2 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xoooooo/ooooo2/ox-x-2/oxx4/1x-1-2/xoo4/xoo3x o 0 18 +xxoooox/xxxxoxx/ooo-oxx/oo-1-2/3-3/7/o5x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +6o/xx5/xx-1-2/xx2o2/xx-x-ox/oxxxxoo/oxxxooo o 2 18 +xxxxxxo/oxx-oxo/oo-1-oo/x-3-1/xx-1-2/1x1-3/xxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +5oo/7/1o1-3/oo-x-xx/oox-xox/x1ooooo/xxoooox o 1 18 +x-xoo-1/1-xox-x/2-o-xx/3-xxx/2-o-oo/1-xxo-o/o-xx1-o o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +x-2x-1/1-xxx-x/2-x-oo/3-ooo/2-x-oo/1-oox-x/1-ooo-x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxo2oo/xxo-3/xx-1-2/x-o2-1/xx-1-2/xxx-1xx/xoo2xx o 2 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +7/7/oxx-1xx/xo-1-xx/ooo-xox/xooooox/xoxooox o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +6o/xxox1xo/xxoxx2/ooox3/ooox3/oxxx2x/oxoo2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-3-x/1-3-o/2-1-xo/oxo-1xo/ox-o-1x/o-xxo-x/o-xxx-1 o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-2x-1/1-xxx-o/xo-x-oo/xxx-ooo/oo-1-xx/1-3-o/1-3-x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-3-o/x-o2-x/xx-o-xx/xxx-xxx/xx-o-xx/x-o2-x/x-3-1 o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxx3o/oxxxx2/ox1xx2/oooxx2/oooxx2/3xx2/5x1 o 1 18 +xooo2o/xooo3/oox-3/oo-x-2/xx1-3/xxoxx2/xxox2x o 1 18 +1-xxx-o/x-xxx-x/xo-x-xo/xoo-xxo/xx-x-2/x-x2-1/1-3-x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1-3-1/1-2o-1/xx-o-ox/xxx-xxx/oo-x-xx/o-xxx-x/o-oo1-x o 0 18 +xxoo3/xxxo3/xxx-3/xx-1-2/oxo-3/xxxo3/xxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1-1x1-x/1-xxx-x/xx-x-oo/xxx-xxo/xx-1-xx/o-3-x/1-3-x o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +3xoxx/xxoooxx/xxo-oxx/xo-1-2/xx1-3/x5x/6x o 1 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxxx2o/xxxx3/xxxo3/xxoo3/ooxx3/oxxx3/1xx3x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +x-3-o/x-3-o/xo-1-xo/oox-xxx/oo-o-xx/1-xxo-1/1-xxo-1 o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +xxooxxo/xxxxxxx/oxx-xxo/ox-1-oo/3-3/6x/o5x o 0 18 +6o/xx1x3/xxox3/ooox3/oooo3/xoo4/xx4x o 1 18 +xxxx2o/ooxoo2/xx1x3/xxxx3/1xo4/1ooo3/o1oox2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1xxoooo/1xooooo/2-x-xx/3xxox/2-1-xx/1o2x1x/o5x o 1 18 +2oooxo/2xxooo/2oxxxx/2oxxxx/4xxx/4oo1/oo5 o 0 18 +o1o3o/ooo3o/oo-1-2/xxx4/x1-1-2/xxxxxo1/xxxxxo1 o 3 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxo3o/xxxo3/xx-o-2/xx5/oo-x-2/xxoxx1x/xxox2x o 1 18 +1ooooxx/xooxxxx/oxx-xxx/oo-1-xo/3-1oo/7/o6 o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +xxxx3/1ooxx2/1ooo3/1oxoo2/1x1xx2/xxxxx2/xxxx2x o 2 18 +6o/7/1oxx3/ooxxo2/oooxoo1/ooxxx2/ooxxx2 o 0 18 +oooxxxo/ooooxxx/oo-o-x1/xxoo3/1x-1-2/7/6x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxx2ox/xxxxxx1/x1ooo2/xxoo3/1xo4/7/5xx o 1 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1-x2-o/1-1x1-o/x1-1-2/xx1-3/xx-1-oo/1-oxx-o/1-xxx-x o 4 18 +xxoxxxx/ooo-xxx/oo-o-x1/x-o2-1/xo-1-2/xxx-2x/oxxx2x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +x3ooo/x3ooo/3xooo/3xooo/2xxoxx/2xxxox/3oxoo o 0 18 +1oooo1o/oxxxo2/oxx-3/xx-1-2/oox-3/xxxx2x/ooo3x o 0 18 +oox3o/ooxx2o/ooxx3/ooxx3/xxxx3/xxxoo1x/oxx3x o 0 18 +1xx3x/1x3xx/xx-x-2/xxxx3/oo-o-2/ooooo1x/ooooo2 o 1 18 +xx2oox/xx1-oo1/xx-1-2/x-3-1/xx-1-2/ooo-x2/xxoxxxx o 0 18 diff --git a/hsm.py b/hsm.py new file mode 100644 index 0000000..1cd8c1a --- /dev/null +++ b/hsm.py @@ -0,0 +1,344 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +from torch.distributions import Categorical + +import gym +from gym import spaces +import numpy as np +import ataxx +from tqdm import tqdm + +import ataxx.players +import matplotlib.pyplot as plt + + +def default_eval(board: ataxx.Board): + black, white, _, _ = board.count() + if board.turn == ataxx.BLACK: + return black - white + else: + return white - black + +class AtaxxEnv(gym.Env): + def __init__(self, board_dim=7, opponent='alphabeta', depth=2, eval_fn=default_eval, board=None): + super(AtaxxEnv, self).__init__() + + # Initialize the Ataxx Board + self.board_dim = board_dim + self.board = ataxx.Board(board_dim=board_dim) if not board else board + self.opponent = opponent + self.depth = depth + self.eval_fn = eval_fn if eval_fn is not default_eval else default_eval # default evaluation function + + # Define the action space and observation space + # Actions: flatten the 7x7 grid to a 49-dimensional space (or any number depending on board_dim) + self.action_space = spaces.Discrete(board_dim * board_dim) # Example: 49 actions (7x7 grid) + self.observation_space = spaces.Box(low=0, high=1, shape=(board_dim, board_dim), dtype=np.float32) + + def sample_action(self, action_index): + from_row = action_index // (self.board_dim * self.board_dim) + from_col = (action_index % (self.board_dim * self.board_dim)) // self.board_dim + to_row = (action_index % self.board_dim) // self.board_dim + to_col = action_index % self.board_dim + move = ataxx.Move(from_col, from_row, to_col, to_row) + return move + + def reset(self): + """Resets the environment to the initial state.""" + self.board = ataxx.Board(board_dim=self.board_dim) # Reset the Ataxx board + return np.array([row[2:-2] for row in self.board._board[2:-2]]) # Return the board state as a numpy array + + def step(self, action): + """Takes an action and returns the next state, reward, done, and additional info.""" + # Decode the action from the action space (convert index to row, col) + move = self.sample_action(action) + + done = self.board.gameover() + + # Make the move + if self.board.is_legal(move): + self.board.makemove(move) + elif not done: + # Invalid action, immediate negative reward + move = np.random.choice(self.board.legal_moves()) + + # Get the reward + if done: + if self.board.result() == '1-0': # Example: Player X wins + reward = 1 + elif self.board.result() == '0-1': # Example: Player O wins + reward = -1 + else: + reward = 0 # Draw + else: + reward = 0.1 # Reward some exploration + + # If the game is not over, the opponent takes a turn + opponent_move = self.get_opponent_move() + if not done and opponent_move: + self.board.makemove(opponent_move) + + # Return the new state, reward, done flag, and info + return np.array([row[2:-2] for row in self.board._board[2:-2]]), reward, done, {} + + def get_opponent_move(self): + """Get the move for the opponent (random).""" + return ataxx.players.negamax(self.board, 2) + + def render(self, mode='human'): + """Render the environment (print the board to the console).""" + print(self.board) + + def close(self): + """Clean up the environment (if necessary).""" + pass + +class HierarchicalSoftmaxNet(nn.Module): + def __init__(self, board_size=7, num_categories=2, num_subcategories=4, num_actions=49): + super(HierarchicalSoftmaxNet, self).__init__() + self.fc1 = nn.Linear(board_size * board_size, 256) # Flatten the board + self.fc2 = nn.Linear(256, 128) + self.fc3 = nn.Linear(128, 64) + + # Hierarchical softmax output layers + self.level1 = nn.Linear(64, num_categories) # Categories (e.g., offensive, defensive) + self.level2 = nn.Linear(64, num_subcategories) # Sub-categories + self.level3 = nn.Linear(64, num_actions) # Final actions (e.g., specific move) + + # Value function head (for value loss) + self.value_head = nn.Linear(64, 1) + + def forward(self, state): + x = torch.relu(self.fc1(state)) + x = torch.relu(self.fc2(x)) + x = torch.relu(self.fc3(x)) + + # Output for hierarchical softmax (Level 1: Categories, Level 2: Subcategories, Level 3: Actions) + level1_probs = torch.softmax(self.level1(x), dim=-1) + level2_probs = torch.softmax(self.level2(x), dim=-1) + level3_probs = torch.softmax(self.level3(x), dim=-1) + + # Output for value function + value = self.value_head(x) + + return level1_probs, level2_probs, level3_probs, value + +def ppo_loss(old_log_probs, log_probs, advantages, values, returns, clip_epsilon=0.2, value_loss_coef=0.5, entropy_coef=0.01): + """ + Compute the PPO loss for the current policy. + + Parameters: + - old_log_probs: The log probabilities from the old policy (before update). + - log_probs: The log probabilities from the new policy (after update). + - advantages: The advantage estimates for each state-action pair. + - values: The state value estimates from the current policy network. + - returns: The target returns (i.e., the Monte Carlo returns or TD returns). + - clip_epsilon: The clipping parameter (usually 0.2). + - value_loss_coef: Coefficient for the value loss. + - entropy_coef: Coefficient for the entropy term (encourages exploration). + + Returns: + - Total loss, including the policy loss, value loss, and entropy loss. + """ + + # Compute the ratio (r_t) + ratios = torch.exp(log_probs - old_log_probs) + + # Compute the clipped surrogate loss (Policy loss) + surrogate_loss = torch.min(ratios * advantages, torch.clamp(ratios, 1 - clip_epsilon, 1 + clip_epsilon) * advantages) + + # Value loss (Mean Squared Error between value predictions and targets) + value_loss = (values - returns).pow(2) + + # Entropy loss (encourages exploration by penalizing low entropy in the policy distribution) + entropy_loss = -torch.mean(torch.exp(log_probs) * log_probs) + + # Combine the losses + total_loss = -torch.mean(surrogate_loss) + value_loss_coef * value_loss + entropy_coef * entropy_loss + + return total_loss + +def compute_gae(rewards, values, next_values, done_flags, gamma=0.99, lam=0.95): + """ + Compute the Generalized Advantage Estimation (GAE). + + Arguments: + - rewards: List or array of rewards at each time step + - values: List or array of state values (from the value head) at each time step + - next_values: List or array of next state values + - done_flags: List or array of boolean values indicating whether the episode has ended + - gamma: Discount factor + - lam: GAE lambda factor + + Returns: + - advantages: Computed advantages at each time step + - returns: Computed returns (value + advantage) + """ + advantages = torch.zeros_like(rewards) + returns = torch.zeros_like(rewards) + + last_gae_lambda = 0 + for t in reversed(range(len(rewards))): + if done_flags[t]: + next_value = 0 # No next state if done + else: + next_value = next_values[t] + + # Compute temporal difference error (delta_t) + delta = rewards[t] + gamma * next_value - values[t] + + # Compute GAE advantage + advantages[t] = delta + gamma * lam * last_gae_lambda + returns[t] = advantages[t] + values[t] + + # Update the last GAE lambda + last_gae_lambda = advantages[t] + + return advantages, returns + +def train_step(state, action, reward, next_state, done, model, old_log_probs, optimizer, gamma=0.99, lam=0.95): + """ + Perform one training step (forward pass, backward pass) using PPO with GAE. + """ + + # Convert state and next state to tensors + state_tensor = torch.tensor(state, dtype=torch.float32).flatten().unsqueeze(0) + next_state_tensor = torch.tensor(next_state, dtype=torch.float32).flatten().unsqueeze(0) + + # Get the new log probabilities and values from the model + level1_probs, level2_probs, level3_probs, values = model(state_tensor) + dist1 = Categorical(level1_probs) + dist2 = Categorical(level2_probs) + dist3 = Categorical(level3_probs) + + # Sample actions from the distributions + action1 = dist1.sample() + action2 = dist2.sample() + action3 = dist3.sample() + + # Combine actions from the hierarchy + action = action3.item() # Use the final action from level3 + + # Compute new log probabilities for PPO update + new_log_probs = dist1.log_prob(action1) + dist2.log_prob(action2) + dist3.log_prob(action3) + + # Collect reward, value, and done information for the current timestep + rewards = torch.tensor([reward], dtype=torch.float32) + values = values.detach().squeeze(0) + + # Get the next value (could be zero if done) + next_values = model(torch.tensor(next_state, dtype=torch.float32).flatten().unsqueeze(0))[3].detach().squeeze(0) + + # GAE computation + advantages, returns = compute_gae(rewards, values, next_values, done_flags=[done], gamma=gamma, lam=lam) + + # Compute the advantage (simplified as scalar for now) + advantage = advantages[0] + return_value = returns[0] + + # Calculate PPO loss + loss = ppo_loss(old_log_probs, new_log_probs, advantage, values, return_value) + + # Backpropagate and update the model parameters + optimizer.zero_grad() + loss.backward() + optimizer.step() + + return loss # Return the loss for logging purposes + +def get_agent(bs=7): + # Initialize model and optimizer + model = HierarchicalSoftmaxNet(board_size=bs, num_categories=2, num_subcategories=4, num_actions=bs*bs) + optimizer = optim.Adam(model.parameters(), lr=0.001) + env = AtaxxEnv() + + # Simulated training loop + num_episodes = 10 + losses = [] + for episode in tqdm(range(num_episodes)): + state = env.reset() # Reset the environment + done = False + total_reward = 0 + + while not done: + # Convert state to tensor + state_tensor = torch.tensor(state, dtype=torch.float32).flatten().unsqueeze(0) + + # Get probabilities from the model + level1_probs, level2_probs, level3_probs, value = model(state_tensor) + + # Select actions using the probabilities from each level + dist1 = Categorical(level1_probs) + dist2 = Categorical(level2_probs) + dist3 = Categorical(level3_probs) + + action1 = dist1.sample() + action2 = dist2.sample() + action3 = dist3.sample() + + # Combine the actions into a single action for the environment + action = action3.item() + + # Store the old log probabilities for PPO update + old_log_probs = dist1.log_prob(action1) + dist2.log_prob(action2) + dist3.log_prob(action3) + + # Take action in the environment + next_state, reward, done, _ = env.step(action) + + # Train the model using PPO + loss = train_step(state, action, reward, next_state, done, model, old_log_probs, optimizer) + + total_reward += reward + state = next_state + losses.append(loss.item()) + print(env.board) + # print(f"Episode {episode + 1}, Total Reward: {total_reward}") + plt.figure(figsize=(10, 5)) + plt.plot(losses, label='PPO Loss', color='blue') + plt.xlabel('Training Steps') + plt.ylabel('Loss') + plt.title('Training Loss Over Time') + plt.legend() + plt.show() + + return model + +def generate_move(model, board, board_size=7): + """ + Generate a move using a trained hierarchical softmax model. + + Parameters: + - model: The trained PyTorch model. + - board: The current board. + - board_size: The size of the board (default is 7 for Ataxx). + + Returns: + - move: The move selected by the model. + """ + env = AtaxxEnv(board_dim=board_size, board=board) + + # Ensure the board state is a PyTorch tensor and flattened + board_state = np.array([row[2:-2] for row in board._board[2:-2]]) + state_tensor = torch.tensor(board_state, dtype=torch.float32).flatten().unsqueeze(0) + + # Get action probabilities from the model + level1_probs, level2_probs, level3_probs, loss = model(state_tensor) + + # Sample the action from the categorical distributions (one per level) + dist1 = torch.distributions.Categorical(level1_probs) + dist2 = torch.distributions.Categorical(level2_probs) + dist3 = torch.distributions.Categorical(level3_probs) + + action1 = dist1.sample() # Sample from the first level (category) + action2 = dist2.sample() # Sample from the second level (subcategory) + action3 = dist3.sample() # Sample from the third level (specific move) + + # Now, we need to combine action2 and action3 to form a valid board position + # Assuming action2 is a row index, and action3 is a column index, or any other encoding you want to use + move = env.sample_action(action3.item()) + if not board.is_legal(move): + move = np.random.choice(board.legal_moves()) + + return move diff --git a/learn_ataax.py b/learn_ataax.py index b2b749d..07d7791 100644 --- a/learn_ataax.py +++ b/learn_ataax.py @@ -1,9 +1,52 @@ import ataxx import sys import ataxx.players +import numpy as np +from ataxx import FEN_4CORNERS, FEN_4SIDES, FEN_CENTERX, FEN_EMPTY, FEN_ISLAND, FEN_STARTPOS +from tqdm import tqdm +import hsm BLACK, WHITE, GAP, EMPTY = 0, 1, 2, 3 +N_MOVES_EXAMPLE = 35 +POSSIBLE_BOARDS = [FEN_4CORNERS, FEN_4SIDES, FEN_CENTERX, FEN_EMPTY, FEN_ISLAND, FEN_STARTPOS] +PLAYER_TYPES = [ataxx.players.alphabeta, ataxx.players.greedy, ataxx.players.negamax] +N_TRAINING_EXAMPLES = 1000 +TRAIN_DEPTH = 2 + +def load_end_data(): + with open("endgame.txt", "r") as datafile: + data = datafile.readlines() + for fen in data: + fen = fen.strip() + board = ataxx.Board(fen) + print(board) + +def gen_end_examples(): + with open("endgame.txt", 'w+') as outfile: + for i in tqdm(range(N_TRAINING_EXAMPLES)): + board = ataxx.Board(np.random.choice(POSSIBLE_BOARDS)) + p1 = np.random.choice(PLAYER_TYPES) + p2 = np.random.choice(PLAYER_TYPES) + for m in range(N_MOVES_EXAMPLE): + for p in [p1, p2]: + if p == ataxx.players.alphabeta: + move = p(board, float('-inf'), float('inf'), TRAIN_DEPTH) + elif p == ataxx.players.negamax: + move = p(board, TRAIN_DEPTH) + elif p == ataxx.players.greedy: + move = p(board) + if board.gameover(): + break + board.makemove(move) + # print(board) + if board.gameover(): + # We went too far, retry generating + m -= 1 + else: + fen = board.get_fen() + outfile.write(fen + "\n") + def play_solo(): fen = input("FEN: ") board_dim = int(input("BOARD SIZE: ")) @@ -30,17 +73,120 @@ def play_solo(): print(F"Result: {board.result()}") -# T -def eval_function(board: ataxx.Board): - return 0 +def default_eval(board: ataxx.Board): + black, white, _, _ = board.count() + if board.turn == ataxx.BLACK: + return black - white + else: + return white - black + +""" +Evaluation function that favors pieces placed closer to the center of the board +""" +def weight_center_eval_function(board: ataxx.Board): + player = board.turn + points = default_eval(board) + # Define the center coordinates + center_x, center_y = (board.board_dim - 1) // 2, (board.board_dim - 1) // 2 + + # Iterate over the grid and calculate the Manhattan distance to the center + for i in range(board.board_dim): + for j in range(board.board_dim): + # Manhattan distance from the current cell (i, j) to the center + if board.get(i, j) == player: + distance = abs(i - center_x) + abs(j - center_y) + + # Assign points inversely proportional to the distance + # We can use the formula `points = max_points - distance` + # where max_points is the maximum possible distance, which is n-1 for the corners + max_distance = (board.board_dim - 1) * 2 + p = max(0, max_distance - distance) # Ensure no negative points + + points += p + return points + +""" +Evaluation function that discourages "L" and "U" shapes +""" +def keep_clustered_eval_function(board: ataxx.Board): + points = default_eval(board) + player = board.turn + + def find_l_shapes(board: ataxx.Board): + rows, cols = len(board), len(board[0]) + l_shapes = [] + + # Loop through the grid and check for L shapes + for i in range(1, board.board_dim - 1): + for j in range(1, board.board_dim - 1): + # Check for L shapes (both horizontal and vertical parts) + + # 1. L shape - bottom-left corner (┐) + if board[i][j] == 1 and board[i-1][j] == 1 and board[i][j-1] == 1: + l_shapes.append(((i, j), "┐")) + + # 2. L shape - top-left corner (└) + if board[i][j] == 1 and board[i-1][j] == 1 and board[i][j+1] == 1: + l_shapes.append(((i, j), "└")) + + # 3. L shape - top-right corner (┌) + if board[i][j] == 1 and board[i+1][j] == 1 and board[i][j-1] == 1: + l_shapes.append(((i, j), "┌")) + + # 4. L shape - bottom-right corner (┌) + if board[i][j] == 1 and board[i+1][j] == 1 and board[i][j+1] == 1: + l_shapes.append(((i, j), "└")) + + return l_shapes + + def find_u_shapes(board: ataxx.Board): + rows, cols = len(board), len(board[0]) + u_shapes = [] + + # Loop through the grid and check for U shapes + for i in range(1, board.board_dim - 1): + for j in range(1, board.board_dim - 1): + # Check for U shapes with different possible configurations. + + # 1. U shape - open top, with vertical sides + if board[i][j] == 1 and board[i][j-1] == 1 and board[i][j+1] == 1 and board[i-1][j] == 1: + u_shapes.append(((i, j), "U")) + + return u_shapes + + return points - 5 * len(find_l_shapes(board)) - 5 * len(find_u_shapes(board)) + +def play_hierarchical_softmax_agent(agent, depth=2, opponent='alphabeta', board="startpos", board_dim=7): + board = ataxx.Board(board, board_dim=board_dim) + turn_counter = 1 + + while not board.gameover(): + try: + if turn_counter % 2 == 1: + # Opponent goes first + if opponent == 'alphabeta': + move = ataxx.players.alphabeta(board, float('-inf'), float('inf'), depth) + else: + move = opponent(board) + else: + # Your Hierarchical Softmax agent's move + move = hsm.generate_move(agent, board) + if board.is_legal(move): + board.makemove(move) + else: + print(f"Illegal move: {move}") + except KeyboardInterrupt: + print("") + break + turn_counter += 1 + + print(f"Result: {board.result()}") + return board.result() + -def alphabeta(board, alpha, beta, depth, root=True): +def alphabeta(board, alpha, beta, depth, root=True, evalFn=default_eval): if depth == 0: - black, white, _, _ = board.count() - if board.turn == ataxx.BLACK: - return black - white - else: - return white - black + return evalFn(board) best_move = None @@ -64,7 +210,7 @@ def alphabeta(board, alpha, beta, depth, root=True): return alpha # Two alpha-beta players play against each other -def play_alphabeta(depth=2, opponent='alphabeta', board="startpos", board_dim=7): +def play_alphabeta(depth=2, opponent='alphabeta', board="startpos", board_dim=7, evalFn=default_eval): board = ataxx.Board(board, board_dim=board_dim) turn_counter = 1 @@ -77,7 +223,7 @@ def play_alphabeta(depth=2, opponent='alphabeta', board="startpos", board_dim=7) else: move = opponent(board) else: - move = alphabeta(board, float('-inf'), float('inf'), depth) + move = alphabeta(board, float('-inf'), float('inf'), depth, evalFn=evalFn) if board.is_legal(move): board.makemove(move) else: @@ -85,8 +231,6 @@ def play_alphabeta(depth=2, opponent='alphabeta', board="startpos", board_dim=7) except KeyboardInterrupt: print("") break - # print(board) - # next = input("NEXT:") turn_counter += 1 print(F"Result: {board.result()}") @@ -99,17 +243,33 @@ def main(): if len(sys.argv) == 0: print("Available modes: solo") mode = sys.argv[1] + if mode == 'make_data': + gen_end_examples() + if mode == 'read_data': + load_end_data() if mode == 'solo': play_solo() if mode == 'alphabeta': + # board = input("BOARD FEN: ") board_size = int(input("BOARD SIZE: ")) wincount = 0 - n_games = 1 + n_games = 100 for i in range(n_games): - result = play_alphabeta(opponent='alphabeta', board="island", board_dim=board_size) + result = play_alphabeta(opponent='alphabeta', board_dim=board_size, evalFn=keep_clustered_eval_function) if result == '1-0': wincount+=1 print(wincount / n_games) + if mode == 'hsm': + agent = hsm.get_agent() + board_size = 7 + wincount = 0 + n_games = 100 + for i in range(n_games): + result = play_hierarchical_softmax_agent(agent, opponent='alphabeta', board_dim=board_size) + if result == '1-0': + wincount+=1 + print(wincount / n_games) + From ffdd162ab1cbf2a9521fbe4a137f8241409d883a Mon Sep 17 00:00:00 2001 From: pabaill Date: Wed, 4 Dec 2024 14:17:10 -0800 Subject: [PATCH 5/7] MCTS and HSM2 --- P2_ONLY_random_state_agent.pth | Bin 0 -> 284534 bytes STABLE_random_state_agent.pth | Bin 0 -> 284534 bytes __pycache__/hsm.cpython-39.pyc | Bin 9656 -> 9642 bytes __pycache__/hsmv2.cpython-39.pyc | Bin 0 -> 6745 bytes __pycache__/mcts.cpython-39.pyc | Bin 0 -> 4484 bytes endgame_agent.pth | Bin 0 -> 284420 bytes hsm.py | 3 +- hsm_weights1.pth | Bin 0 -> 284410 bytes hsmv2.py | 294 +++++++++++++++++++++++++++++++ learn_ataax.py | 55 +++++- mcts.py | 168 ++++++++++++++++++ quiz3.ipynb | 267 ++++++++++++++++++++++++++++ random_state_agent.pth | Bin 0 -> 284534 bytes 13 files changed, 781 insertions(+), 6 deletions(-) create mode 100644 P2_ONLY_random_state_agent.pth create mode 100644 STABLE_random_state_agent.pth create mode 100644 __pycache__/hsmv2.cpython-39.pyc create mode 100644 __pycache__/mcts.cpython-39.pyc create mode 100644 endgame_agent.pth create mode 100644 hsm_weights1.pth create mode 100644 hsmv2.py create mode 100644 mcts.py create mode 100644 quiz3.ipynb create mode 100644 random_state_agent.pth diff --git a/P2_ONLY_random_state_agent.pth b/P2_ONLY_random_state_agent.pth new file mode 100644 index 0000000000000000000000000000000000000000..a4725d0f28b2f6b948082b1b87a128df51a6d7ae GIT binary patch literal 284534 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

&&h$dWogAdm$Sf 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