diff --git a/currissue.txt b/currissue.txt new file mode 100644 index 0000000..5c7ab0a --- /dev/null +++ b/currissue.txt @@ -0,0 +1 @@ +people in innermost rows just tunnel through and disappear... why? diff --git a/main.py b/main.py index 635f743..046c869 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,14 @@ #(height, width) import random as rnd import os +import sys import itertools from enum import Enum import time import math from queue import PriorityQueue as pq +from sortedcontainers import SortedList as sl +from intervaltree import IntervalTree as itree DEBUG=True # DEBUG=False @@ -25,144 +28,167 @@ entries=[(0,3)] # entries=[(7,3),(7,43)] # entries=[(7,3)] -passengers = None +tickTaken = 0 +passengers = None class GridSquare: - #typ: SquareType, occupant: index - def __init__(self, typ, occupant): + #typ: SquareType + def __init__(self, typ): 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)] + #occupAtTick is an interval tree, stores intervals where the gridSquare is occupied + #intervals are [a,b), a nice sane choice + #values are individuals + self.occupAtTick = itree() 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 + self.inter = None + #Path is composed of tuples: (pos, t) + self.path = [] 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 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)] +def findPath(passenger, pid, currTick): + global passengers + global grid - dest = None + #used when moving into seats + afterTick = 0 - if passenger.inter == None: - dest = passenger.dest - else: - dest = passenger.inter + dest = passenger.inter + #Element format: (Tick at time of movement, Position, Time stayed in previous square) 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 + time=[[10**10 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)] - 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) + time[passenger.curr[0]][passenger.curr[1]]=currTick + + q.put((currTick, passenger.curr, 1)) while not q.empty(): u = q.get() if u[1] == dest: + grid[u[1][0]][u[1][1]].occupAtTick.addi(u[0],u[0]+3,pid) + afterTick = u[0]+2 + # passenger.path.append((u[1], u[0])) + u=prev[u[1][0]][u[1][1]] while prev[u[1][0]][u[1][1]] != None: - passenger.path.append(u[1]) + grid[u[1][0]][u[1][1]].occupAtTick.addi(u[0],u[0]+u[2],pid) + # passenger.path.append((u[1], u[0])) u=prev[u[1][0]][u[1][1]] - return + # passenger.path.append((passenger.curr, currTick)) + break + #The Art of Standing Still + q.put((u[0] + 1, u[1], 1)) 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 + alt = 0 + if grid[x[0]][x[1]].typ == SquareType.SEAT: + if ( not (grid[u[1][0]][u[1][1]].typ == SquareType.AISLE and u[1][1] != x[1]) and + len(grid[x[0]][x[1]].occupAtTick[u[0]:u[0]+5-1]) == 0): + alt = time[u[1][0]][u[1][1]] + 5 + if alt < time[x[0]][x[1]]: + time[x[0]][x[1]] = alt + prev[x[0]][x[1]] = u + q.put((alt, x, 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 - border=[] - arrFile = open("figure2.txt") - - height=int(arrFile.readline()) - width=int(arrFile.readline()) - print(height) - print(width) - - grid = [[GridSquare(SquareType.AISLE, None) for x in range(0,width)] for y in range(0,height)] + continue + elif grid[x[0]][x[1]].typ == SquareType.AISLE: + if len(grid[x[0]][x[1]].occupAtTick[u[0]+1:u[0]+1+1]) == 0: + alt = time[u[1][0]][u[1][1]] + 1 + if alt < time[x[0]][x[1]]: + time[x[0]][x[1]] = alt + prev[x[0]][x[1]] = u + q.put((alt, x, 1)) + else: + continue + else: + continue + # print(grid[passenger.path[3][0][0]][passenger.path[3][0][1]].occupAtTick) - for y in range(0,height): - for x in range(0,width+1): - char = arrFile.read(1); - 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 - - 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 + dest = passenger.dest + moveDir = None + if dest[0] > passenger.inter[0]: + moveDir = -1 + else: + moveDir = 1 + mDone=False + while not mDone: + mDone = True + u=passenger.dest + while u != passenger.inter: + occup = list(grid[u[0]+moveDir][u[1]].occupAtTick[afterTick:afterTick+5]) + if len(occup) != 0: + if (moveDir == 1 and passengers[occup[0][2]].dest < u) or (moveDir == -1 and passengers[occup[0][2]].dest > u): + # if dest == (6,4): + # print(u) + mDone=False + occup2 = list(grid[u[0]][u[1]].occupAtTick[afterTick:afterTick+5]) + if len(occup2) != 0: + grid[u[0]+moveDir][u[1]].occupAtTick.addi(occup[0][0], afterTick, occup[0][2]) + grid[u[0]+moveDir][u[1]].occupAtTick.remove(occup[0]) + grid[u[0]][u[1]].occupAtTick.addi(occup2[0][0], afterTick, occup2[0][2]) + grid[u[0]][u[1]].occupAtTick.remove(occup2[0]) + grid[u[0]+moveDir][u[1]].occupAtTick.addi(afterTick,10**11,occup2[0][2]) + grid[u[0]][u[1]].occupAtTick.addi(afterTick,10**11,occup[0][2]) + else: + grid[u[0]+moveDir][u[1]].occupAtTick.addi(occup[0][0], afterTick, occup[0][2]) + grid[u[0]+moveDir][u[1]].occupAtTick.remove(occup[0]) + grid[u[0]][u[1]].occupAtTick.addi(afterTick,10**11,occup[0][2]) + u = (u[0] + moveDir, u[1]) + afterTick+=4 + + +def printPath(p): + print("inter: " + str(p.inter)) + print("dest: " + str(p.dest)) + for x in p.path: + print(str(x[0]) + ": " + str(grid[x[0][0]][x[0][1]].occupAtTick[x[1]])) - return border +btime = 3 #passengers board every btime ticks +delay = 0.01 -def nunty(x): - if x is None: return -1 - return x +#Precomputation of all paths, later code is just output functionality +def compute(): + global btime + global passengers + global tickTaken + tick=0 + toadd=0 + #genderequality #blm #blessed #syria + for (i, prsn) in enumerate(passengers): + for e in entries: + if toadd < len(passengers) and len(grid[e[0]][e[1]].occupAtTick[tick]) == 0: + prsn.curr = (e[0], e[1]) + findPath(prsn, i, tick) + if DEBUG: + print("calculating: " + str(i)) + tick += btime + toadd += 1 + else: + tick += 1 -btime = 3 #passengers board every btime ticks + for row in grid: + for x in row: + # print(x.occupAtTick) + if len(x.occupAtTick) != 0: + # print("list(x.occupAtTick.items)[-1][0]: " + str(list(x.occupAtTick.items())[-1][0])) + tickTaken = max(tickTaken, list(x.occupAtTick.items())[-1][0]) + print("Time Taken: " + str(tickTaken)) -def tick(t, toad): +def tick(t): done=True global btime + global delay # print grid if DEBUG: print(chr(0x3000), end="") @@ -186,8 +212,8 @@ def tick(t, toad): print(chr(0xFF10 + (i % 10)), end="") for guy in row: - if guy.occupant is not None: - print(chr(0x20000 + guy.occupant), end="") + if len(guy.occupAtTick[t]) != 0: + print(chr(0x20000 + list(guy.occupAtTick[t])[0][2]), end="") elif guy.typ == SquareType.SEAT: print(":", end="") elif guy.typ == SquareType.WALL: @@ -196,84 +222,70 @@ def tick(t, toad): print("_", end="") print() print("---") - # print(grid[3][0].occupant, grid[3][1].occupant, passengers[nunty(grid[3][1].occupant)].dest) - 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 + printPath(passengers[2]) if DEBUG: # time.sleep(1.0) # time.sleep(0.5) # time.sleep(0.1) - # time.sleep(0.05) + time.sleep(0.05) # time.sleep(0.02) - time.sleep(0.01) + # 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 +def init(): + global height + global width + global grid + global passengers + passengers = [] + arrFile = open("figure2.txt") + + height=int(arrFile.readline()) + width=int(arrFile.readline()) + print(height) + print(width) + + grid = [[GridSquare(SquareType.AISLE) for x in range(0,width)] for y in range(0,height)] + + for y in range(0,height): + for x in range(0,width+1): + char = arrFile.read(1); + match char: + case 'S': + grid[y][x].typ = SquareType.SEAT + passengers.append(Passenger((y,x),(-1,-1))) + case 'W': + grid[y][x].typ = SquareType.WALL + case '.': + grid[y][x].typ = SquareType.AISLE + + for x in passengers: + 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]) + break + +def run(end): t = 0 - while toad != -1: - toad = tick(t,toad) + while t < end: + tick(t) t += 1 - def main(): global passengers + init() #boarding order - for seediter in range(43,2000): - passengers = GenPassList() - print("Seed: " + str(seediter)) - rnd.seed(seediter) - # passengers.reverse() - rnd.shuffle(passengers) - run() + seediter = int(sys.argv[1]) + print("Seed: " + str(seediter)) + rnd.seed(seediter) + # passengers.reverse() + rnd.shuffle(passengers) + compute() + run(tickTaken) if __name__ == "__main__": main()