1- ! =======================================================
2- ! Conway's game of life
3- !
4- ! =======================================================
5- ! Adapted from https://github.com/tuckerrc/game_of_life
6- ! =======================================================
7- program game_of_life
8-
1+ module game_of_life
2+ use animation, only : draw_board
93 implicit none
10-
11- logical , parameter :: animate = .true.
12- integer , dimension (:,:), allocatable :: starting_board
13- integer :: generation_number
14- logical :: steady_state = .false.
15-
16- ! ! CLI args
17- character (len= :), allocatable :: executable_name, input_filename
18-
19- ! Get current_board file path from command line
20- if (command_argument_count() == 1 ) then
21- call read_cli_arg(1 , input_filename)
22- else
23- write (* ,' (A)' ) " Error: Invalid input"
24- call read_cli_arg(0 , executable_name)
25- write (* ,' (A,A,A)' ) " Usage: " , executable_name, " <input_file_name>"
26- stop
27- end if
28-
29- call read_model_from_file(input_filename, starting_board)
30-
31- call find_steady_state(steady_state, generation_number, starting_board, animate)
32-
33- if (steady_state) then
34- write (* ,' (a,i6,a)' ) " Reached steady after " , generation_number, " generations"
35- else
36- write (* ,' (a,i6,a)' ) " Did NOT Reach steady after " , generation_number, " generations"
37- end if
4+ public
385
396contains
407
41- ! > Read a cli arg at a given index and return it as a string (character array)
42- subroutine read_cli_arg (arg_index , arg )
43- ! > The index of the cli arg to try and read
44- integer , intent (in ) :: arg_index
45- ! > The string into which to store the cli arg
46- character (len= :), allocatable , intent (out ) :: arg
47-
48- integer :: argl
49- character (len= :), allocatable :: cli_arg_temp_store
50-
51- call get_command_argument(arg_index, length= argl)
52- allocate (character (argl) :: cli_arg_temp_store)
53- call get_command_argument(arg_index, cli_arg_temp_store)
54- arg = trim (cli_arg_temp_store)
55- end subroutine read_cli_arg
56-
57- ! > Populate the board from a provided file
58- subroutine read_model_from_file (input_filename , board )
59- character (len= :), allocatable , intent (in ) :: input_filename
60- integer , dimension (:,:), allocatable , intent (out ) :: board
61-
62- ! > A flag to indicate if reading the file was successful
63- character (len= :), allocatable :: io_error_message
64-
65- ! Board definition args
66- integer :: row, nrow, ncol
67- integer , parameter :: max_nrows = 100 , max_ncols = 100
68-
69- ! File IO args
70- integer :: input_file_io, iostat
71- character (len= 80 ) :: text_to_discard
72-
73- input_file_io = 1111
74-
75- ! Open input file
76- open (unit= input_file_io, &
77- file= input_filename, &
78- status= ' old' , &
79- IOSTAT= iostat)
80-
81- if ( iostat == 0 ) then
82- ! Read in board from file
83- read (input_file_io,' (a)' ) text_to_discard ! Skip first line
84- read (input_file_io,* ) nrow, ncol
85-
86- ! Verify the number of rows and columns read from the file
87- if (nrow < 1 .or. nrow > max_nrows) then
88- allocate (character (100 ) :: io_error_message)
89- write (io_error_message,' (a,i6,a,i6)' ) " nrow must be a positive integer less than " , max_nrows, " found " , nrow
90- elseif (ncol < 1 .or. ncol > max_ncols) then
91- allocate (character (100 ) :: io_error_message)
92- write (io_error_message,' (a,i6,a,i6)' ) " ncol must be a positive integer less than " , max_ncols, " found " , ncol
93- end if
94- else
95- allocate (character (100 ) :: io_error_message)
96- write (io_error_message,' (a)' ) ' *** Error when opening ' // input_filename
97- endif
98-
99- if (.not. allocated (io_error_message)) then
100-
101- allocate (board(nrow, ncol))
102-
103- read (input_file_io,' (a)' ) text_to_discard ! Skip next line
104- ! Populate the boards starting state
105- do row = 1 , nrow
106- read (input_file_io,* ) board(row, :)
107- end do
108-
109- end if
110-
111- close (input_file_io)
112-
113- if (allocated (io_error_message)) then
114- write (* ,* ) io_error_message
115- deallocate (io_error_message)
116- stop
117- end if
118- end subroutine read_model_from_file
119-
1208 ! > Find the steady state of the Game of Life board
1219 subroutine find_steady_state (steady_state , generation_number , input_board , animate )
12210 ! > Whether the board has reached a steady state
@@ -230,33 +118,4 @@ subroutine check_for_steady_state(steady_state, current_board, new_board)
230118 steady_state = .true.
231119 end subroutine check_for_steady_state
232120
233- ! > Output the current board to the terminal
234- subroutine draw_board (board )
235- ! > The current state of the board
236- integer , dimension (:,:), allocatable , intent (in ) :: board
237-
238- integer :: row, col, nrow, ncol
239- character (:), allocatable :: output
240-
241- nrow = size (board, 1 )
242- ncol = size (board, 2 )
243-
244- allocate (character (nrow) :: output)
245-
246- ! Clear the terminal screen
247- call system(" clear" )
248-
249- do row= 1 , nrow
250- output = " "
251- do col= 1 , ncol
252- if (board(row,col) == 1 ) then
253- output = trim (output)// " #"
254- else
255- output = trim (output)// " ."
256- endif
257- enddo
258- print * , output
259- enddo
260- end subroutine draw_board
261-
262- end program game_of_life
121+ end module game_of_life
0 commit comments