To preface, I am incredibly new to COBOL, and have only been writing it for about a week.
I wrote a program that plays a Rock-Paper-Scissors (RPS) game and the computer randomly picks an option each turn.
Originally, I had the section that generates a random value in the same program, but I wanted to make a module out of it, since I didn't want to have to write that random number generation for each program I write.
The way I found on the internet to do this was to use CALL on the module I compiled, and feed it the necessary variables. However, while randomly generating a number, it also changed two variables that weren't related to the CALL: USER-WIN, COMP-WIN.
Here is the code for the RPS program:
IDENTIFICATION DIVISION.
PROGRAM-ID. ADVENT-RPS.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CHOICE.
03 USER-CHOICE PIC A(1).
03 COMP-CHOICE PIC A(1).
01 WIN.
03 COMP-WIN PIC 9 VALUE 0.
03 USER-WIN PIC 9 VALUE 0.
01 RAND.
03 UPPER-BOUND PIC 9 VALUE 3.
03 RAND-VAL PIC 9.
PROCEDURE DIVISION.
DISPLAY "Choose R, P, or S"
PERFORM UNTIL 1 = 0
*> ACCEPT USER INPUT FROM TERMINAL AND CHECK FOR CORRECTNESS
PERFORM USER-PIC
*> GENERATES RANDOM COMPUTER CHOICE
PERFORM COMP-PICK
*> CHECKS WHO WON THE ROUND AND IF SOMEONE WON THE GAME
PERFORM CHECK-WIN
END-PERFORM.
STOP RUN.
USER-PIC.
ACCEPT USER-CHOICE FROM CONSOLE.
IF (USER-CHOICE NOT = "R") AND
(USER-CHOICE NOT = "P") AND
(USER-CHOICE NOT = "S")
DISPLAY "Please choose a valid input (R, P, S)."
PERFORM USER-PIC
END-IF.
COMP-PICK.
*> CAUSING USER-WIN AND COMP-WIN TO CHANGE UNCONTROLLABLY
CALL "RAND" USING UPPER-BOUND, RAND-VAL.
IF RAND-VAL = 0
MOVE "R" TO COMP-CHOICE
ELSE
IF RAND-VAL = 1
MOVE "P" TO COMP-CHOICE
ELSE
MOVE "S" TO COMP-CHOICE
END-IF
END-IF.
DISPLAY "Computer chose: " COMP-CHOICE.
CHECK-WIN.
IF USER-CHOICE = COMP-CHOICE
DISPLAY "It's a tie!"
EXIT PARAGRAPH
ELSE
IF (USER-CHOICE = "R" AND COMP-CHOICE = "P") OR
(USER-CHOICE = "P" AND COMP-CHOICE = "S") OR
(USER-CHOICE = "S" AND COMP-CHOICE = "R")
DISPLAY "Computer beat you this round!"
COMPUTE COMP-WIN = COMP-WIN + 1
ELSE
DISPLAY "You beat the computer this round!"
COMPUTE USER-WIN = USER-WIN + 1
END-IF
END-IF.
IF USER-WIN = 2
DISPLAY "You won!"
STOP RUN.
IF COMP-WIN = 2
DISPLAY "Computer won!"
STOP RUN.
END PROGRAM ADVENT-RPS.
This is the random number generation program:
IDENTIFICATION DIVISION.
PROGRAM-ID. RAND.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SEED-STRING PIC X(16).
01 WS-SEED-INT PIC 9(16).
LINKAGE SECTION.
01 UPPER-BOUND PIC 9(38).
01 RAND-VAL PIC 9(38).
PROCEDURE DIVISION USING UPPER-BOUND, RAND-VAL.
MOVE FUNCTION CURRENT-DATE TO WS-SEED-STRING.
MOVE FUNCTION NUMVAL(WS-SEED-STRING) TO WS-SEED-INT.
COMPUTE RAND-VAL = FUNCTION RANDOM(WS-SEED-INT) * UPPER-BOUND.
EXIT PROGRAM.
I am using the GnuCOBOL compiler and used cobc -m -free RAND.COBOL
to compile the random number generator and cobc -x -free RPS.COBOL
to compile the RPS program. I am on Linux Mint Xfce if that is also important.
I tried putting variables on different levels, thinking that would change something, and it didn't. I also added the random number generator code back in to the RPS code, and it work perfectly fine then.
I also tried changing the size of UPPER-BOUND and RAND-VAL in the RAND program, and I found that if they are declared as size 9(15) and lower they work perfectly fine.
I think this has something to do with the RAND program overwriting memory that is used for COMP-WIN and USER-WIN, however I don't know if that is the case, and would like to know why this occurs and how to prevent similar thing in the future.
Additionally, I don't understand why changing the sizes of UPPER-BOUND and RAND-VAL in RAND fixes the issue. Does it have something to do with the size of WS-SEED-INT and what the RANDOM function returns?