Advertisement
autid

AoC 2018 Day15 FORTRAN

Dec 15th, 2018
948
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. PROGRAM DAY15
  2.   TYPE GOBLIN
  3.      INTEGER :: POSITION(2)
  4.      INTEGER :: ATTACK=3
  5.      INTEGER :: HEALTH=200
  6.   END TYPE GOBLIN
  7.   TYPE ELF
  8.      INTEGER :: POSITION(2)
  9.      INTEGER :: ATTACK=3
  10.      INTEGER :: HEALTH=200
  11.   END TYPE ELF
  12.   INTEGER :: I,J,K,E,G,X,Y,IERR,STEPS,A
  13.   CHARACTER(LEN=1),ALLOCATABLE :: GRID(:,:),STARTGRID(:,:)
  14.   LOGICAL, ALLOCATABLE :: MOVED(:,:),TARGETSQUARE(:,:)
  15.   INTEGER, ALLOCATABLE :: DISTANCES(:,:)
  16.   CHARACTER(LEN=1) :: TEST
  17.   CHARACTER(LEN=:), ALLOCATABLE :: INLINE
  18.   TYPE(GOBLIN), ALLOCATABLE,TARGET :: GOBLINS(:)
  19.   TYPE(ELF), ALLOCATABLE,TARGET :: ELVES(:)
  20.  
  21.   OPEN(1,FILE='INPUT.TXT')
  22.   X=0
  23.   DO
  24.      READ(1,'(A)',ADVANCE='NO',IOSTAT=IERR)TEST
  25.      IF(IERR.NE.0)EXIT
  26.      X=X+1
  27.   END DO
  28.   REWIND(1)
  29.   Y=0
  30.   DO
  31.      READ(1,*,IOSTAT=IERR)
  32.      IF(IERR.NE.0)EXIT
  33.      Y=Y+1
  34.   END DO
  35.   REWIND(1)
  36.   ALLOCATE(GRID(X,Y),DISTANCES(X,Y),MOVED(X,Y),TARGETSQUARE(X,Y),STARTGRID(X,Y))
  37.   ALLOCATE(CHARACTER(LEN=X) :: INLINE)
  38.   E=0
  39.   G=0
  40.   DO J=1,Y
  41.      READ(1,'(A)')INLINE
  42.      DO I=1,X
  43.         GRID(I,J)=INLINE(I:I)
  44.         IF(INLINE(I:I).EQ.'E')E=E+1
  45.         IF(INLINE(I:I).EQ.'G')G=G+1
  46.      END DO
  47.   END DO
  48.   CLOSE(1)
  49.   ALLOCATE(ELVES(E),GOBLINS(G))
  50.  
  51.   A=3
  52.   STARTGRID=GRID
  53.   DO
  54.      GRID=STARTGRID
  55.      E=1
  56.      G=1
  57.      DO J=1,Y
  58.         DO I=1,X
  59.            IF(GRID(I,J).EQ.'E')THEN
  60.               ELVES(E)%POSITION=(/I,J/)
  61.               ELVES(E)%HEALTH=200
  62.               ELVES(E)%ATTACK=A
  63.               E=E+1
  64.            ELSEIF(GRID(I,J).EQ.'G')THEN
  65.               GOBLINS(G)%POSITION=(/I,J/)
  66.               GOBLINS(G)%HEALTH=200
  67.               G=G+1
  68.            END IF
  69.         END DO
  70.      END DO
  71.      MOVED=.FALSE.
  72.      STEPS=0
  73.      OUTER:DO
  74.         DO J=1,Y
  75.            DO I=1,X
  76.               IF(SCAN(GRID(I,J),'.#').NE.0)CYCLE
  77.               IF(MOVED(I,J))CYCLE
  78.               CALL MOVE((/I,J/),GRID(I,J))
  79.               IF(COUNT(GRID.EQ.'E').EQ.0)EXIT OUTER
  80.               IF(COUNT(GRID.EQ.'G').EQ.0)EXIT OUTER
  81.            END DO
  82.         END DO
  83.         MOVED=.FALSE.
  84.         STEPS=STEPS+1
  85.        
  86.      END DO OUTER
  87.      J=0
  88.      DO I=1,SIZE(ELVES,DIM=1)
  89.         IF(ELVES(I)%HEALTH>0)J=J+ELVES(I)%HEALTH
  90.      END DO
  91.      DO I=1,SIZE(GOBLINS,DIM=1)
  92.         IF(GOBLINS(I)%HEALTH>0)J=J+GOBLINS(I)%HEALTH
  93.      END DO
  94.      IF(A.EQ.3)WRITE(*,'("PART 1: ",I0)') STEPS*J
  95.      IF(ALL((/(ELVES(I)%HEALTH,I=1,SIZE(ELVES,DIM=1))/)>0))EXIT
  96.      A=A+1
  97.   END DO
  98.   WRITE(*,'("PART 2: ",I0)') STEPS*J
  99. CONTAINS
  100.   SUBROUTINE MOVE(POS,TEAM)
  101.     INTEGER, INTENT(IN) :: POS(2)
  102.     CHARACTER(LEN=1), INTENT(IN) :: TEAM
  103.     CHARACTER(LEN=1) :: OPPOSITION
  104.     INTEGER :: I,J,K,NEWPOS(2)
  105.     IF(TEAM.EQ.'E')OPPOSITION='G'
  106.     IF(TEAM.EQ.'G')OPPOSITION='E'
  107.     NEWPOS=POS
  108.     IF(.NOT.ANY((/GRID(POS(1)-1:POS(1)+1,POS(2)),GRID(POS(1),POS(2)-1:POS(2)+1)/).EQ.OPPOSITION))THEN
  109.        TARGETSQUARE=.FALSE.
  110.        DO J=2,Y-1
  111.           DO I=2,X-1
  112.              IF(GRID(I,J).EQ.OPPOSITION)THEN
  113.                 IF(GRID(I-1,J).EQ.'.')TARGETSQUARE(I-1,J)=.TRUE.
  114.                 IF(GRID(I+1,J).EQ.'.')TARGETSQUARE(I+1,J)=.TRUE.
  115.                 IF(GRID(I,J-1).EQ.'.')TARGETSQUARE(I,J-1)=.TRUE.
  116.                 IF(GRID(I,J+1).EQ.'.')TARGETSQUARE(I,J+1)=.TRUE.
  117.              END IF
  118.           END DO
  119.        END DO
  120.        DISTANCES=X*Y
  121.        WHERE(TARGETSQUARE)DISTANCES=0
  122.        DO K=1,COUNT(GRID.EQ.'.')
  123.           DO J=2,Y-1
  124.              DO I=2,X-1
  125.                 IF(GRID(I,J).EQ.'.')THEN
  126.                    DISTANCES(I,J)=MIN(DISTANCES(I,J),MINVAL((/DISTANCES(I-1:I+1,J),DISTANCES(I,J-1:J+1)/))+1)
  127.                 END IF
  128.              END DO
  129.           END DO
  130.        END DO
  131.        K=MINVAL((/DISTANCES(POS(1)-1:POS(1)+1,POS(2)),DISTANCES(POS(1),POS(2)-1:POS(2)+1)/))
  132.        IF(DISTANCES(POS(1),POS(2)).EQ.K)THEN
  133.          
  134.        ELSEIF(DISTANCES(POS(1),POS(2)-1).EQ.K)THEN
  135.           NEWPOS=POS+(/0,-1/)
  136.        ELSEIF(DISTANCES(POS(1)-1,POS(2)).EQ.K)THEN
  137.           NEWPOS=POS+(/-1,0/)
  138.        ELSEIF(DISTANCES(POS(1)+1,POS(2)).EQ.K)THEN
  139.           NEWPOS=POS+(/1,0/)
  140.        ELSEIF(DISTANCES(POS(1),POS(2)+1).EQ.K)THEN
  141.           NEWPOS=POS+(/0,+1/)
  142.        END IF
  143.     END IF
  144.     GRID(POS(1),POS(2))='.'
  145.     GRID(NEWPOS(1),NEWPOS(2))=TEAM
  146.     IF(TEAM.EQ.'E')THEN
  147.        DO I=1,SIZE(ELVES,DIM=1)
  148.           IF(ALL(ELVES(I)%POSITION.EQ.POS))ELVES(I)%POSITION=NEWPOS
  149.        END DO
  150.     ELSE
  151.        DO I=1,SIZE(GOBLINS,DIM=1)
  152.           IF(ALL(GOBLINS(I)%POSITION.EQ.POS))GOBLINS(I)%POSITION=NEWPOS
  153.        END DO
  154.     END IF
  155.     CALL ATTACK(NEWPOS,TEAM,OPPOSITION)
  156.     MOVED(NEWPOS(1),NEWPOS(2))=.TRUE.
  157.   END SUBROUTINE MOVE
  158.  
  159.   SUBROUTINE ATTACK(POS,TEAM,OPPOSITION)
  160.     INTEGER, INTENT(IN) :: POS(2)
  161.     CHARACTER(LEN=1), INTENT(IN) :: TEAM,OPPOSITION
  162.     TYPE(ELF),POINTER :: ELFO
  163.     TYPE(GOBLIN), POINTER :: GOBBO
  164.     INTEGER :: LOWESTHEALTH,I,J,K
  165.    
  166.     ELFO=>NULL()
  167.     GOBBO=>NULL()
  168.     LOWESTHEALTH = MAXVAL((/GOBLINS%HEALTH,ELVES%HEALTH/))+1
  169.     IF(TEAM.EQ.'E')THEN
  170.        DO I=1,SIZE(ELVES,DIM=1)
  171.           IF(ALL(ELVES(I)%POSITION.EQ.POS))ELFO => ELVES(I)
  172.        END DO
  173.        DO J=-1,1
  174.           DO I=-1,1
  175.              IF((I.NE.0).AND.(J.NE.0))CYCLE
  176.              IF(GRID(POS(1)+I,POS(2)+J).NE.'G')CYCLE
  177.              DO K=1,SIZE(GOBLINS,DIM=1)
  178.                 IF(ANY(GOBLINS(K)%POSITION.NE.(/POS(1)+I,POS(2)+J/)))CYCLE
  179.                 IF(GOBLINS(K)%HEALTH<LOWESTHEALTH)THEN
  180.                    GOBBO => GOBLINS(K)
  181.                    LOWESTHEALTH = GOBBO%HEALTH
  182.                 END IF
  183.              END DO
  184.           END DO
  185.        END DO
  186.        IF(ASSOCIATED(GOBBO))THEN
  187.           GOBBO%HEALTH=GOBBO%HEALTH-ELFO%ATTACK
  188.           IF(GOBBO%HEALTH.LE.0)THEN
  189.              GRID(GOBBO%POSITION(1),GOBBO%POSITION(2))='.'
  190.              GOBBO%POSITION=(/0,0/)
  191.           END IF
  192.        END IF
  193.     ELSE
  194.        DO I=1,SIZE(GOBLINS,DIM=1)
  195.           IF(ALL(GOBLINS(I)%POSITION.EQ.POS))GOBBO => GOBLINS(I)
  196.        END DO
  197.        DO J=-1,1
  198.           DO I=-1,1
  199.              IF((I.NE.0).AND.(J.NE.0))CYCLE
  200.              IF(GRID(POS(1)+I,POS(2)+J).NE.'E')CYCLE
  201.              DO K=1,SIZE(ELVES,DIM=1)
  202.                 IF(ANY(ELVES(K)%POSITION.NE.(/POS(1)+I,POS(2)+J/)))CYCLE
  203.                 IF(ELVES(K)%HEALTH<LOWESTHEALTH)THEN
  204.                    ELFO => ELVES(K)
  205.                    LOWESTHEALTH = ELFO%HEALTH
  206.                 END IF
  207.              END DO
  208.           END DO
  209.        END DO
  210.        IF(ASSOCIATED(ELFO))THEN
  211.           ELFO%HEALTH=ELFO%HEALTH-GOBBO%ATTACK
  212.           IF(ELFO%HEALTH.LE.0)THEN
  213.              GRID(ELFO%POSITION(1),ELFO%POSITION(2))='.'
  214.              ELFO%POSITION=(/0,0/)
  215.           END IF
  216.        END IF
  217.     END IF
  218.   END SUBROUTINE ATTACK
  219. END PROGRAM DAY15
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement