Skip to content

Commit

Permalink
Merge branch 'nikhilhenry:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
PjrCodes authored Sep 4, 2024
2 parents 2b500f0 + a7ced18 commit b640dda
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 32 deletions.
Binary file added assets/sprites/music_bg1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/music_bg2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/music_bg3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/music_bg4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/sprites/reset1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/sprites/reset2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/sprites/undo1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/sprites/undo2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 56 additions & 27 deletions board.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
"""
Expand Down Expand Up @@ -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 = ""
Expand All @@ -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:
Expand Down Expand Up @@ -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]:
"""
Expand Down Expand Up @@ -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


"""
Expand Down
6 changes: 4 additions & 2 deletions constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Empty file removed search/astar.py
Empty file.
7 changes: 4 additions & 3 deletions search/dfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand All @@ -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]
Expand All @@ -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))

Expand Down

0 comments on commit b640dda

Please sign in to comment.