[Bmax] Praktisches, skalierbares 2D-Array als Type
Übersicht

![]() |
FetzeBetreff: [Bmax] Praktisches, skalierbares 2D-Array als Type |
![]() Antworten mit Zitat ![]() |
---|---|---|
Da ich selber derzeit Bedarf an sowas hatte, es aber bisher keine zufriedenstellende Lösung gab, habe ich mich mal hieran gemacht. Das Testprogramm - Erst lesen, dann starten! - sollte eigentlich alles erklären.
Code: [AUSKLAPPEN] '##### TESTPROGRAMM #####
SuperStrict SeedRnd MilliSecs() Graphics 800, 600, 0, -1 'Erstmal ein DDObjArray erstellen, Größe 1 * 1, also genau 1 Feld an Position [0, 0] Global ddaTest:DDObjArray = DDObjArray.Create(1, 1) 'Jetzt weisen wir der Position [0, 0] das String-Objekt "Hallo" zu.. ddaTest.Set(0, 0, "Hallo") Print "ddaTest.Set(0, 0, ''Hallo'')" '..das wir mit Get nun an Position [0, 0] zurückgeliefert bekommen Print "ddaTest.Get(0, 0) = " + String(ddaTest.Get(0, 0)) 'Übrigens kann man ein DDObjArray auch gefahrlos kopieren. ddaTest = ddaTest.Copy() 'In diesem Fall überschreiben wir unser Array mit einer Kopie von sich selbst. 'Jetzt weisen wir dem DDObjArray einen neuen Ursprungspunkt zu, der bei [1, 1] liegt. Alle "Koordinaten" 'des DDObjArrays stehen RELATIV zu diesem Ursprungspunkt. Wenn ich also den Wert unserer alten [0, 0]-Position 'erfahren will, muss ich im folgenden nach [-1, -1] fragen, da [0, 0] relativ zu [1, 1] = [-1, -1]. 'So lange SetOrigin und AssertPos (Aber dazu kommen wir später) nicht aufgerufen werden, sind die RELATIVEN 'Koordinaten gleich den ABSOLUTEN koordinaten, da der Ursprungspunkt dann an [0, 0] liegt. ddaTest.SetOrigin(1, 1) Print "ddaTest.SetOrigin(1, 1)" 'Hier ein kleiner Beweis: Print "ddaTest.Get(-1, -1) = " + String(ddaTest.Get(-1, -1)) 'Würden wir Get weiterhin mit [0, 0] aufrufen, bekämen wir nen ordentlichen "Index out of bounds"-Fehler: 'Damit würden wir nach der ABSOLUTEN Position [1, 1] (die RELATIV zum Urpsrung [1, 1] an [0, 0] liegt) fragen, 'die bei unserem 1 * 1 - Array jedoch nicht existiert. 'Wir wollen aber um jeden Preis weiterhin auch an [0, 0] speichern und laden können. Hier gibt es 2 Möglichkeiten: 'Entweder, wir erhöhen die absolute Größe des DDObjArrays: ddaTest.Resize(2, 2) Print "ddaTest.Resize(2, 2)" 'Zur Erinnerung: Größe 2 * 2 bedeutet absolut von [0, 0] bis [1, 1], in diesem Fall relativ aber von '[-1, -1] bis [0, 0] ddaTest.Set(0, -1, "Das ist") ddaTest.Set(-1, 0, "ein") ddaTest.Set(0, 0, "Test") Print "ddaTest.Set(0, -1, ''Das ist'')" Print "ddaTest.Set(-1, 0, ''ein'')" Print "ddaTest.Set(0, 0, ''Test'')" Print "ddaTest.Get(-1, -1) = " + String(ddaTest.Get(-1, -1)) Print "ddaTest.Get(0, -1) = " + String(ddaTest.Get(0, -1)) Print "ddaTest.Get(-1, 0) = " + String(ddaTest.Get(-1, 0)) Print "ddaTest.Get(0, 0) = " + String(ddaTest.Get(0, 0)) 'Kommen wir nun zur anderen Möglichkeit. Ich werde unsere Veränderungen dafür rückgängig machen: ddaTest.Resize(1, 1) Print "ddaTest.Resize(1, 1)" 'Die andere Möglichkeit ist der Befehl "AssertPos". Mit ihm kann man "auf eine beliebige Position bestehen", d.h. 'Diese Position wird auf jeden Fall existieren, allerdings nicht unbedingt NUR diese Position. Denn: AssertPos 'ist im wesentlichen eine Automatische Fassung von Resize, kombiniert mit SetOrigin. AssertPost garantiert, dass 'sich danach noch alles an seinem Platz befindet, jedoch mehr Platz vorhanden ist, in dem sich etwas befinden 'kann - und das genau dort, wo man es braucht. Hier nocheinmal genau dasselbe wie eben, nur mit AssertPos statt 'Resize: ddaTest.AssertPos(0, 0) Print "ddaTest.AssertPos(0, 0)" 'Das Array wurde nun auf die absolute Größe [2, 2] vergrößert, damit es vom relativen [-1, -1] in der relative '[0, 0] hineinragt und [0, 0] nun mit einem Objekt befüllt werden kann. Dabei wurden auch gleichzeitig die 'Koordinaten [0, -1] und [-1, 0] frei. Im wesentlichen also genau wie Resize(2, 2). ddaTest.Set(0, -1, "Das ist") ddaTest.Set(-1, 0, "ein") ddaTest.Set(0, 0, "Test") Print "ddaTest.Set(0, -1, ''Das ist'')" Print "ddaTest.Set(-1, 0, ''ein'')" Print "ddaTest.Set(0, 0, ''Test'')" Print "ddaTest.Get(-1, -1) = " + String(ddaTest.Get(-1, -1)) Print "ddaTest.Get(0, -1) = " + String(ddaTest.Get(0, -1)) Print "ddaTest.Get(-1, 0) = " + String(ddaTest.Get(-1, 0)) Print "ddaTest.Get(0, 0) = " + String(ddaTest.Get(0, 0)) 'Aber: AssertPost kann noch mehr. Wenn wir beispielsweise in unserem Beispiel-Array die Position [-2, -2] 'belegen wollen, kommen wir mit Resize nicht weit, sondern müssten auch den Ursprung umverlegen. Damit man 'sich mit diesem ganzen kram nicht befassen muss, gibt es die AssertPost-Methode, die das alles vollautomatisch 'erledigt. ddaTest.AssertPos(-2, -2) Print "ddaTest.AssertPos(-2, -2)" 'Dadurch haben wir nun nebenbei bemerkt ein 3 * 3 - Array, das von [-2, -2] bis [0, 0] reicht. ddaTest.Set(-2, -2, "Blub") Print "ddaTest.Set(-2, -2, ''Blub'')" Print "ddaTest.Get(-2, -2) = " + String(ddaTest.Get(-2, -2)) 'Natürlich sind solcherlei Arrays recht kompliziert in Schleifen zu verwenden, da man möglicherweise nicht 'weis, wo man beginnen und wo enden soll. Damit trotzdem keine Verwirrung entsteht, gibt es einige Methoden, 'die es einem etwas erleichtern: For Local iYLoop:Int = ddaTest.GetLowestY() To ddaTest.GetHighestY() For Local iXLoop:Int = ddaTest.GetLowestX() To ddaTest.GetHighestX() Print "[" + iXLoop + ", " + iYLoop + "] = " + String(ddaTest.Get(iXLoop, iYLoop)) Next Next 'Und hier unser Array nocheinmal grafisch dargestellt! ^^ SetClsColor 255, 255, 255 Repeat Cls For Local iYLoop:Int = ddaTest.GetLowestY() To ddaTest.GetHighestY() For Local iXLoop:Int = ddaTest.GetLowestX() To ddaTest.GetHighestX() SetColor 200, (iYLoop - ddaTest.GetLowestY()) * 75, (iXLoop - ddaTest.GetLowestX()) * 75 DrawRect (iXLoop - ddaTest.GetLowestX()) * 100, (iYLoop - ddaTest.GetLowestY()) * 100, 100, 100 SetColor 0, 0, 0 DrawText iXLoop + " " + iYLoop, (iXLoop - ddaTest.GetLowestX()) * 100, ((iYLoop - ddaTest.GetLowestY()) * 100) + 10 DrawText String(ddaTest.Get(iXLoop, iYLoop)), (iXLoop - ddaTest.GetLowestX()) * 100, ((iYLoop - ddaTest.GetLowestY()) * 100) + 20 Next Next Flip Until KeyHit(KEY_ESCAPE) 'Zu guter letzt: ddaTest.Clear() 'Die Clear-Methode löscht den Inhalt des Arrays komplett. Dabei bleibt seine Größe jedoch erhalten. '######################## Type DDObjArray Field objArray :Object[][] Field iWidth :Int Field iHeight :Int Field iOriginX :Int Field iOriginY :Int 'Setzt den Ausgangspunkt des Arrays neu. Beispiel: SetOrigin(1, 1) sorgt dafür, dass man objArray[0][0] per 'Get-Methode unter Get(-1, -1) erreicht, da jede Position nun relativ zu [1, 1] gesehen wird. Method SetOrigin:Byte(iParX:Int, iParY:Int) iOriginX = iParX iOriginY = iParY Return True End Method 'Sorgt durch Resize und SetOrigin dafür, dass die angegebene Position innerhalb des Arrays liegt. Die 'bisherigen Datensätze bleiben unter derselben Position erreichbar wie vorher. Method AssertPos:Byte(iParX:Int, iParY:Int) If ValidPos(iParX, iParY) = True Then Return True Local iNewWidth:Int = iWidth Local iNewHeight:Int = iHeight Local iNewOriginX:Int = iOriginX Local iNewOriginY:Int = iOriginY If iParX + iOriginX + 1 > iWidth Then iNewWidth = iParX + iOriginX + 1 ElseIf iParX + iOriginX < 0 Then iNewWidth = iWidth - (iParX + iOriginX) iNewOriginX:- (iParX + iOriginX) End If If iParY + iOriginY + 1 > iHeight Then iNewHeight = iParY + iOriginY + 1 ElseIf iParY + iOriginY < 0 Then iNewHeight = iHeight - (iParY + iOriginY) iNewOriginY:- (iParY + iOriginY) End If Resize(iNewWidth, iNewHeight) Rem Local iRelX:Int = iNewOriginX - iOriginX Local iRelY:Int = iNewOriginY - iOriginY If iRelX <> 0 Or iRelY <> 0 Then Local ddaTemp:DDObjArray = Self.Copy() Self.Clear() For Local iYTemp:Int = GetLowestY() To GetHighestY() For Local iXTemp:Int = GetLowestX() To GetHighestX() If iXTemp + iRelX + iOriginX < 0 Then Continue If iXTemp + iRelX + iOriginX >= iWidth Then Continue If iYTemp + iRelY + iOriginY < 0 Then Continue If iYTemp + iRelY + iOriginY >= iHeight Then Continue Set(iXTemp + iRelX, iYTemp + iRelY, ddaTemp.Get(iXTemp, iYTemp)) Next Next End If End Rem Local iRelX:Int = iNewOriginX - iOriginX Local iRelY:Int = iNewOriginY - iOriginY If iRelX <> 0 Or iRelY <> 0 Then For Local iYTemp:Int = GetHighestY() To GetLowestY() Step -1 For Local iXTemp:Int = GetHighestX() To GetLowestX() Step -1 If ValidPos(iXTemp + iRelX, iYTemp + iRelY) = False Then Continue If ValidPos(iXTemp, iYTemp) = False Then Continue Set(iXTemp + iRelX, iYTemp + iRelY, Get(iXTemp, iYTemp)) Set(iXTemp, iYTemp, Null) Next Next End If SetOrigin(iNewOriginX, iNewOriginY) Return True End Method 'Zuschneiden des DDObjArrays: Inhalt und Position des Inhalts bleibt gleich, größe des Arrays wird jedoch 'auf ein Minimum reduziert. Method CutDown:Byte() If iWidth = 1 And iHeight = 1 Then Return True Local iLowestX:Int = 2147483647 'Höchstmöglicher Integer-Wert Local iLowestY:Int = 2147483647 Local iHighestX:Int = -2147483647 'Niedrigstmöglicher Integer-Wert Local iHighestY:Int = -2147483647 'Eckpunkte finden: For Local iLoop:Int = GetLowestX() To GetHighestX() For Local iLoop2:Int = GetLowestY() To GetHighestY() If Get(iLoop, iLoop2) <> Null Then If iLoop < iLowestX Then iLowestX = iLoop If iLoop2 < iLowestY Then iLowestY = iLoop2 If iLoop > iHighestX Then iHighestX = iLoop If iLoop2 > iHighestY Then iHighestY = iLoop2 End If Next Next 'Einzige Schlussfolgerung, wenn gar kein Wert gesetzt wurde: Das Array ist leer. If iLowestX = 2147483647 And iLowestY = 2147483647 And iHighestX = -2147483647 And iHighestY = -2147483647 Then Resize(1, 1) Return True End If Local iNewWidth:Int = iHighestX - iLowestX + 1 Local iNewHeight:Int = iHighestY - iLowestY + 1 Local iNewOriginX:Int = iOriginX - (iLowestX - GetLowestX()) Local iNewOriginY:Int = iOriginY - (iLowestY - GetLowestY()) Local iRelX:Int = iNewOriginX - iOriginX Local iRelY:Int = iNewOriginY - iOriginY If iRelX <> 0 Or iRelY <> 0 Then For Local iYTemp:Int = GetLowestY() To GetHighestY() For Local iXTemp:Int = GetLowestX() To GetHighestX() If ValidPos(iXTemp + iRelX, iYTemp + iRelY) = False Then Continue If ValidPos(iXTemp, iYTemp) = False Then Continue Set(iXTemp + iRelX, iYTemp + iRelY, Get(iXTemp, iYTemp)) Set(iXTemp, iYTemp, Null) Next Next End If Resize(iNewWidth, iNewHeight) SetOrigin(iNewOriginX, iNewOriginY) Return True End Method Method GetLowestX:Int() Return -iOriginX End Method Method GetLowestY:Int() Return -iOriginY End Method Method GetHighestX:Int() Return iWidth - iOriginX - 1 End Method Method GetHighestY:Int() Return iHeight - iOriginY - 1 End Method Method Copy:DDObjArray() Local ddaTemp:DDObjArray = New DDObjArray ddaTemp.objArray = objArray[..] For Local iLoop:Int = 0 To objArray.length - 1 ddaTemp.objArray[iLoop] = objArray[iLoop][..] Next ddaTemp.iWidth = iWidth ddaTemp.iHeight = iHeight ddaTemp.iOriginX = iOriginX ddaTemp.iOriginY = iOriginY Return ddaTemp End Method Method Set:Byte(iParX:Int, iParY:Int, objPar:Object) objArray[iParX + iOriginX][iParY + iOriginY] = objPar Return True End Method Method Get:Object(iParX:Int, iParY:Int) Return objArray[iParX + iOriginX][iParY + iOriginY] End Method Method ValidPos:Byte(iParX:Int, iParY:Int) If iParX + iOriginX >= 0 And iParX + iOriginX < iWidth Then If iParY + iOriginY >= 0 And iParY + iOriginY < iHeight Then Return True End If End If Return False End Method Method Clear:Byte() Local iOldWidth:Int = iWidth Local iOldHeight:Int = iHeight Resize(0, 0) Resize(iOldWidth, iOldHeight) Return True End Method Method Resize:Byte(iParWidth:Int, iParHeight:Int) ?Debug If iParWidth = 0 Then RuntimeError("Invalid Width-Parameter: " + iParWidth) If iParHeight = 0 Then RuntimeError("Invalid Height-Parameter: " + iParHeight) ? If objArray.length <> iParWidth Then objArray = objArray[..iParWidth] End If For Local iLoop:Int = 0 To iParWidth - 1 If objArray[iLoop].length <> iParHeight Then objArray[iLoop] = objArray[iLoop][..iParHeight] End If Next iWidth = iParWidth iHeight = iParHeight Return True End Method Function Create:DDObjArray(iParWidth:Int, iParHeight:Int) Local ddaTemp:DDObjArray = New DDObjArray ddaTemp.Resize(iParWidth, iParHeight) Return ddaTemp End Function End Type Viel Spaß damit, Kommentare und Erweiterungen erwünscht ![]() |
||
- Zuletzt bearbeitet von Fetze am Do, Jul 20, 2006 16:19, insgesamt einmal bearbeitet
![]() |
Fetze |
![]() Antworten mit Zitat ![]() |
---|---|---|
So, gibt ne neue Methode. Mit der kann man das DDObjArray bei gleichbleibenden Abfragepositionen zuschneiden lassen, d.h. leere Ränder werden entfernt.
Einfach mal testen, indem man irgendeine irrsinnige AssertPos aufruft und direkt danach ein CutDown. Nach dem CutDown sollte alles wieder genauso aussehen wie vorher. Code: [AUSKLAPPEN] 'Zuschneiden des DDObjArrays: Inhalt und Position des Inhalts bleibt gleich, größe des Arrays wird jedoch 'auf ein Minimum reduziert. Method CutDown:Byte() If iWidth = 1 And iHeight = 1 Then Return True Local iLowestX:Int = 2147483647 'Höchstmöglicher Integer-Wert Local iLowestY:Int = 2147483647 Local iHighestX:Int = -2147483647 'Niedrigstmöglicher Integer-Wert Local iHighestY:Int = -2147483647 'Eckpunkte finden: For Local iLoop:Int = GetLowestX() To GetHighestX() For Local iLoop2:Int = GetLowestY() To GetHighestY() If Get(iLoop, iLoop2) <> Null Then If iLoop < iLowestX Then iLowestX = iLoop If iLoop2 < iLowestY Then iLowestY = iLoop2 If iLoop > iHighestX Then iHighestX = iLoop If iLoop2 > iHighestY Then iHighestY = iLoop2 End If Next Next 'Einzige Schlussfolgerung, wenn gar kein Wert gesetzt wurde: Das Array ist leer. If iLowestX = 2147483647 And iLowestY = 2147483647 And iHighestX = -2147483647 And iHighestY = -2147483647 Then Resize(1, 1) Return True End If Local iNewWidth:Int = iHighestX - iLowestX + 1 Local iNewHeight:Int = iHighestY - iLowestY + 1 Local iNewOriginX:Int = iOriginX - (iLowestX - GetLowestX()) Local iNewOriginY:Int = iOriginY - (iLowestY - GetLowestY()) Local iRelX:Int = iNewOriginX - iOriginX Local iRelY:Int = iNewOriginY - iOriginY If iRelX <> 0 Or iRelY <> 0 Then For Local iYTemp:Int = GetLowestY() To GetHighestY() For Local iXTemp:Int = GetLowestX() To GetHighestX() If iXTemp + iRelX + iOriginX < 0 Then Continue If iXTemp + iRelX + iOriginX >= iWidth Then Continue If iYTemp + iRelY + iOriginY < 0 Then Continue If iYTemp + iRelY + iOriginY >= iHeight Then Continue Set(iXTemp + iRelX, iYTemp + iRelY, Get(iXTemp, iYTemp)) Set(iXTemp, iYTemp, Null) Next Next End If Resize(iNewWidth, iNewHeight) SetOrigin(iNewOriginX, iNewOriginY) Return True End Method |
||
![]() |
Fetze |
![]() Antworten mit Zitat ![]() |
---|---|---|
Habe gerade die (hoffentlich) letzten Bugs entfernt, jetzt sollte das Array wirklich 100% stabil laufen. Habe meinen ersten Post editiert. | ||
![]() |
Artemis |
![]() Antworten mit Zitat ![]() |
---|---|---|
Gute Idee. Kann man bestimmt mal gebrauchen. *thumbs up* | ||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group