Advertisement
autid

AoC 2019 Day9 FORTRAN (intcode)

Dec 9th, 2019
1,760
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. PROGRAM INTCODE
  2.   USE MPI
  3.   TYPE NODE
  4.      INTEGER(8) :: VAL
  5.      INTEGER(8) :: LOCATION
  6.      TYPE(NODE),POINTER :: NEXT
  7.   END TYPE NODE
  8.   TYPE OP
  9.      PROCEDURE(), POINTER, NOPASS :: OP
  10.      INTEGER :: NARGS
  11.   END TYPE OP
  12.   INTEGER(8) :: I,IERR,MODES,OPCODE,A,B,C,D,E,PART1,PART2,RES,J
  13.   INTEGER :: N
  14.   INTEGER(8) :: LASTOUT,INSTR
  15.   CHARACTER(LEN=1) CHAR
  16.   TYPE(NODE),TARGET,ALLOCATABLE :: PROG(:)
  17.   INTEGER, ALLOCATABLE :: STOREDPROG(:)
  18.   TYPE(OP) :: OPS(9)
  19.   INTEGER :: IERROR, NPROC, ICOMM, IRANK,PARENT,REQUEST
  20.   INTEGER(8) :: RELBASE
  21.   LOGICAL :: AMROOT,RUNNING,SETUP,FIRST
  22.   INTEGER :: STATUS(MPI_STATUS_SIZE)
  23.  
  24.   CALL MPI_INIT(IERROR)
  25.   ICOMM = MPI_COMM_WORLD
  26.   CALL MPI_COMM_SIZE(ICOMM,NPROC,IERROR)
  27.   CALL MPI_COMM_RANK(ICOMM, IRANK, IERROR)
  28.   CALL MPI_COMM_GET_PARENT(PARENT, IERROR)
  29.   AMROOT = IRANK.EQ.0
  30.   OPS(1)%NARGS=3
  31.   OPS(1)%OP => ADD
  32.   OPS(2)%NARGS=3
  33.   OPS(2)%OP => MULTIPLY
  34.   OPS(3)%NARGS=1
  35.   OPS(3)%OP => INPUT
  36.   OPS(4)%NARGS=1
  37.   OPS(4)%OP => OUTPUT
  38.   OPS(5)%NARGS=2
  39.   OPS(5)%OP => JUMP_IF_TRUE
  40.   OPS(6)%NARGS=2
  41.   OPS(6)%OP => JUMP_IF_FALSE
  42.   OPS(7)%NARGS=3
  43.   OPS(7)%OP => LESS_THAN
  44.   OPS(8)%NARGS=3
  45.   OPS(8)%OP => EQUALS
  46.   OPS(9)%NARGS=1
  47.   OPS(9)%OP => UPDATE_RELATIVE_BASE
  48.  
  49.   CALL MPI_RECV(N,1,MPI_INTEGER,0,0,PARENT,STATUS,IERROR)
  50.   ALLOCATE(STOREDPROG(0:N))
  51.   CALL MPI_RECV(STOREDPROG,N,MPI_INTEGER,0,1,PARENT,STATUS,IERROR)
  52.  
  53.   RUNNING=.TRUE.
  54.   OUTER:DO
  55.      RELBASE=0
  56.      FIRST=.TRUE.
  57.      IF(ALLOCATED(PROG))DEALLOCATE(PROG)
  58.      ALLOCATE(PROG(0:N))
  59.      DO I=0,N
  60.         PROG(I)%VAL=STOREDPROG(I)
  61.         PROG(I)%LOCATION=I
  62.      END DO
  63.      SETUP=.TRUE.
  64.      I=0
  65.      DO
  66.         IF(.NOT.RUNNING)EXIT OUTER
  67.         INSTR = GETVAL(I)
  68.         MODES=INSTR/100
  69.         OPCODE=MODULO(INSTR,100)
  70.         IF(OPCODE.EQ.99)EXIT
  71.         CALL OPS(OPCODE)%OP(MODES,(/(GETVAL(J),J=I+1,I+OPS(OPCODE)%NARGS)/),I)
  72.      END DO
  73.      IF(AMROOT) THEN
  74.         CALL MPI_RECV(LASTOUT,1,MPI_DOUBLE_PRECISION,NPROC-1,3,ICOMM,STATUS,IERROR)
  75.         CALL MPI_SEND(LASTOUT,1,MPI_DOUBLE_PRECISION,0,999,PARENT,IERROR)
  76.      END IF
  77.   END DO OUTER
  78.   DEALLOCATE(PROG,STOREDPROG)
  79.   CALL MPI_FINALIZE(IERROR)
  80.  
  81.  
  82. CONTAINS
  83.   SUBROUTINE SETVAL(LOC,VAL)
  84.     INTEGER(8),INTENT(IN) :: LOC,VAL
  85.     INTEGER(8) :: KEY
  86.     TYPE(NODE),POINTER :: A
  87.     KEY=MODULO(LOC,SIZE(PROG))
  88.     A => PROG(KEY)
  89.     DO
  90.        IF(A%LOCATION.EQ.LOC)THEN
  91.           A%VAL=VAL
  92.           RETURN
  93.        END IF
  94.        IF(.NOT.ASSOCIATED(A%NEXT))THEN
  95.           ALLOCATE(A%NEXT)
  96.           A => A%NEXT
  97.           A%VAL=VAL
  98.           A%LOCATION=LOC
  99.           RETURN
  100.        END IF
  101.        A => A%NEXT
  102.     END DO
  103.   END SUBROUTINE SETVAL
  104.  
  105.   FUNCTION GETVAL(LOC) RESULT(VAL)
  106.     INTEGER(8) :: LOC,VAL
  107.     INTEGER (8) :: KEY
  108.     TYPE(NODE), POINTER :: A
  109.     KEY=MODULO(LOC,SIZE(PROG))
  110.     A=>PROG(KEY)
  111.     VAL=0
  112.     DO
  113.        IF(A%LOCATION.EQ.LOC)THEN
  114.           VAL=A%VAL
  115.           RETURN
  116.        ELSE IF(.NOT.ASSOCIATED(A%NEXT))THEN
  117.           RETURN
  118.        END IF
  119.        A => A%NEXT
  120.     END DO
  121.   END FUNCTION GETVAL
  122.    
  123.   FUNCTION RESOLVEPARAMS(MODES,PARAMS) RESULT(NEWPARAMS)
  124.     INTEGER(8) :: MODES
  125.     INTEGER(8) :: PARAMS(:), NEWPARAMS(SIZE(PARAMS))
  126.     INTEGER :: MODE(3)
  127.     INTEGER :: I
  128.     MODE(1)=MODULO(MODES,10)
  129.     MODE(2)=MODULO(MODES/10,10)
  130.     MODE(3)=MODES/100
  131.     DO I=1,SIZE(PARAMS)
  132.        SELECT CASE (MODE(I))
  133.        CASE (0)
  134.           IF(I.EQ.3)THEN
  135.              NEWPARAMS(I)=PARAMS(I)
  136.           ELSE
  137.              NEWPARAMS(I)=GETVAL(PARAMS(I))
  138.           END IF
  139.        CASE (1)
  140.           NEWPARAMS(I)=PARAMS(I)
  141.        CASE(2)
  142.           IF(I.EQ.3)THEN
  143.              NEWPARAMS(I)=PARAMS(I)+RELBASE
  144.           ELSE
  145.              NEWPARAMS(I)=GETVAL(PARAMS(I)+RELBASE)
  146.           END IF
  147.        END SELECT
  148.     END DO
  149.   END FUNCTION RESOLVEPARAMS
  150.          
  151.   SUBROUTINE ADD(MODES,PARAMS,I)
  152.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(3)
  153.     INTEGER(8) :: A,B
  154.     INTEGER(8), INTENT(INOUT) :: I
  155.     I=I+4
  156.  
  157.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  158.     CALL SETVAL(PARAMS(3),PARAMS(1)+PARAMS(2))
  159.   END SUBROUTINE ADD
  160.  
  161.   SUBROUTINE MULTIPLY(MODES,PARAMS,I)
  162.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(3)
  163.     INTEGER(8) :: A,B
  164.     INTEGER(8), INTENT(INOUT) :: I
  165.     I=I+4
  166.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  167.     CALL SETVAL(PARAMS(3),PARAMS(1)*PARAMS(2))
  168.   END SUBROUTINE MULTIPLY
  169.  
  170.   SUBROUTINE INPUT(MODES,PARAMS,I)
  171.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(1)
  172.     INTEGER(8) :: A
  173.     INTEGER(8), INTENT(INOUT) :: I
  174.     I=I+2
  175.     IF(MODULO(MODES,10).EQ.2)THEN
  176.        PARAMS(1)=PARAMS(1)+RELBASE
  177.     END IF
  178.     IF(SETUP)THEN
  179.        CALL MPI_RECV(A,1,MPI_DOUBLE_PRECISION,0,2,PARENT,STATUS,IERROR)
  180.        IF(A<0)RUNNING=.FALSE.
  181.        SETUP=.FALSE.
  182.     ELSE
  183.        IF(FIRST.AND.AMROOT)THEN
  184.           CALL MPI_RECV(A,1,MPI_DOUBLE_PRECISION,0,3,PARENT,STATUS,IERROR)
  185.           FIRST=.FALSE.
  186.        ELSE
  187.           CALL MPI_RECV(A,1,MPI_DOUBLE_PRECISION,MODULO(IRANK-1,NPROC),3,ICOMM,STATUS,IERROR)
  188.        END IF
  189.     END IF
  190.     CALL SETVAL(PARAMS(1),A)
  191.   END SUBROUTINE INPUT
  192.  
  193.   SUBROUTINE OUTPUT(MODES,PARAMS,I)
  194.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(1)
  195.     INTEGER(8) :: A,B
  196.     INTEGER(8), INTENT(INOUT) :: I
  197.     I=I+2
  198.  
  199.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  200.     A=PARAMS(1)
  201.     CALL MPI_ISEND(A,1,MPI_DOUBLE_PRECISION,MODULO(IRANK+1,NPROC),3,ICOMM,REQUEST,IERROR)
  202.     LASTOUT=PARAMS(1)
  203.   END SUBROUTINE OUTPUT
  204.  
  205.   SUBROUTINE JUMP_IF_TRUE(MODES,PARAMS,I)
  206.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(2)
  207.     INTEGER(8) :: A,B
  208.     INTEGER(8), INTENT(INOUT) :: I
  209.  
  210.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  211.     IF(PARAMS(1).NE.0)THEN
  212.        I=PARAMS(2)
  213.     ELSE
  214.        I=I+3
  215.     END IF
  216.   END SUBROUTINE JUMP_IF_TRUE
  217.  
  218.   SUBROUTINE JUMP_IF_FALSE(MODES,PARAMS,I)
  219.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(2)
  220.     INTEGER(8) :: A,B
  221.     INTEGER(8), INTENT(INOUT) :: I
  222.  
  223.     PARAMS =  RESOLVEPARAMS(MODES,PARAMS)
  224.     IF(PARAMS(1).EQ.0)THEN
  225.        I=PARAMS(2)
  226.     ELSE
  227.        I=I+3
  228.     END IF
  229.   END SUBROUTINE JUMP_IF_FALSE
  230.  
  231.   SUBROUTINE LESS_THAN(MODES,PARAMS,I)
  232.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(3)
  233.     INTEGER(8) :: A,B
  234.     INTEGER(8), INTENT(INOUT) :: I
  235.     I=I+4
  236.  
  237.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  238.     IF(PARAMS(1)<PARAMS(2))THEN
  239.        A=1
  240.        CALL SETVAL(PARAMS(3),A)
  241.     ELSE
  242.        A=0
  243.        CALL SETVAL(PARAMS(3),A)
  244.     END IF
  245.   END SUBROUTINE LESS_THAN
  246.  
  247.   SUBROUTINE EQUALS(MODES,PARAMS,I)
  248.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(3)
  249.     INTEGER(8) :: A,B
  250.     INTEGER(8), INTENT(INOUT) :: I
  251.     I=I+4
  252.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  253.     IF(PARAMS(1).EQ.PARAMS(2))THEN
  254.        A=1
  255.        CALL SETVAL(PARAMS(3),A)
  256.     ELSE
  257.        A=0
  258.        CALL SETVAL(PARAMS(3),A)
  259.     END IF
  260.   END SUBROUTINE EQUALS
  261.  
  262.   SUBROUTINE UPDATE_RELATIVE_BASE(MODES,PARAMS,I)
  263.     INTEGER(8), INTENT(INOUT) :: MODES, PARAMS(1)
  264.     INTEGER(8) :: A
  265.     INTEGER(8), INTENT(INOUT) :: I
  266.     I=I+2
  267.     PARAMS = RESOLVEPARAMS(MODES,PARAMS)
  268.     RELBASE = RELBASE + PARAMS(1)
  269.   END SUBROUTINE UPDATE_RELATIVE_BASE
  270.  
  271. END PROGRAM INTCODE
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement