From 388260629132d623d3b6fca4dc41a9c3c6704846 Mon Sep 17 00:00:00 2001 From: Nikhil Henry <25770025+nikhilhenry@users.noreply.github.com> Date: Sat, 31 Aug 2024 20:19:30 +0530 Subject: [PATCH 1/5] update sprites --- assets/sprites/music_bg1.png | Bin 0 -> 425 bytes assets/sprites/music_bg2.png | Bin 0 -> 385 bytes assets/sprites/reset1.png | Bin 528 -> 526 bytes assets/sprites/reset2.png | Bin 484 -> 484 bytes assets/sprites/undo1.png | Bin 503 -> 501 bytes assets/sprites/undo2.png | Bin 460 -> 460 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/sprites/music_bg1.png create mode 100644 assets/sprites/music_bg2.png diff --git a/assets/sprites/music_bg1.png b/assets/sprites/music_bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..ce59ab6023fd28bc3762257654c60e3664238348 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zlRaG=Ln`LH zoxPW@$w8pyqJ;J1_=QvVeiW>!lRtPP+H+yX8;uL6j_lTu+i~0>Z66=g^qqz2ocAWG zG|i4X`&(|A)|(YJ^Xqs-W1ZL*urA;{+cWv+)hcPnQ~zc7t^Z#+|MOya1CIl@!)IOP zr8D=(Zi=Y-mt-^B>bRn9<36SohA4(v;c9cvd~fG|zUX4fy(x0R?{40-)cbU0{}T6j zMk5AYhO-LK9$deCujb6jqGT(%TGkT`TNq3Ns}HEJO0#g2uWW~yA|=@%*5C$m!9>Ok z#te|bQdP`n;@Xn-Z#mKgRRa{5wczOftsQP&5VLvrGCKNRh)>IVU9@w(am%smtfw}_ zedlhpV*=Z}n%&~}^DZ0RyT(^U?cQ>J^1qVRlv}BF<>fECu7;xuV*6RTCcJ00y2|fV z^q;Smzopr E08@UiF#rGn literal 0 HcmV?d00001 diff --git a/assets/sprites/music_bg2.png b/assets/sprites/music_bg2.png new file mode 100644 index 0000000000000000000000000000000000000000..bd283963c3c9168eb1057ab20353aef3d6f04abf GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%ztvy{FLn`LH zo$bxn-jo&0CRrKy|(M*fur+}zr7K6>Lo<@0{4unyt@5zXTHzT zFJJciVt50~0_FvUa~WfgeA{qbW~FmHqfi51gB!>Q4+bj+DNYA=2W5~=FIZ>X<*B^C zrNR-Sq%E%DrofgT+r=@MUf3QCxi9&uN`1v%2Z%Pc zC)JHho;iBlzrJuiLlxsi-3bbN(`7#0eXyUq(@MCO`vSK>(;V@2>(nYQl^uBv3{wVA LS3j3^P6Ru`{IuG>EN3 zVTy>Y#Ic?G?`++DTcRYr`*Z)ek2 z6%fjLKHlH_U5ojtuK*K3Isj?rJQDQ$_tzN}&noU8_Re-pPk&Hf0VaTS0MZPea6G@g zeR2-E+dp!}L(0$j)7idWPW~aA8@6bgrs=yj>G<8@2#Vw%76DQd_s>HL0TUoM>7{E? zivekZl*yy7t$q|Bx4_aJiY?*Lb^5L)vx52xAQb@VebjHU41+o4Iz9&}EZhPVUPaCW ztOrO3AdLwi9e;o{CV+GR(y+b{2!VX!3jr5^YTk|#rAQ0(UCTDDCKX`rE^#K5N|6;X zz#$xY57-@!vq6_w1w~iD0J0Jw0&osvYk>`eT+j1sVSOQzD@2v+0#k$%nG%P?N>wyL zB*i=njNxpe>MI~>dEBSe<#K;H+-GWeTzv(Y0MY?SqhMZuVHkA&KX<*HlA2L`MJs002ovPDHLkV1nG#*slNp delta 489 zcmVXzLM|9!#2NVVLk({&>ieIYu593Pp?9jbmJL-Xp}qZeQhDK0WN_U zssoY%9KyT=M5n>7k>jQ;n)& z*+K5=Q)EK~u@OS)XQ+>h+YpHzmI|;)5kzlVboC_#ECcqN_2e5RH8dpw1dzkgzLDpi z3ye+wiz|W%NJTJ@WbJV|x+dgyQh+Rl<5cz2;h6*fF=90LjZ)8m|Ig(AbH~HBI4!n9 z*R+>ksFHxxtiYwF>gTuwBpQ(z2`wn^3p7;^D7ud^F9Gub7%hPYDf(FR-r(E=GRi0O f5-=YC$1%Vo7l{ZGXL`W4v?~)&)apnX|+D{ z9pDDA1+ZDlNHFvFuRBW5CXUa?(dU>s!F&g}0c-(m`b>;6|9|-OMv#K%=lf&2X>Yy* z4w^sKwN29ZPv;9r$v-Lvq!vEi4`~FwCivmq_OY_NMsdx9^i8TTL2q3fGvQH8^9L8M)iI`2;>!C z2)F@K=j|v{ihqni*EVXW)uIM09VN|zQYo?ndNhm^p94oY@h&jd|3nC}2LfGvPc%=-dW%?B~LA7Z`(%q<&`9Dxc6)|m6&VCjY=)nq;b e<_&Nh-)p#Qo30R1Uz15PuU)NNJUpwDzlG+22Mb z8vDi1veGsL$2OCJ|NF2;!AI|Wridss;Q~kpAWg1kYM$Tjj(||;Tra2QrN8-^uK*W7 zIsj?fJksg;_w9{}hs1m{ul>&H3Fa%n1&|Ivnx7|Xo?oo?0)L_4c|Fd}OB3@IU|xV3 zdV%M?BK?24J}^a+#w!4EQ|hj_-3w6-a0|rbCcr7+Kg?Tzbq+}F9JOpY@9A?u0$2~= zYFNMfp!x!f0An_-cs&l0)mQ*E5RogOx%=qJjT_bq(3X4%iY$P_1&|Iv8W%u10BKwR z=>Vh|^*mq*U4LUX$6-nF6_Aq{WdJK)fDpP9q)wkK2O@}rkeqe;uA%-wBugOVYrvH$|e)8V$Ar#=^;mcRNYh+x!7u*9AK5g;yAe>z+^a0`@v zP@46gpw@SWQeD4!!Mp`r0O6hShJoX{^$P7!rtUo+q0iq(;MhCC&_b^p z19VC+_9c#;So)<(-$X(Z7f#+Xd z-v~mP&d2^e-Zj`h^BLd*paVeD=aHo6zrRjY@l4|3aUE>u)PDr?8Q=n-13=SwBJlj; z?m0Nt}YYJt=OHB*}ER@!_9s1ShiK}ysp(1z>jku(FwG=h5qC2M&+M(T2Tyc{0WwLGq( z22kPxpaVc-UVvs84E{fNy&Q{*qExzyUc6(}eL!4oQAeY~P}R@DEl}ekHF^R?&iewY z>Oqe0+nBe2c>#(oppax6$GkTvU67(SnYVy>0UXCTzv~BF^v}vQ{r~^~07*qoM6N<$ Ef&}Q<-T(jq delta 464 zcmV;>0Wbdb1NQ@vF@Ld1L_t(|ob8*xZo)7S#sfm#Dxe);>W+8>o}WiR>`X8esJb!G zPL^UTBxmRTS$DrJQ3&VH_nj}8G>v1MN#W=IP@}*jdpuK$C~Cq5kPbi^sAnS2e{FUI zp^WEr+^44o$7enRTmb0+qna>awn@9jG}em*YgC6gKUm)_5Z(f3%aw+NBIP-%ht`G6uM1oRBRq%8tfR;bK? zE~ql18Ud(Kw+al+bdD7utAP0os7?UvTA*$fXs0;GQm8ruI2t0=0&w60NCzN|3m_eU zH0A|h?E^TT?tgMoodFz;5K9Jd{kTzrx>mSp`US(b4ygc|XFed70VU#46iyNWYMA+e z>Q$f()v~Fw2nINM1rh;5;H6gJY?4Sbpic!axj!p+e$MRgXLXocjLH!ihdWkEo)Q6P$vQh-@~=j>oS3 zoggS=b~5%Rt7J9{d@~=p-@T}catt2N8$yL8!T`1aHn}y^sQHiGCqT+{&fmxOrrz+M16u)RbA&6YvUCcY{`dmO#l!qb{Z0C%}XO$QvnD zvp^lGyGLjO#tcGw0R^4_t?K|4CVBvpFn}$9P1bXQR-YMq^-NHEgZl)80c-(ma^4p( z)emy&zK;6@xHn*M2^b_f#xd^=YByxinB13udjo>NITa5_WJa~;Knef=0000DD=Y1bv%GD=e3;ls@ zQ?LGveOUo0@k3+++NK6E(g*MaK+-n>D-|LWFa=g3k}&`aacyvEr`ME%wZRFJGXVN5 z5Z49z5vOQ{q7y(d5Q#Q`0yBVH05@g;w*YR`8$db-P<*=!MRWov1|gCJQ2n?OgSb&R z%jOM(E*(?@B!BO`gDn9u=3pG0CKQlK1?P!lj` zgiV4%ATeNHR$_L1jQRwSb^(bgP@e!ZfLj1JUiS&6de6|*pP}Om>JwlFa0}qZ=Xrso z&I6yi@1s5e>J11kfdrXdW6X1d(hUh(lll@+Z-8Ma=M@J{^ihZdf?VDJ0000 Date: Sat, 31 Aug 2024 20:46:41 +0530 Subject: [PATCH 2/5] use mute button with bg --- assets/sprites/music_bg3.png | Bin 0 -> 417 bytes assets/sprites/music_bg4.png | Bin 0 -> 386 bytes constants.py | 6 ++++-- main.py | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 assets/sprites/music_bg3.png create mode 100644 assets/sprites/music_bg4.png diff --git a/assets/sprites/music_bg3.png b/assets/sprites/music_bg3.png new file mode 100644 index 0000000000000000000000000000000000000000..bb3b887a2488734a5a38aa948c347641153229da GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zqdi?5Ln`LH zoo&e1?JaQv&fhgy0$CwBD%rh%xSx&t9@tpbHB$cMw zB@Zg)gGI}}$eq_}>rz!@zQA;$CGFVBKQC)K6;f@!-@bbPYkAEVQ3a61pHm*`&*IN3 zO`8|^=G)B8vX_KkXgjbiU|q1%_+d)jR!b}P+|7qWs(dQN`O|l675|?wWgk-tLlncT z(lgz^zo&AqnePbI(0Pmb){EH>C2E&&*0P>p*ur39#GuR2%j3Z9pbWAJEcAtK#$KMI zb(x*4P&GgSQ^)T5Y{6cr!BSPsO|ur*pS8LEvM4^CWAb_KlE#Q?7kNg>2C;@^?-rTI)@`Pa|N0z#3-roc6=Uza3vSraaa6xi=}C2?>(}N9cgz>|GwfyDtGvO% s>bS*|-3NC{U&{9RBDlcZfum@jy_MC)Ib16b1H+ub)78&qol`;+0I9#MumAu6 literal 0 HcmV?d00001 diff --git a/assets/sprites/music_bg4.png b/assets/sprites/music_bg4.png new file mode 100644 index 0000000000000000000000000000000000000000..40615a2f4820774cdde631272e9f7812ad02a0bd GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zZ9H8ZLn`LH zoxPFkkb{7Wu%J@Yjg@m-=l=h%`%>r46+afksbNk+NqfA@Wcz1cubhzlZsTr&$tg1* zsL5B{y=>Add-3_qiX|SLoDS>`!ncfj=f$u4&KG#B*mnBcrR$$BUe5rM_`K4+s(Rn9 z(6~ysK%K5*?!O{I&I~=_rW`ouL`LokO{@VG!P7BsER53cf=Un#dT)=f}$G5CdZHo7~ zRZRJve(mF{Wxc@Nk=Mxb()RI$_iX=TJ+91r5#12iAn;@l!~0UT%Hos8JitI@@O1Ta JS?83{1OVC0pECde literal 0 HcmV?d00001 diff --git a/constants.py b/constants.py index 3a520c2..151f9d3 100644 --- a/constants.py +++ b/constants.py @@ -63,8 +63,10 @@ SPRT_BESTFS_BTN = pygame.image.load(PATH_SPRITES / "bst_button1.png") SPRT_BESTFS_BTN_CLICKED = pygame.image.load(PATH_SPRITES / "bst_button2.png") -SPRT_MUSIC_OFF_BTN = pygame.image.load(PATH_SPRITES / "music_off.png") -SPRT_MUSIC_ON_BTN = pygame.image.load(PATH_SPRITES / "music_on.png") +SPRT_MUSIC_OFF_BTN_HOVERED = pygame.image.load(PATH_SPRITES / "music_bg4.png") +SPRT_MUSIC_OFF_BTN = pygame.image.load(PATH_SPRITES / "music_bg3.png") +SPRT_MUSIC_ON_BTN_HOVERED = pygame.image.load(PATH_SPRITES / "music_bg2.png") +SPRT_MUSIC_ON_BTN = pygame.image.load(PATH_SPRITES / "music_bg1.png") SPRT_RESTART_BTN = pygame.image.load(PATH_SPRITES / "reset1.png") SPRT_RESTART_BTN_CLICKED = pygame.image.load(PATH_SPRITES / "reset2.png") diff --git a/main.py b/main.py index ce857bf..e6c96c9 100644 --- a/main.py +++ b/main.py @@ -103,6 +103,8 @@ def __init__( (30 + 64 + 5, 400), c.SPRT_MUSIC_ON_BTN, c.SPRT_MUSIC_OFF_BTN, + c.SPRT_MUSIC_ON_BTN_HOVERED, + c.SPRT_MUSIC_OFF_BTN_HOVERED, ) self.undo_button = widgets.ImageButton( (99 + 64 + 5, 400), From 3ef1d2f1ca2b519429bb6ddd6f4cee07de108ffd Mon Sep 17 00:00:00 2001 From: Nikhil Henry <25770025+nikhilhenry@users.noreply.github.com> Date: Sat, 31 Aug 2024 23:18:12 +0530 Subject: [PATCH 3/5] modify movegen, goaltest, hash board differently --- board.py | 83 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/board.py b/board.py index 8e95854..cab0091 100644 --- a/board.py +++ b/board.py @@ -3,11 +3,10 @@ """ from __future__ import annotations - from enum import Enum from collections import defaultdict import pickle -from typing import Dict +from typing import Dict,Self from search import dhokla_first_search, best_first_search, bread_first_search from utils import Position from search import Node @@ -16,6 +15,22 @@ import argparse +def construct_matrix_from_hashmap(board_hashmap): + n=7 + matrix = [[board_hashmap[Position(i,j)] for j in range(n)] for i in range(n)] + return matrix + + +def rotate90(mat_mat): + n= len(mat_mat) + matrix = [[mat_mat[j][i] for j in range(n)] for i in range(n)] + # Reverse each row + for i in range(n): + matrix[i].reverse() + return matrix + +def str_matrix(matrix:list[list[NodeState]]): + return "".join(["".join([str(s) for s in row]) for row in matrix]) class Move: """ @@ -107,7 +122,14 @@ def construct_from_string(cls, s: str): def __hash__(self) -> int: # to allow for hashing of the board state, we use the string representation - return hash(str(self)) + # create a list of all rotated states + top = construct_matrix_from_hashmap(self._board) + hashed = hash(str_matrix(top)) + for _ in range(3): + top = rotate90(top) + hashed+=hash(str_matrix(top)) + + return hashed def __str__(self) -> str: s = "" @@ -128,38 +150,43 @@ def __getitem__(self, pos: Position) -> NodeState: def __setitem__(self, pos: Position, value: NodeState): self._board[pos] = value - def __le__(self, other): - return self.num_marbles <= other.num_marbles + def __le__(self, other:Self): + #return self.num_marbles <= other.num_marbles + return self._distance_from_center() <= other._distance_from_center() def __eq__(self, other): return hash(self) == hash(other) + def _total_possible_moves(self): + marble_positions = [pos for pos, state in self._board.items() if state == NodeState.FILLED] + total = 0 + for marble in marble_positions: + total+=len(self.get_possible_move_locations(marble)) + return total + + def _distance_from_center(self): + marble_positions = [pos for pos, state in self._board.items() if state == NodeState.FILLED] + manhattan = 0 + for position in marble_positions: + diff = self._CENTER - position + manhattan += abs(diff.row) + abs(diff.column) + return manhattan + def solvable(self) -> bool: """ - Returns True if current arrangment of marbles allows for some marbles to be eliminated, else False. + Returns True if moves are still possible, else False. """ if self.num_marbles == 1: # solved! return True - if self.num_marbles > 4: - # some moves can still be made in this state - return True - marble_positions = [ pos for pos, state in self._board.items() if state == NodeState.FILLED ] # compute the distance between this marble and every other marble for marble in marble_positions: - for other in marble_positions: - if other == marble: - continue - distance = marble - other - # if either difference in column or row is odd we can eliminate a marble - if distance.row == 0 and distance.column % 2 == 1: - return True - if distance.column == 0 and distance.row % 2 == 1: - return True + if len(self.get_possible_move_locations(marble)) != 0: + return True return False def make_move(self, move: Move) -> Board | None: @@ -219,21 +246,23 @@ def make_move(self, move: Move) -> Board | None: return new_board - def get_possible_move_locations(self, pos: Position) -> list[Position]: + def get_possible_move_locations(self, src: Position) -> list[Position]: """ Returns a list of possible move-to positions from the given position """ - positions = [] + moves = [] for i in range(-2, 3, 2): if i == 0: # to avoid self moves continue - if self[pos + Position(i, 0)] == NodeState.EMPTY: - positions.append(pos + Position(i, 0)) - if self[pos + Position(0, i)] == NodeState.EMPTY: - positions.append(pos + Position(0, i)) + if self[src + Position(i, 0)] == NodeState.EMPTY: + moves.append(Move(src,src + Position(i, 0))) + if self[src + Position(0, i)] == NodeState.EMPTY: + moves.append(Move(src,src + Position(0, i))) + + # filter the positions based on if the in-between has a marble - return positions + return [move.dst for move in moves if self[move.get_in_between_pos()] == NodeState.FILLED] def move_gen(self) -> list[Board]: """ @@ -265,7 +294,7 @@ def goal_test(self) -> bool: """ Returns True if the game is over """ - return self.num_marbles == 1 + return self.num_marbles == 1 and self[Position(3,3)] == NodeState.FILLED """ From 110600a92cfe9330532532ef5f71883f23414a9b Mon Sep 17 00:00:00 2001 From: PjrCodes <25995849+PjrCodes@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:40:46 +0530 Subject: [PATCH 4/5] remov astar --- search/astar.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 search/astar.py diff --git a/search/astar.py b/search/astar.py deleted file mode 100644 index e69de29..0000000 From a7ced1860d0b7dd5d36e10651727de0fd19a9ea4 Mon Sep 17 00:00:00 2001 From: PjrCodes <25995849+PjrCodes@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:45:54 +0530 Subject: [PATCH 5/5] dfs now uses sets in all cases --- search/dfs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/search/dfs.py b/search/dfs.py index 767fcf1..d85ddc9 100644 --- a/search/dfs.py +++ b/search/dfs.py @@ -7,7 +7,8 @@ def dhokla_first_search(start_node: Node): prev_marble_count = start_node.board.num_marbles open: list[Node] = [start_node] - closed: list = [] + closed: set = set() + while open != []: parent = open.pop() if parent.board.goal_test(): @@ -17,7 +18,7 @@ def dhokla_first_search(start_node: Node): prev_marble_count = parent.board.num_marbles print(f"Marbles left: {parent.board.num_marbles}") - closed.append(parent.board) + closed.add(parent.board) children: list = parent.board.move_gen() children = [child for child in children if child not in closed] @@ -43,7 +44,7 @@ def stepped_dhokla_first_search(node: Node, open: list[Node] | None, closed: set children: list = parent.board.move_gen() children = [child for child in children if child not in closed] - + for child in children: open.append(Node(child, parent))