Task: Forest fire








VB: Public Class ForestFire
    Private _forest(,) As ForestState
    Private _isBuilding As Boolean
    Private _bm As Bitmap
    Private _gen As Integer
    Private _sw As Stopwatch

    Private Const _treeStart As Double = 0.5
    Private Const _f As Double = 0.00001
    Private Const _p As Double = 0.001

    Private Const _winWidth As Integer = 300
    Private Const _winHeight As Integer = 300

    Private Enum ForestState
        Empty
        Burning
        Tree
    End Enum

    Private Sub ForestFire_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(_winWidth, _winHeight)
        ReDim _forest(_winWidth, _winHeight)

        Dim rnd As New Random()
        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                _forest(j, i) = IIf(rnd.NextDouble <= _treeStart, ForestState.Tree, ForestState.Empty)
            Next
        Next

        _sw = New Stopwatch
        _sw.Start()
        DrawForest()
        Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If _isBuilding Then Exit Sub

        _isBuilding = True
        GetNextGeneration()

        DrawForest()
        _isBuilding = False
    End Sub

    Private Sub GetNextGeneration()
        Dim forestCache(_winWidth, _winHeight) As ForestState
        Dim rnd As New Random()

        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                Select Case _forest(j, i)
                    Case ForestState.Tree
                        If forestCache(j, i) <> ForestState.Burning Then
                            forestCache(j, i) = IIf(rnd.NextDouble <= _f, ForestState.Burning, ForestState.Tree)
                        End If

                    Case ForestState.Burning
                        For i2 As Integer = i - 1 To i + 1
                            If i2 = -1 OrElse i2 >= _winHeight Then Continue For
                            For j2 As Integer = j - 1 To j + 1
                                If j2 = -1 OrElse i2 >= _winWidth Then Continue For
                                If _forest(j2, i2) = ForestState.Tree Then forestCache(j2, i2) = ForestState.Burning
                            Next
                        Next
                        forestCache(j, i) = ForestState.Empty

                    Case Else
                        forestCache(j, i) = IIf(rnd.NextDouble <= _p, ForestState.Tree, ForestState.Empty)
                End Select
            Next
        Next

        _forest = forestCache
        _gen += 1
    End Sub

    Private Sub DrawForest()
        Dim bmCache As New Bitmap(_winWidth, _winHeight)

        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                Select Case _forest(j, i)
                    Case ForestState.Tree
                        bmCache.SetPixel(j, i, Color.Green)

                    Case ForestState.Burning
                        bmCache.SetPixel(j, i, Color.Red)
                End Select
            Next
        Next

        _bm = bmCache
        Me.Refresh()
    End Sub

    Private Sub ForestFire_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        e.Graphics.DrawImage(_bm, 0, 0)

        Me.Text = "Gen " & _gen.ToString() & " @ " & (_gen / (_sw.ElapsedMilliseconds / 1000)).ToString("F02") & " FPS: Forest Fire"
    End Sub
End Class


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)
           .