REM Advent of Code 2022: Day 7, part 1 and 2
REM Written in Applesoft BASIC

REM Usual initialization. SPEED= sets the text speed; I play with it
REM and some empty FOR loops during the program for artistic effect.

 10  ONERR  GOTO 700
 20  PRINT  CHR$ (4),"OPEN INPUT"
 30  PRINT  CHR$ (4),"READ INPUT"
 40  HOME 
 50  SPEED= 170

REM DN$ and DS are a index-matched "map" of paths and sizes. A size of
REM 200 accommodated my input.
REM W$ stores the current working directory.

 100  DIM DN$(200)
 110  DIM DS(200)
 120  FOR I = 0 TO 199:DN$(I) = "": NEXT I
 130  FOR I = 0 TO 199:DS(I) = 0: NEXT I
 140 W$ = "/"

REM Main loop: consume a line of input, display it, and then handle
REM either the "ls" or "cd" that it is.

 200  GOSUB 4000
 210  PRINT "$";
 215  FOR I = 0 TO 1000: NEXT I
 218  SPEED= 70: PRINT  RIGHT$ (S$, LEN (S$) - 1): SPEED= 170
 220  IF  LEFT$ (S$,4) = "$ cd" GOTO 300
 230  GOTO 500

REM "cd" routine. If the path starts with '/', then clear the working
REM directory so we return to root.
REM If starting with a '.', GOTO 350 to handle backing up a level.
REM Otherwise, append to the working directory.

 300 C$ =  MID$ (S$,6,1)
 305  IF  ASC (C$) = 47 THEN W$ = ""
 310  IF  ASC (C$) = 46 GOTO 350
 320 W$ = W$ +  MID$ (S$,6, LEN (S$) - 5)
 330  IF  ASC ( RIGHT$ (W$,1)) <  > 47 THEN W$ = W$ + "/"
 340  GOTO 400

 350 W$ =  LEFT$ (W$, LEN (W$) - 1)
 360  IF  RIGHT$ (W$,1) <  > "/" GOTO 350
 370  GOTO 200

REM Call 2000 to create a size entry for this directory if it does not
REM exist.

 400 S$ = W$
 410  GOSUB 2000
 420  GOTO 200

 REM "ls" routine. Leave the loop if we reach the next command; skip dirs.

 500 V = 0
 510  GOSUB 4000
 515  IF  LEFT$ (S$,1) = "$" GOTO 210
 520  PRINT S$
 530  IF  LEFT$ (S$,3) = "dir" GOTO 510

REM Call 3000 to add file's size to relevant directorys' totals.

 540 V =  VAL (S$)
 550 S$ = W$
 560  GOSUB 3000
 570  GOTO 510

REM We will land here once the file has been completely read. Do the
REM search for part 1, summing into T.

 700 T = 0
 710  FOR I = 0 TO 199
 720  IF  LEN (DN$(I)) = 0 THEN I = 199: GOTO 740
 730  IF DS(I) <  = 100000 THEN T = T + DS(I)
 740  NEXT I
 745  PRINT 
 750  PRINT "part 1: ";T;" bytes"

REM Part 2 is at 5000. It will come back to 900 to exit.

 760  GOTO 5000

 900  PRINT  CHR$ (4),"CLOSE"
 910  SPEED= 255
 920  END 

REM Subroutine: Fetches the size of directory S$, putting it in V.

 1000 V = 0
 1010  FOR I = 0 TO 199
 1020  IF DN$(I) = S$ THEN V = DS(I):I = 199
 1030  NEXT I
 1040  RETURN 

REM Subroutine: Initializes new entry for directory S$.

 2000  FOR I = 0 TO 199
 2010  IF DN$(I) = S$ THEN  PRINT "ERROR": END 
 2020  IF  LEN (DN$(I)) = 0 THEN DN$(I) = S$:DS(I) = 0:I = 199
 2030  NEXT I
 2040  RETURN 

REM Subroutine: Adds size V to entry for directory S$ and its parents.

 3000  FOR I = 0 TO 199
 3010 L =  LEN (S$)
 3015 M =  LEN (DN$(I))
 3020  IF  LEN (DN$(I)) = 0 THEN I = 199: GOTO 3040
 3030  IF L >  = M AND  LEFT$ (S$,M) = DN$(I) GOTO 3060
 3040  NEXT I
 3050  RETURN 
 3060 DS(I) = DS(I) + V
 3080  GOTO 3040

REM Subroutine: Reads next line of input from the file.

 4000 S$ = ""
 4010  GET C$
 4020  IF  ASC (C$) < 32 GOTO 4050
 4030 S$ = S$ + C$
 4040  GOTO 4010
 4050  RETURN 

REM Part 2. Start by printing total filesystem size.

 5000  PRINT "$ ";
 5002  SPEED= 70: PRINT "df -h": SPEED= 170
 5004  FOR I = 0 TO 1000: NEXT I
 5006 S$ = "/"
 5010  GOSUB 1000
 5015  PRINT V

REM Calculate free memory requirements.

 5020 UN = 70000000 - V
 5030 RE = 30000000 - UN
 5040 DE = 99999999
 5100  PRINT "$";
 5110  SPEED= 70: PRINT " cleanup": SPEED= 170
 5120  FOR I = 0 TO 1000: NEXT I
 5130  PRINT "NEED TO FREE ";RE;" BYTES..."

REM The actual work: iterate for smallest entry that is at least RE bytes.

 5200  FOR I = 0 TO 199
 5210  IF  LEN (DN$(I)) = 0 THEN I = 199: GOTO 5230
 5220  IF DS(I) > RE AND DS(I) < DE THEN DE = DS(I)
 5230  NEXT I

REM All done!

 5240  PRINT "FREED ";DE;" BYTES."
 5250  GOTO 900

REM Debug subroutine: print all contents of directory/size map.

 6000  FOR I = 0 TO 199
 6010  IF  LEN (DN$(I)) = 0 THEN I = 199: GOTO 6030
 6020  PRINT DN$(I),DS(I)
 6030  NEXT I
 6040  RETURN