Skip to content

Commit

Permalink
⚡ Modularised most of everything, integrating dearch methods
Browse files Browse the repository at this point in the history
  • Loading branch information
vishalpaudel committed Oct 20, 2023
1 parent 457b95f commit 66fddb1
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 175 deletions.
15 changes: 0 additions & 15 deletions main.py

This file was deleted.

3 changes: 2 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from searchViz.Game import Game
from searchViz.Search import dfs

from searchViz.constants import NUM_NODES

# to hide the message


def main():
aGame = Game(search_method=dfs, num_nodes=NUM_NODES)
Expand Down
169 changes: 72 additions & 97 deletions src/searchViz/Game.py
Original file line number Diff line number Diff line change
@@ -1,136 +1,111 @@
# /usr/bin/env python3


import pygame
import numpy as np

import pygame as pg
from .constants import SCR_SIZE, BG_COLOR, RED, WHITE, NODE_RADIUS, SEARCH_RATE


from .Search import Search
from .Graph import Graph


class Game:
def __init__(self, search_method: Search, num_nodes: int):
pygame.init()
pg.init()

# main attributes of the game
self.search_method = search_method
self.Graph = Graph(num_nodes)

# pygame initialization
self.screen = pygame.display.set_mode(SCR_SIZE)
pygame.display.set_caption(f"Search Method: {search_method.name}")
# pg initialization
self.screen = pg.display.set_mode(SCR_SIZE)
self.graph_surf = pg.Surface(self.screen.get_size(), pg.SRCALPHA)
pg.display.set_caption(f"Search Method: {search_method.name}")

# more helper attributes
self.font = pg.font.Font(None, 36)
self.bg_surf = pg.Surface(self.screen.get_size())
self.bg_surf.fill(BG_COLOR)

# control flow related attributes
self.start_search = False
self.running = True

print("🐼 searchViz has been initialized! 🎉")

def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.running = False
pg.quit()
print("\n\t🐼 Bye from searchViz 🔥")
exit()
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1: # Left mouse button
click_x, click_y = event.pos
pg.draw.circle(
self.graph_surf,
RED,
(click_x, click_y),
radius=5 * NODE_RADIUS,
)

def run(self):
# Handle spacebar key press
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
self.start_search = not self.start_search

return None

def draw_graph(self):
# unpacking frequently used variables
graph_surf = self.graph_surf
num_nodes = self.Graph.num_nodes
nodes = self.Graph.nodes
colors = self.Graph.colors
radius = self.Graph.radius
edges = self.Graph.edges

open = int(np.random.randint(0, num_nodes, 1)[0])
closed = []

screen = self.screen

step = 1
start_search = False
font = pygame.font.Font(None, 36)
last_step_update_time = pygame.time.get_ticks()

# Precompute some values outside the loop
bg_surface = pygame.Surface(screen.get_size())
bg_surface.fill(BG_COLOR)

graph_surface = pygame.Surface(screen.get_size(), pygame.SRCALPHA)
# need to use this when traversing
# edge_colors = self.Graph.edge_color

# Draw nodes and their edges
for i in range(num_nodes):
# Unique (uni-directional) edges
for j in range(i, num_nodes):
if edges[i, j]:
pygame.draw.line(graph_surface, WHITE, nodes[i], nodes[j])
pg.draw.line(graph_surf, WHITE, nodes[i], nodes[j])

node = nodes[i]
pygame.draw.circle(
graph_surface,
pg.draw.circle(
graph_surf,
color=tuple(colors[i]),
center=node,
radius=radius[i],
)

running = True
while running:
current_time = pygame.time.get_ticks()
# Clear the screen once at the beginning of the frame
# graph_surface.blit(bg_surface, (0, 0))

screen.blit(bg_surface, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Left mouse button
click_x, click_y = event.pos

pygame.draw.circle(
graph_surface,
RED,
(click_x, click_y),
radius=5 * NODE_RADIUS,
)
# Handle spacebar key press
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
start_search = not start_search

screen.blit(graph_surface, (0, 0))

# Update game logic here
if start_search:
# Calculate the time elapsed since the last step update
time_elapsed = current_time - last_step_update_time

# Check if 5 seconds (5000 milliseconds) have passed
if time_elapsed >= SEARCH_RATE * 1000:
# Increment the step and update the last step update time
def run(self):
last_time = pg.time.get_ticks()
step = 0
self.draw_graph()
while self.running:
cur_time = pg.time.get_ticks()

self.screen.blit(self.bg_surf, (0, 0))
self.handle_events()
self.screen.blit(self.graph_surf, (0, 0))

_txt = self.font.render(f"searchViz: {step}", 1, (255, 255, 255))
self.screen.blit(_txt, (10, 10))

pg.display.flip()

# Time control
if self.start_search:
_delta = cur_time - last_time
if _delta >= SEARCH_RATE * 1000:
step += 1
last_step_update_time = current_time
# draw node

node = nodes[open]
pygame.draw.circle(
graph_surface,
color=RED,
center=nodes[open],
radius=2 * radius[open],
)
last_time = cur_time
# APPLY SEARCH HERE

flag = False
for i in range(open, num_nodes):
connected = edges[open, i]
if connected:
closed.append(i)
open = i
flag = True
break

if not flag:
for i in range(0, open):
connected = edges[i, open]
if connected and (i not in closed):
closed.append(i)
open = i
flag = True
break
if not flag:
open = int(np.random.randint(0, num_nodes, 1)[0])

step_text = font.render(f"Step: {step}", True, (255, 255, 255))
screen.blit(step_text, (10, 10)) # Adjust the position as needed

pygame.display.flip()

pygame.quit()
pg.quit()
113 changes: 81 additions & 32 deletions src/searchViz/Graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,77 +5,126 @@

import numpy as np
import time
from typing import List

import threading


class Node:
def __init__(self, id: np.uint16):
"""
id: the id of the node, np.uint16 for maximum
of 2^16 (= 65535 + 1) nodes on the screen
"""
self.id = id


class Graph:
def __init__(self, num_nodes: int):
self.num_nodes = num_nodes

_start_time = time.time()
self.nodes, self.colors, self.radius = nodes(num_nodes)
self.edges = edges(self.nodes)
self.nodes, self.colors, self.radius = create_nodes(num_nodes)
self.edges, self.edge_colors = create_edges(self.nodes)

start_id, end_id = np.random.randint(0, self.num_nodes, size=2, dtype=np.uint16)
self.start_node = Node(start_id)
self.end_node = Node(end_id)

_end_time = time.time()
_elapsed_time = _end_time - _start_time

print(f"Took {_elapsed_time:.3f} seconds.")
print(f"\t🕰️ Took {_elapsed_time:.3f} seconds.\n")

########################################################################
# THE MOVEGEN AND GOALTEST FUNCTIONS
########################################################################

def x_distribution(n: int):
return NODES_X_DISTRIBUTION(n)
def moveGen(self, state: Node) -> List[Node]:
"""
Takes a state and returns an array of neighbors
"""
neighbors = []

id = np.uint16(0)
while id < self.num_nodes:
if [id, state.id] == 1:
neighbors.append(Node(id))
id += 1

def y_distribution(n: int):
return NODES_Y_DISTRIBUTION(n)
print()
return neighbors

def goalTest(self, state: Node) -> bool:
print(state)
return True

def edge_confidence(node1: np.ndarray, node2: np.ndarray):
return EDGE_CONFIDENCE(node1, node2)

def create_nodes(n: int):
"""
Returns a vector of `n` points, colors, radii:
[
(5.0, 0.1)
(2.1, 5.0)
...
(3.1, 4.0)
]
according to a distribution function defined in constants
"""

def nodes(n: int):
# returns a vector of `n` points, colors:
# [
# (5.0, 0.1)
# (2.1, 5.0)
# ...
# (3.1, 4.0)
# ]
# according to a distribution function defined in constants

print("creating nodes... timer started...")
x_values = x_distribution(n)
y_values = y_distribution(n)
print(f"🕰️\tCreating {n} nodes... timer started...")
x_values = NODES_X_DISTRIBUTION(n)
y_values = NODES_Y_DISTRIBUTION(n)

colors = np.full((n, 4), fill_value=BLUE, dtype=np.uint8)
radius = np.full((n,), fill_value=NODE_RADIUS, dtype=np.uint8)
radii = np.full((n,), fill_value=NODE_RADIUS, dtype=np.uint8)

# generating the goal node
goal_loc = np.random.randint(0, n, 1)
colors[goal_loc] = RED
print(goal_loc)
radius[goal_loc] = 3 * NODE_RADIUS
radii[goal_loc] = 3 * NODE_RADIUS

nodes = np.column_stack((x_values, y_values))
print("Finished creating nodes!")
print("✅\tFinished creating nodes!\n")

return nodes, colors, radii

return nodes, colors, radius

def create_edges(nodes: np.ndarray):
"""
Creates edges for the give nodes locations
"""
global done
done = threading.Event()

def edges(nodes: np.ndarray):
print("creating edges...")
dot_thread = threading.Thread(target=animate_dots)
dot_thread.start()

n = len(nodes)
edges = np.zeros((n, n))
i, j = np.triu_indices(n, k=1)

_toss = np.random.rand(n, n)
_confidence = np.zeros((n, n))
_confidence[i, j] = edge_confidence(nodes[i], nodes[j])
_confidence[i, j] = EDGE_CONFIDENCE(nodes[i], nodes[j])

# confidence number of times there will be an edge
edges = _toss <= _confidence
edge_color = (edges).astype(int)

# Stop the dot animation
done.set()
dot_thread.join() # Wait for the animation thread to finish

print("\n\tFinished creating edges!\n")
return edges, edge_color

print("Finished creating edges!")

return edges
# for animating while the edges get created
def animate_dots():
symbols = [".", "..", "...", "...🐌"]
while not done.is_set():
for symbol in symbols:
print(f"🕰️\tCreating edges {symbol}", end=" \r", flush=True)
time.sleep(0.25)
return
Loading

0 comments on commit 66fddb1

Please sign in to comment.