C# to BMax

Started by _PJ_, February 15, 2020, 19:43:42

Previous topic - Next topic

_PJ_

There is a youtube animation that details a simple, naive cell automata algorithm for generating "caves"

I copied the essence of the code to BMax with only one significant alteration (in the video the content creator is manipulating the data whilst it is iterated - in my version the applicaiotn is made after all results are in) which seems to improve things slightly in my version.
Other than this, I'm nott really sure there should be anything different in the code execution, however, the results are radically dissimilar - is anyone able to shed light on possible reason for the differences?


The YouTube video is found here: https://www.youtube.com/watch?v=v7yyZZjF1z4

My BMax version (with the amendment noted above) is here:

SuperStrict

Global G:TGraphics

Global Cave:TCave

Const CAVE_WIDTH:Int=128
Const CAVE_HEIGHT:Int=72
Const CAVE_SCALE:Int = 4
Const CAVE_SMOOTHING:Int = 5
Const CAVE_FILL_PERCENTAGE:Int = 47
Const CELL_CUTOFF:Int = 4

RunTime

Function RunTime()
Initialise
Loop
CloseDown
End Function

Type TCave
Field Map:Int[0,0]

Field RandomSeed:Int

Function Create:TCave(W:Int,H:Int,Seed:Int=0)
Local NewCave:TCave= New TCave
If (Seed=0)
Seed=MilliSecs()
End If

NewCave.RandomSeed=Seed
NewCave.GenerateMap(W,H)

Return NewCave
End Function

Method GenerateMap(W:Int,H:Int)
Self.Map:Int[] = New Int[W,H]
RandomiseMap

Local Iter:Int
For Iter=1 To CAVE_SMOOTHING
SmoothMap
Next
End Method

Method RandomiseMap()
SeedRnd Self.RandomSeed
Local W:Int=Self.Map.Dimensions[0]
Local H:Int=Self.Map.Dimensions[1]

Local X:Int
Local Y:Int

For Y = 0 To H-1
For X = 0 To W-1
Self.Map[X,Y]= ( Rand(100) <= CAVE_FILL_PERCENTAGE )
Next
Next

End Method


Method SmoothMap()
Local W:Int=Self.Map.Dimensions[0]
Local H:Int=Self.Map.Dimensions[1]

Local X:Int
Local Y:Int

Local iX:Int
Local iY:Int

Local Walls:Int

Local Change:Int[W,H]

For Y = 0 To H-1
For X = 0 To W-1

Walls = WallCount(X,Y)

If (Walls = CELL_CUTOFF)
Change[X,Y]=Self.Map[X,Y]
Else
Change[X,Y]=(Walls > CELL_CUTOFF)
End If

Next
Next
X=0
Y=0
For Y=0 To H-1
For X=0 To W-1
Map[X,Y]=Change[X,Y]
Next
Next

End Method

Method WallCount:Int(X:Int,Y:Int)
Local iX:Int
Local iY:Int

Local W:Int=Self.Map.Dimensions[0]
Local H:Int=Self.Map.Dimensions[1]

Local Count:Int

For iY = Y-1 To Y+1
For iX = X-1 To X+1

If ((iX<1) Or (iX>=(W-1)) Or (iY<1) Or (iY>=(H-1)) )
Count:+1
Else
If ( (iX <> X) And ( iY <> Y ) )
Count:+Self.Map[iX,iY]
End If
End If

Next
Next

Return Count
End Method

Method Display(oX:Int=0,oY:Int=0,ScaleX:Int=1,ScaleY:Int=1)
Local W:Int=Self.Map.Dimensions[0]
Local H:Int=Self.Map.Dimensions[1]

Local X:Int
Local Y:Int

For Y = 0 To H-1
For X = 0 To W-1
If (Self.Map[X,Y])
DrawRect oX+(X * ScaleX), oY + (Y * ScaleY), ScaleX, ScaleY
End If
Next
Next

DrawText Self.RandomSeed,0,GraphicsHeight()-TextHeight("|")
End Method
End Type

Function Initialise()
InitialiseGPU
InitialiseCave
End Function

Function Loop()
While Not (KeyHit(KEY_ESCAPE))
Cls
Update
Flip
Wend
End Function

Function Update()
UpdateCave
End Function

Function UpdateCave()
Cave.Display((GraphicsWidth()*0.5)-((CAVE_WIDTH*CAVE_SCALE)*0.5),(GraphicsHeight()*0.5)-((CAVE_HEIGHT*CAVE_SCALE)*0.5),CAVE_SCALE,CAVE_SCALE)
End Function

Function InitialiseCave()
Cave = TCave.Create(CAVE_WIDTH,CAVE_HEIGHT)
End Function

Function InitialiseGPU()
G:TGraphics = Graphics(DesktopWidth(),DesktopHeight(),0,60,GRAPHICS_BACKBUFFER,0,0)
Cls
End Function

Function UnInitialise()
UnInitialiseCave
UnInitialiseGPU
End Function

Function UnInitialiseCave()
Cave.Map=Null
Cave=Null
End Function

Function UnInitialiseGPU()
EndGraphics
End Function

Function CloseDown()
UnInitialise
End
End Function


_PJ_

I feel silly.
I should give myself the fresh approach of a new day before I post these things :)

It was a very basic mistake (aren't they always?)
The error was here:

If ( (iX <> X) And ( iY <> Y ) )
Count:+Self.Map[iX,iY]
End If

Which ONLY counted those cases where iX != X and iY<>Y (essentially just the four neighbouring corners) instead of a more correct:

If ( (iX = X) And ( iY =Y ) )
' Ignore the central case X,Y
Else
Count:+Self.Map[iX,iY]
End If




_PJ_

Since installing the most recent version of BMax NG [from a much earlier version, so may not be a change in the very latest patch], I am receiving errors in compiling projects using similar code to the above::

The offence seems to relate to calls to the "Dimensions" property of array.

The error message is
"Semanting...
Compile Error: Method cannot be used as a function pointer"

Has something changed or am I doing something wrong???

 (( possibly something to do with

Function bbRefArrayDimensions:Int( _array:Object )         
from brl.mod/Reflection.mod/reflection.bmx


))

Midimaster

#3
As I understand the BlitzMax help correct Dimensions is not an array, but  a method, that returns an array. So you need to set (round) brackets:

wrong:

Map.Dimensions[1]

right:
Map.Dimensions()[1]

Local W:Int=Self.Map.Dimensions()[0]
Local H:Int=Self.Map.Dimensions()[1]               

...crossing the alps with my bike at the moment

_PJ_

Thanks Midimaster!

Again, so obvious now you point it out - but I was so blind to it.
Strange that it was working previously, perhaps the compiler could figure out what was meant, but with NG's "Superstrict" requirement no ambiguity allowed.