Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- PROGRAM DAY3
- TYPE NODE
- INTEGER :: LOCATION(2),TIME
- TYPE(NODE), POINTER :: NEXT => NULL()
- END TYPE NODE
- TYPE TABLE
- TYPE(NODE), POINTER :: NEXT => NULL()
- END TYPE TABLE
- TYPE(TABLE) :: VISITED(0:9999)
- INTEGER :: N1,N2,IERR,I,PART1,PART2,X,Y,T
- CHARACTER(LEN=10), ALLOCATABLE :: WIRE1(:),WIRE2(:)
- CHARACTER(LEN=1) :: CHAR
- ! Input
- OPEN(1,FILE="input.txt")
- N1=1
- DO
- READ(1,'(A1)',IOSTAT=IERR,ADVANCE="NO")CHAR
- IF(IERR.NE.0)EXIT
- IF(CHAR.EQ.",")N1=N1+1
- END DO
- REWIND(1)
- READ(1,*)
- N2=1
- DO
- READ(1,'(A1)',IOSTAT=IERR,ADVANCE="NO")CHAR
- IF(IERR.NE.0)EXIT
- IF(CHAR.EQ.",")N2=N2+1
- END DO
- REWIND(1)
- ALLOCATE(WIRE1(N1),WIRE2(N2))
- READ(1,*)WIRE1
- READ(1,*)WIRE2
- CLOSE(1)
- ! First wire
- PART1=0
- PART2=0
- T=0
- X=0
- Y=0
- DO I=1,SIZE(WIRE1)
- CALL RUN(WIRE1(I),X,Y,T,VISITED,1,PART1,PART2)
- END DO
- ! Second wire
- T=0
- X=0
- Y=0
- DO I=1,SIZE(WIRE2)
- CALL RUN(WIRE2(I),X,Y,T,VISITED,2,PART1,PART2)
- END DO
- ! Output
- WRITE(*,'("Part 1: ",I0)') PART1
- WRITE(*,'("Part 2: ",I0)') PART2
- CONTAINS
- SUBROUTINE RUN(INSTR,X,Y,T,VISITED,WIRE,PART1,PART2)
- ! Calculate points visited due to INSTR
- ! If wire 1, saves points in table
- ! If wire 2, checks for intersections with wire 1
- INTEGER, INTENT(INOUT) :: X,Y,T,PART1,PART2
- CHARACTER(LEN=*), INTENT(IN) :: INSTR
- INTEGER :: DIST,I,WIRE
- TYPE(TABLE), INTENT(INOUT) :: VISITED(:)
- READ(INSTR(2:),*)DIST
- DO I=1,DIST
- T=T+1
- SELECT CASE(INSTR(1:1))
- CASE("U")
- Y=Y+1
- CASE("D")
- Y=Y-1
- CASE("R")
- X=X+1
- CASE("L")
- X=X-1
- END SELECT
- IF(WIRE.EQ.1)THEN
- CALL ADD((/X,Y/),T,VISITED)
- ELSE
- CALL FIND((/X,Y/),T,VISITED,PART1,PART2)
- END IF
- END DO
- END SUBROUTINE RUN
- SUBROUTINE ADD(LOCATION,TIME,VISITED)
- ! Adds location and time to table if not yet visited
- INTEGER, INTENT(IN) :: LOCATION(2),TIME
- TYPE(TABLE), INTENT(INOUT) :: VISITED(:)
- INTEGER :: KEY
- TYPE(NODE), POINTER :: A
- KEY=MODULO(SUM(ABS(LOCATION)),SIZE(VISITED))
- IF(.NOT.ASSOCIATED(VISITED(KEY)%NEXT))THEN
- ALLOCATE(VISITED(KEY)%NEXT)
- A => VISITED(KEY)%NEXT
- A%LOCATION = LOCATION
- A%TIME = TIME
- RETURN
- END IF
- A => VISITED(KEY)%NEXT
- DO
- IF(ALL(LOCATION.EQ.A%LOCATION))RETURN
- IF(.NOT.ASSOCIATED(A%NEXT))EXIT
- A => A%NEXT
- END DO
- ALLOCATE(A%NEXT)
- A => A%NEXT
- A%LOCATION = LOCATION
- A%TIME = TIME
- END SUBROUTINE ADD
- SUBROUTINE FIND(LOCATION,TIME,VISITED,PART1,PART2)
- ! Checks for intersection with recorded points
- ! Updates answers if found
- INTEGER, INTENT(IN) :: LOCATION(2),TIME
- TYPE(TABLE), INTENT(INOUT) :: VISITED(:)
- INTEGER, INTENT(INOUT) :: PART1,PART2
- INTEGER :: KEY
- TYPE(NODE), POINTER :: A
- KEY=MODULO(SUM(ABS(LOCATION)),SIZE(VISITED))
- IF(.NOT.ASSOCIATED(VISITED(KEY)%NEXT))RETURN
- A => VISITED(KEY)%NEXT
- DO
- IF(ALL(LOCATION.EQ.A%LOCATION))EXIT
- IF(.NOT.ASSOCIATED(A%NEXT))RETURN
- A => A%NEXT
- END DO
- IF(PART1.EQ.0)PART1=SUM(ABS(LOCATION))
- PART1 = MIN(SUM(ABS(LOCATION)),PART1)
- IF(PART2.EQ.0)PART2=TIME+A%TIME
- PART2=MIN(TIME+A%TIME,PART2)
- END SUBROUTINE FIND
- END PROGRAM
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement