1 changed files with 425 additions and 0 deletions
@ -0,0 +1,425 @@ |
|||
#!/usr/bin/env python3 |
|||
#(height, width) |
|||
import random as rnd |
|||
import os |
|||
import itertools |
|||
from enum import Enum |
|||
import time |
|||
import math |
|||
from queue import PriorityQueue as pq |
|||
import threading |
|||
|
|||
DEBUG=True |
|||
# DEBUG=False |
|||
graphical=True |
|||
|
|||
clear="clear" |
|||
if os.name == "nt": |
|||
clear="cls" |
|||
|
|||
def resource_path(relative_path): |
|||
try: |
|||
# PyInstaller creates a temp folder and stores path in _MEIPASS |
|||
base_path = sys._MEIPASS; |
|||
except Exception: |
|||
base_path = os.path.abspath("./"); |
|||
return os.path.join(base_path, relative_path); |
|||
|
|||
figNum=2 |
|||
ans = input("Figure Number 1/2/3(other input to default 2): ") |
|||
match ans: |
|||
case "1": |
|||
figNum = 1; |
|||
case "3": |
|||
figNum = 3; |
|||
file = resource_path(f"figures/figure{figNum}.txt"); |
|||
tickDelay = float(input("Tick Delay(s): ")) |
|||
|
|||
imgSpacing = 5 #pixels |
|||
|
|||
class SquareType(Enum): |
|||
AISLE = 0 |
|||
SEAT = 1 |
|||
WALL = 2 |
|||
|
|||
height=0 |
|||
width=0 |
|||
|
|||
tiles = []; |
|||
imageDims = (30, 30); |
|||
root = None; |
|||
|
|||
grid=[] |
|||
# entries=[(3,0)] |
|||
entries=[(0,3)] |
|||
# entries=[(7,3),(7,43)] |
|||
# entries=[(7,3)] |
|||
|
|||
passengers = [] |
|||
|
|||
|
|||
class GridSquare: |
|||
#typ: SquareType, occupant: index |
|||
def __init__(self, typ, occupant): |
|||
self.typ = typ |
|||
self.occupant = occupant |
|||
def __str__(self): |
|||
return "(%s|%s)" % (str(self.typ), str(self.occupant)) |
|||
def __repr__(self): |
|||
return str(self) |
|||
|
|||
def makeGrid(): |
|||
return [[GridSquare(SquareType.AISLE, None) for x in range(0,width)] for y in range(0,height)] |
|||
|
|||
class Passenger: |
|||
shuffled = 0 |
|||
inter = None |
|||
interback = None |
|||
path = [] |
|||
recalc = True |
|||
#dest and curr are both 2-tuples |
|||
def __init__(self, dest, curr): |
|||
self.dest = dest |
|||
self.curr = curr |
|||
def __str__(self): |
|||
return "(%s|%s)" % (dest, curr) |
|||
|
|||
def manhattanDistance(pos1, pos2): |
|||
return abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1]) |
|||
|
|||
def mooreNeighbourhood(pos): |
|||
return [i for i in [(pos[0]+1, pos[1]), (pos[0], pos[1]+1), (pos[0]-1, pos[1]), (pos[0], pos[1]-1)] if |
|||
i[0] >= 0 and i[1] >= 0 and i[0] < height and i[1] < width] |
|||
|
|||
def Dims(): |
|||
global height |
|||
global width |
|||
arrFile = open(file) |
|||
height=int(arrFile.readline()) |
|||
width=int(arrFile.readline()) |
|||
|
|||
def nextSquare(passenger, grid): |
|||
passenger.recalc = False |
|||
passenger.path=[] |
|||
dist=[[0 for x in range(0,width)] for y in range(0,height)] |
|||
prev=[[None for x in range(0,width)] for y in range(0,height)] |
|||
|
|||
dest = None |
|||
|
|||
if passenger.inter == None: |
|||
dest = passenger.dest |
|||
else: |
|||
dest = passenger.inter |
|||
|
|||
q = pq() |
|||
|
|||
for y in range(0,height): |
|||
for x in range(0,width): |
|||
if x != passenger.curr[1] or y != passenger.curr[0]: |
|||
dist[y][x] = 10**10 |
|||
|
|||
mn = mooreNeighbourhood(passenger.curr) |
|||
for (i, man) in enumerate(mn): |
|||
if (grid[passenger.curr[0]][passenger.curr[1]].typ != SquareType.SEAT or man[1] == passenger.curr[1]) and grid[man[0]][man[1]].typ != SquareType.WALL and not (grid[man[0]][man[1]].typ == SquareType.AISLE and grid[man[0]][man[1]].occupant is not None): |
|||
q.put((1, man, i)) |
|||
dist[man[0]][man[1]] = 1 |
|||
prev[man[0]][man[1]] = (0, passenger.curr, 0) |
|||
|
|||
while not q.empty(): |
|||
u = q.get() |
|||
if u[1] == dest: |
|||
while prev[u[1][0]][u[1][1]] != None: |
|||
passenger.path.append(u[1]) |
|||
u=prev[u[1][0]][u[1][1]] |
|||
return |
|||
for x in mooreNeighbourhood(u[1]): |
|||
# if not( grid[x[0]][x[1]].typ == SquareType.SEAT and u[1][1] != x[1]) and grid[x[0]][x[1]].typ != SquareType.WALL and (grid[x[0]][x[1]].occupant == None or grid[x[0]][x[1]].typ == SquareType.SEAT): |
|||
if not( grid[x[0]][x[1]].typ == SquareType.SEAT and u[1][1] != x[1]) and grid[x[0]][x[1]].typ != SquareType.WALL: |
|||
alt = 0 |
|||
if grid[x[0]][x[1]].typ == SquareType.SEAT or grid[u[1][0]][u[1][1]].typ == SquareType.SEAT: |
|||
if grid[x[0]][x[1]].occupant != None: |
|||
alt = dist[u[1][0]][u[1][1]] + 5 + 10 |
|||
else: |
|||
alt = dist[u[1][0]][u[1][1]] + 5 |
|||
else: |
|||
alt = dist[u[1][0]][u[1][1]] + 1 |
|||
# if alt == 0: |
|||
# if x == dest: |
|||
# print("mn: " + str(x) + ", alt: " + str(alt)) |
|||
# print("dist" + str(x) + ": " + str(dist[x[0]][x[1]])) |
|||
if alt < dist[x[0]][x[1]]: |
|||
dist[x[0]][x[1]] = alt |
|||
prev[x[0]][x[1]] = u |
|||
q.put((alt, x, u[2])) |
|||
|
|||
passenger.path = [passenger.curr] |
|||
|
|||
|
|||
def GenPassList(): |
|||
global height |
|||
global width |
|||
global grid |
|||
global tiles |
|||
border=[] |
|||
arrFile = open(file) |
|||
|
|||
height=int(arrFile.readline()) |
|||
width=int(arrFile.readline()) |
|||
print(f"{file} Dimensions: {height}, {width}") |
|||
|
|||
grid = [[GridSquare(SquareType.AISLE, None) for x in range(0,width)] for y in range(0,height)] |
|||
|
|||
for y in range(0,height): |
|||
temp = [] |
|||
for x in range(0,width+1): |
|||
char = arrFile.read(1); |
|||
matched = False; |
|||
match char: |
|||
case 'S': |
|||
grid[y][x].typ = SquareType.SEAT |
|||
border.append(Passenger((y,x),(-1,-1))) |
|||
case 'W': |
|||
grid[y][x].typ = SquareType.WALL |
|||
case '.': |
|||
grid[y][x].typ = SquareType.AISLE |
|||
if graphical and x < width: |
|||
temp.append(Tile(root, imageDims[0], imageDims[1], x, y, 0, grid[y][x].typ, f"{x}|{y}")); |
|||
if graphical: |
|||
tiles.append(temp); |
|||
|
|||
for x in border: |
|||
sign=(-1)**rnd.randint(0,1) |
|||
for i in range(1,7): |
|||
inc = (-1)**i * sign * math.floor((i+1)/2) |
|||
if (inc + x.dest[0] > 0) and (inc + x.dest[0] < height) and (grid[x.dest[0]+inc][x.dest[1]].typ == SquareType.AISLE): |
|||
x.inter=(inc + x.dest[0], x.dest[1]) |
|||
x.interback = x.inter |
|||
|
|||
return border |
|||
|
|||
def nunty(x): |
|||
if x is None: return -1 |
|||
return x |
|||
|
|||
btime = 3 #passengers board every btime ticks |
|||
|
|||
def tick(t, toad): |
|||
done=True |
|||
global btime |
|||
# print grid |
|||
if DEBUG: |
|||
print(chr(0x3000), end="") |
|||
print(chr(0x3000), end="") |
|||
for x in range(0, width): |
|||
if x % 10 == 0: |
|||
print(chr(0xFF10 + int(x / 10)), end="") |
|||
else: |
|||
print(chr(0x3000), end="") |
|||
print() |
|||
print(chr(0x3000), end="") |
|||
print(chr(0x3000), end="") |
|||
for x in range(0, width): |
|||
print(chr(0xFF10 + (x % 10)), end="") |
|||
print() |
|||
for (i, row) in enumerate(grid): |
|||
if i % 10 == 0: |
|||
print(chr(0xFF10 + int(i / 10)), end="") |
|||
else: |
|||
print(chr(0x3000), end="") |
|||
print(chr(0xFF10 + (i % 10)), end="") |
|||
|
|||
for j in range(len(row)): |
|||
guy=row[j] |
|||
o=0 |
|||
if guy.occupant is not None: |
|||
print(chr(0x20000 + guy.occupant), end="") |
|||
o=1 |
|||
elif guy.typ == SquareType.SEAT: |
|||
print(":", end="") |
|||
elif guy.typ == SquareType.WALL: |
|||
print("W", end="") |
|||
else: |
|||
print("_", end="") |
|||
if graphical: |
|||
#print(f"{i},{j},{len(tiles)},{len(tiles[i])}") |
|||
if tiles[i][j].occ != o: #if value has changed since last tick |
|||
tiles[i][j].Update(o); |
|||
print() |
|||
print("---") |
|||
# print(grid[3][0].occupant, grid[3][1].occupant, passengers[nunty(grid[3][1].occupant)].dest) |
|||
elif graphical: |
|||
for (i, row) in enumerate(grid): |
|||
for j in range(len(row)): |
|||
o=0 |
|||
if row[j].occupant is not None: |
|||
o=1 |
|||
#print(f"{i},{j},{len(tiles)},{len(tiles[i])}") |
|||
#print(f"{i},{j},{len(tiles)}") |
|||
if tiles[i][j].occ != o: #if value has changed since last tick |
|||
tiles[i][j].Update(o); |
|||
time.sleep(tickDelay); |
|||
if t % btime == 0: |
|||
for x in entries: |
|||
if toad < len(passengers) and grid[x[0]][x[1]].occupant is None: |
|||
grid[x[0]][x[1]].occupant = toad #added |
|||
passengers[toad].curr = (x[0], x[1]) |
|||
toad += 1 |
|||
for (i, man) in enumerate(passengers): |
|||
if man.curr == man.dest: |
|||
continue |
|||
if man.inter is not None and man.curr == man.inter: |
|||
man.shuffled = 3 |
|||
man.inter = None |
|||
# man.recalc = True |
|||
if man.curr == (-1, -1): |
|||
continue |
|||
# if i == 36 and DEBUG: |
|||
# print(nextSquare(man, grid)) |
|||
done=False |
|||
#im sexist |
|||
if len(man.path) == 0 or man.recalc: |
|||
# if DEBUG: |
|||
# print("Recalculating: " + str(man.curr)) |
|||
nextSquare(man, grid) |
|||
|
|||
nextS = man.path.pop() |
|||
|
|||
if DEBUG: |
|||
print(str(man.curr) + ", " + str(man.interback) + ", " + str(man.dest) + ", " + str(nextS) + ", " + str(man.inter)) |
|||
|
|||
if passengers[i].shuffled == 0 and not ( grid[nextS[0]][nextS[1]].typ == SquareType.AISLE and grid[nextS[0]][nextS[1]].occupant is not None): |
|||
cp = man.curr |
|||
man.curr = nextS |
|||
other = grid[cp[0]][cp[1]] |
|||
other.occupant = grid[man.curr[0]][man.curr[1]].occupant #they move out of there |
|||
if other.occupant is not None: |
|||
passengers[other.occupant].curr = cp |
|||
passengers[other.occupant].shuffled = 5 |
|||
passengers[other.occupant].recalc = True |
|||
man.recalc = True |
|||
grid[man.curr[0]][man.curr[1]].occupant = i |
|||
for man in passengers: |
|||
if man.shuffled != 0: |
|||
man.shuffled-=1 |
|||
if DEBUG: |
|||
# time.sleep(1.0) |
|||
# time.sleep(0.5) |
|||
# time.sleep(0.1) |
|||
# time.sleep(0.05) |
|||
# time.sleep(0.02) |
|||
time.sleep(0.01) |
|||
# time.sleep(0.001) |
|||
os.system(clear) |
|||
if done and toad >= len(passengers): |
|||
print("Number of ticks: " + str(t)) |
|||
return -1 |
|||
# exit() |
|||
return toad |
|||
|
|||
def run(): |
|||
toad = 0 |
|||
t = 0 |
|||
while toad != -1: |
|||
toad = tick(t,toad) |
|||
t += 1 |
|||
|
|||
def main(): |
|||
global passengers |
|||
global tiles |
|||
#boarding order |
|||
|
|||
startSeed=43 |
|||
for seediter in range(startSeed,2000): |
|||
if seediter != startSeed: |
|||
tiles = [] |
|||
passengers = GenPassList() |
|||
print("Seed: " + str(seediter)) |
|||
rnd.seed(seediter) |
|||
# passengers.reverse() |
|||
rnd.shuffle(passengers) |
|||
run() |
|||
|
|||
def execute(): |
|||
th1 = threading.Thread(target=main); |
|||
th1.daemon = True; |
|||
th1.start(); |
|||
|
|||
# ======================================================================================================================================== |
|||
# GUI IMPLEMENTATION |
|||
if graphical: |
|||
import tkinter as tk; |
|||
from tkinter import ttk; |
|||
import tkinter.constants as const; |
|||
from PIL import ImageTk, Image; |
|||
import threading; |
|||
|
|||
imgs = []; |
|||
|
|||
class Tile: |
|||
def __init__(self, r, w, h, x, y, occ, typ, name="--"): |
|||
global imgSpacing |
|||
self.occ = occ; |
|||
self.typ = typ; |
|||
self.img = None; |
|||
if self.typ == SquareType.AISLE or self.typ == SquareType.WALL: |
|||
self.name = "█"; |
|||
if self.typ == SquareType.WALL: |
|||
self.img = seatImg |
|||
else: |
|||
self.img = imgs[self.occ]; |
|||
else: |
|||
self.name = name; |
|||
self.frame = ttk.LabelFrame(root, text=self.name, width=w, height=h); |
|||
self.frame.place(x = x * imageDims[0], y = y * (imageDims[1] + imgSpacing)); |
|||
self.panel = ttk.Label(self.frame, image=self.img); |
|||
self.panel.pack(side = "top", fill = "both", expand = "yes") |
|||
def __str__(self): |
|||
return f"{self.name}|{self.occ}|{self.typ}|{self.img}"; |
|||
def Update(self, occ, typ=None): |
|||
self.occ = occ; |
|||
if typ != None: |
|||
self.typ = typ; |
|||
if self.typ == SquareType.AISLE: |
|||
self.panel.configure(image=imgs[0]); |
|||
elif self.typ == SquareType.WALL: |
|||
self.panel.configure(image=ImageTk.PhotoImage(Image.open(resource_path("imgs/wall.png")))); |
|||
else: |
|||
self.panel.configure(image=imgs[self.occ]); |
|||
|
|||
if __name__ == "__main__": |
|||
if graphical: |
|||
Dims(); |
|||
|
|||
# Create the window |
|||
root = tk.Tk(); |
|||
root.title('IMMC 2022'); |
|||
#root.iconbitmap(resource_path("icon.ico")); |
|||
#root.resizable(0, 0); |
|||
|
|||
# Place the window in the center of the screen |
|||
windowWidth = width * imageDims[0] + 10;#was 510 |
|||
windowHeight = height * (imageDims[1] + imgSpacing) + 10; # was 332 |
|||
screenWidth = root.winfo_screenwidth(); |
|||
screenHeight = root.winfo_screenheight(); |
|||
xCordinate = int((screenWidth/2) - (windowWidth/2)); |
|||
yCordinate = int((screenHeight/2) - (windowHeight/2)); |
|||
root.geometry("{}x{}+{}+{}".format(windowWidth, windowHeight, xCordinate, yCordinate)); |
|||
|
|||
# Create a style |
|||
style = ttk.Style(root); |
|||
style.configure("Button", background="red"); |
|||
style.map('Button', background=[('active','red')]); |
|||
# Import the tcl file |
|||
root.tk.call('source', resource_path('theme/dark.tcl')); |
|||
# Set the theme with the theme_use method |
|||
style.theme_use('azure-dark'); |
|||
|
|||
seatImg = ImageTk.PhotoImage(Image.open(resource_path("imgs/wall.png"))); |
|||
imgs = [ImageTk.PhotoImage(Image.open(resource_path("imgs/occ0.png"))), ImageTk.PhotoImage(Image.open(resource_path("imgs/occ1.png")))] |
|||
|
|||
accentbutton_engage = ttk.Button(root, text='Start', style='Accent.TButton', command=execute); |
|||
accentbutton_engage.place(x=0, y=0); |
|||
|
|||
root.mainloop(); |
|||
else: |
|||
main() |
Loading…
Reference in new issue