Task: Brownian tree




Go: package main

import (
    "fmt"
    "image"
    "image/color"
    "image/png"
    "math/rand"
    "os"
)

const w = 400     
const h = 300     
const n = 15000   
const frost = 255 

var g *image.Gray

func main() {
    g = image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{w, h}})
    
    g.SetGray(w/3, h/3, color.Gray{frost})
generate:
    for a := 0; a < n; {
        
        rp := image.Point{rand.Intn(w), rand.Intn(h)}
        if g.At(rp.X, rp.Y).(color.Gray).Y == frost {
            
            for {
                rp.X += rand.Intn(3) - 1
                rp.Y += rand.Intn(3) - 1
                
                if !rp.In(g.Rect) {
                    continue generate
                }
                if g.At(rp.X, rp.Y).(color.Gray).Y != frost {
                    break
                }
            }
        } else {
            
            
            for !hasNeighbor(rp) {
                rp.X += rand.Intn(3) - 1
                rp.Y += rand.Intn(3) - 1
                
                if !rp.In(g.Rect) {
                    continue generate
                }
            }
        }
        
        g.SetGray(rp.X, rp.Y, color.Gray{frost})
        a++
        
        if a%100 == 0 {
            fmt.Println(a, "of", n)
        }
    }
    f, err := os.Create("tree.png")
    if err != nil {
        fmt.Println(err)
        return
    }
    err = png.Encode(f, g)
    if err != nil {
        fmt.Println(err)
    }
    f.Close()
}

var n8 = []image.Point{
    {-1, -1}, {-1, 0}, {-1, 1},
    {0, -1}, {0, 1},
    {1, -1}, {1, 0}, {1, 1}}

func hasNeighbor(p image.Point) bool { 
    for _, n := range n8 {
        o := p.Add(n)
        if o.In(g.Rect) && g.At(o.X, o.Y).(color.Gray).Y == frost {
            return true
        }
    }
    return false
}








Ada: with Ada.Numerics.Discrete_Random;

with SDL.Video.Windows.Makers;
with SDL.Video.Renderers.Makers;
with SDL.Events.Events;

procedure Brownian_Tree is

   Width   : constant := 800;
   Height  : constant := 600;
   Points  : constant := 50_000;

   subtype Width_Range  is Integer range 1 .. Width;
   subtype Height_Range is Integer range 1 .. Height;
   type    Direction    is (N, NE, E, SE, S, SW, W, NW);
   package Random_Width   is new Ada.Numerics.Discrete_Random (Width_Range);
   package Random_Height  is new Ada.Numerics.Discrete_Random (Height_Range);
   package Random_Direc   is new Ada.Numerics.Discrete_Random (Direction);

   Window   : SDL.Video.Windows.Window;
   Renderer : SDL.Video.Renderers.Renderer;
   Event    : SDL.Events.Events.Events;

   Width_Gen  : Random_Width.Generator;
   Height_Gen : Random_Height.Generator;
   Direc_Gen  : Random_Direc.Generator;

   function Poll_Quit return Boolean is
      use type SDL.Events.Event_Types;
   begin
      while SDL.Events.Events.Poll (Event) loop
         if Event.Common.Event_Type = SDL.Events.Quit then
            return True;
         end if;
      end loop;
      return False;
   end Poll_Quit;

   procedure Draw_Brownian_Tree is
      Field : array (Width_Range, Height_Range) of Boolean := (others => (others => False));
      X     : Width_Range;
      Y     : Height_Range;
      Direc : Direction;

      procedure Random_Free (X : out Width_Range; Y : out Height_Range) is
      begin
         
         loop
            X := Random_Width.Random (Width_Gen);
            Y := Random_Height.Random (Height_Gen);
            exit when Field (X, Y) = False;
         end loop;
      end Random_Free;

   begin
      
      Field (Random_Width.Random  (Width_Gen),
             Random_Height.Random (Height_Gen)) := True;

      for I in 0 .. Points loop
         Random_Free (X, Y);
         loop
            
            while
              X = Width_Range'First  or X = Width_Range'Last or
              Y = Height_Range'First or Y = Height_Range'Last
            loop
               Random_Free (X, Y);
            end loop;
            exit when Field (X - 1, Y - 1) or Field (X, Y - 1) or Field (X + 1, Y - 1);
            exit when Field (X - 1, Y)     or                     Field (X + 1, Y);
            exit when Field (X - 1, Y + 1) or Field (X, Y + 1) or Field (X + 1, Y + 1);
            Direc := Random_Direc.Random (Direc_Gen);
            case Direc is
               when NW | N | NE => Y := Y - 1;
               when SW | S | SE => Y := Y + 1;
               when others => null;
            end case;
            case Direc is
               when NW | W | SW => X := X - 1;
               when SE | E | NE => X := X + 1;
               when others => null;
            end case;
         end loop;
         Field (X, Y) := True;
         Renderer.Draw (Point => (SDL.C.int (X), SDL.C.int (Y)));

         if I mod 100 = 0 then
            if Poll_Quit then
               return;
            end if;
            Window.Update_Surface;
         end if;
      end loop;
   end Draw_Brownian_Tree;

begin
   Random_Width.Reset  (Width_Gen);
   Random_Height.Reset (Height_Gen);
   Random_Direc.Reset  (Direc_Gen);

   if not SDL.Initialise (Flags => SDL.Enable_Screen) then
      return;
   end if;

   SDL.Video.Windows.Makers.Create (Win      => Window,
                                    Title    => "Brownian tree",
                                    Position => SDL.Natural_Coordinates'(X => 10, Y => 10),
                                    Size     => SDL.Positive_Sizes'(Width, Height),
                                    Flags    => 0);
   SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface);
   Renderer.Set_Draw_Colour ((0, 0, 0, 255));
   Renderer.Fill (Rectangle => (0, 0, Width, Height));
   Renderer.Set_Draw_Colour ((200, 200, 200, 255));

   Draw_Brownian_Tree;
   Window.Update_Surface;

   loop
      exit when Poll_Quit;
      delay 0.050;
   end loop;
   Window.Finalize;
   SDL.Finalise;
end Brownian_Tree;