Task: Forest fire



C#: using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;

namespace ForestFire
{
    class Program : Form
    {
        private static readonly Random rand = new Random();
        private Bitmap img;

        public Program(int w, int h, int f, int p)
        {
            Size = new Size(w, h);
            StartPosition = FormStartPosition.CenterScreen;

            Thread t = new Thread(() => fire(f, p));
            t.Start();

            FormClosing += (object sender, FormClosingEventArgs e) => { t.Abort(); t = null; };
        }

        private void fire(int f, int p)
        {
            int clientWidth = ClientRectangle.Width;
            int clientHeight = ClientRectangle.Height;
            int cellSize = 10;

            img = new Bitmap(clientWidth, clientHeight);
            Graphics g = Graphics.FromImage(img);

            CellState[,] state = InitializeForestFire(clientWidth, clientHeight);

            uint generation = 0;

            do
            {
                g.FillRectangle(Brushes.White, 0, 0, img.Width, img.Height);
                state = StepForestFire(state, f, p);

                for (int y = 0; y < clientHeight - cellSize; y += cellSize)
                {
                    for (int x = 0; x < clientWidth - cellSize; x += cellSize)
                    {
                        switch (state[y, x])
                        {
                            case CellState.Empty:
                                break;
                            case CellState.Tree:
                                g.FillRectangle(Brushes.DarkGreen, x, y, cellSize, cellSize);
                                break;
                            case CellState.Burning:
                                g.FillRectangle(Brushes.DarkRed, x, y, cellSize, cellSize);
                                break;
                        }
                    }
                }

                Thread.Sleep(500);

                Invoke((MethodInvoker)Refresh);

            } while (generation < uint.MaxValue);

            g.Dispose();
        }

        private CellState[,] InitializeForestFire(int width, int height)
        {
            
            var state = new CellState[height, width];
            state.Initialize();
            return state;
        }

        private enum CellState : byte
        {
            Empty = 0,
            Tree = 1,
            Burning = 2
        }

        private CellState[,] StepForestFire(CellState[,] state, int f, int p)
        {
            
            var newState = (CellState[,])state.Clone();

            int numRows = state.GetLength(0);
            int numCols = state.GetLength(1);

            for (int r = 1; r < numRows - 1; r++)
            {
                for (int c = 1; c < numCols - 1; c++)
                {
                    
                    switch (state[r, c])
                    {
                        case CellState.Empty:
                            if (rand.Next(0, p) == 0)
                                newState[r, c] = CellState.Tree;
                            break;

                        case CellState.Tree:
                            if (NeighborHasState(state, r, c, CellState.Burning) || rand.Next(0, f) == 0)
                                newState[r, c] = CellState.Burning;
                            break;

                        case CellState.Burning:
                            newState[r, c] = CellState.Empty;
                            break;
                    }
                }
            }

            return newState;
        }

        private bool NeighborHasState(CellState[,] state, int x, int y, CellState value)
        {
            
            for (int r = -1; r <= 1; r++)
            {
                for (int c = -1; c <= 1; c++)
                {
                    if (r == 0 && c == 0)
                        continue;

                    if (state[x + r, y + c] == value)
                        return true;
                }
            }

            return false;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.DrawImage(img, 0, 0);
        }

        [STAThread]
        static void Main(string[] args)
        {
            Application.Run(new Program(w: 500, h: 500, f: 2, p: 5));
        }
    }
}







COBOL:        IDENTIFICATION DIVISION.
       PROGRAM-ID. forest-fire.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       
       
       
       78  IGNITE-PROB                 VALUE 1.
       78  NEW-TREE-PROB               VALUE 100.

       78  EMPTY-PROB                  VALUE 3333.

       78  AREA-SIZE                   VALUE 40.

       01  sim-table.
           03  sim-row OCCURS AREA-SIZE TIMES INDEXED BY row-index.
               05  sim-area OCCURS AREA-SIZE TIMES
                   INDEXED BY col-index.
                   07  current-status  PIC 9.
                       
                       
                       88  empty       VALUE 0. 
                       88  tree        VALUE 2. 
                       88  burning     VALUE 4. 
                       
                   07  next-status     PIC 9.
                       88  empty       VALUE 0.
                       88  tree        VALUE 2.
                       88  burning     VALUE 4.
    
       01  rand-num                    PIC 9999.
        
       01  next-row                    PIC 9(4).
       01  next-col                    PIC 9(4).

       01  neighbours-row              PIC 9(4).
       01  neighbours-col              PIC 9(4).

       PROCEDURE DIVISION.
       main-line.
           
           MOVE FUNCTION RANDOM(FUNCTION CURRENT-DATE (9:8)) TO rand-num

           PERFORM initialise-table
           PERFORM FOREVER
               PERFORM show-simulation
               PERFORM step-simulation
           END-PERFORM

           GOBACK
           .

       initialise-table.
           PERFORM VARYING row-index FROM 1 BY 1
                   UNTIL AREA-SIZE < row-index
                   AFTER col-index FROM 1 BY 1
                       UNTIL AREA-SIZE < col-index
               PERFORM get-rand-num
               IF rand-num <= EMPTY-PROB
                   SET empty OF current-status (row-index, col-index)
                       TO TRUE
                   SET empty OF next-status (row-index, col-index)
                       TO TRUE
               ELSE
                   SET tree OF current-status (row-index, col-index)
                       TO TRUE
                   SET tree OF next-status (row-index, col-index)
                       TO TRUE
               END-IF
           END-PERFORM
           .

       show-simulation.
           PERFORM VARYING row-index FROM 1 BY 1
                   UNTIL AREA-SIZE < row-index
                   AFTER col-index FROM 1 BY 1
                       UNTIL AREA-SIZE < col-index
                DISPLAY SPACE AT LINE row-index COLUMN col-index
                    WITH BACKGROUND-COLOR
                        current-status (row-index, col-index)
           END-PERFORM
           .

       
       step-simulation.
            PERFORM VARYING row-index FROM 1 BY 1
                   UNTIL AREA-SIZE < row-index
                   AFTER col-index FROM 1 BY 1
                       UNTIL AREA-SIZE < col-index
                EVALUATE TRUE
                    WHEN empty OF current-status (row-index, col-index)
                        PERFORM get-rand-num
                        IF rand-num <= NEW-TREE-PROB
                            SET tree OF next-status
                                 (row-index, col-index) TO TRUE
                        END-IF

                    WHEN tree OF current-status (row-index, col-index)
                        PERFORM simulate-tree

                    WHEN burning OF current-status
                            (row-index, col-index)
                        SET empty OF next-status (row-index, col-index)
                            TO TRUE
                END-EVALUATE
            END-PERFORM

            PERFORM update-statuses.
            .

       
       
       simulate-tree.
           
           COMPUTE next-row = FUNCTION MIN(row-index + 1, AREA-SIZE)
           COMPUTE next-col = FUNCTION MIN(col-index + 1, AREA-SIZE)
           
           COMPUTE neighbours-row = FUNCTION MAX(row-index - 1, 1)
           COMPUTE neighbours-col = FUNCTION MAX(col-index - 1, 1)

           
           PERFORM VARYING neighbours-row FROM neighbours-row BY 1
                   UNTIL next-row < neighbours-row
               
               PERFORM VARYING neighbours-col FROM neighbours-col BY 1
                       UNTIL next-col < neighbours-col
                   IF neighbours-row = row-index
                           AND neighbours-col = col-index
                       EXIT PERFORM CYCLE
                   END-IF
                   
                   IF burning OF current-status
                           (neighbours-row, neighbours-col)
                       SET burning OF next-status (row-index, col-index)
                           TO TRUE
                       EXIT PARAGRAPH
                   END-IF
               END-PERFORM

               
               COMPUTE neighbours-col =
                   FUNCTION MAX(neighbours-col - 3, 1)
           END-PERFORM

           
           
           PERFORM get-rand-num
           IF rand-num <= IGNITE-PROB
               SET burning OF next-status (row-index, col-index) TO TRUE
           END-IF
           .

       update-statuses.
           PERFORM VARYING row-index FROM 1 BY 1
                   UNTIL AREA-SIZE < row-index
                   AFTER col-index FROM 1 BY 1
                       UNTIL AREA-SIZE < col-index
               MOVE next-status (row-index, col-index)
                   TO current-status (row-index, col-index)
           END-PERFORM
           .

       
       get-rand-num.
           COMPUTE rand-num =
               FUNCTION MOD(FUNCTION RANDOM * 100000, 10000)
           .