• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

IT-Talents.de Code Competitions

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #243
@KaPiTN: Finde ich sehr cool, auch deine Idee die Zellen zeichnen zu können. Ich hab auch überlegt ob ich nicht so etwas ähnliches mache, bei dem man die Population in den Felder "switchen" kann, aber ich mag die Idee sehr.

Und wenn der "Schwimmer" drin ist, sind wohl auch die Regeln richtig, auch wenn das etwas klein ist. Bei der Competition, ich weiß nicht ob das im normalen Conway auch so ist, "blenden" die Eckfelder über auf die andere Seite. Hast du das ebenfalls drin?
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Ja. Habe ich. Ich habe auch die Darstellung von der Berechnung getrennt. Ich scanne nur einmalig ein und gebe dann die lebenden Zellen an die Darstellung.

Spoileralarm:
Ich frage auch nur einmalig die umliegenden 8 Zellen ab und aktualisiere dann den Zustand

Das einzige was ich wohl ändern müßte, wäre keine Pixel zu malen, sondern Klötzchen.
Das ist jetzt auch kein weiter Sprung mehr, aber ich wollte ja möglichst schnell meine Neugier befriedigen und habe es einfach gehalten. ;)
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
theSplit schrieb:
ich weiß nicht ob das im normalen Conway auch so ist, "blenden" die Eckfelder über auf die andere Seite.
Der ursprüngliche Conway sagt gar nichts über die Spielfeldgrenzen, also könnte man implizit von einem unendlich großen Feld ausgehen. Implementiert sich halt eher lästig. ;)

Bei mir ist jetzt erstmal ne Woche Urlaub, und anschließend knüpf ich mir Qt Quick und QML für die GUI vor. Endlich ein QML-Projekt gefunden, da bin ich schon länger am suchen.

Und bin gespannt, wie euere Animationen in einer Woche ausschauen. :)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #246
Die Routine das "Wrapping" zu implementieren, steckt bei mir mit in den Nachbarzellen "Finder".... sind mittels Ternary Operator - also liegt das Feld an einer Kante, ja/nein, ein paar mehr Zeilen Code - und im Grunde regele ich das über einfache Mathematik.

Einzig allein die Richtungen Oben, Oben Rechts, Rechts, Unten Rechts usw... ja, das ist etwas lästig, aber geht wohl auch nicht anders... zumindest wüsste ich aktuell nicht wie ;)

Hab nur zwei Werte die ich entweder addiere oder abziehe - alles in einer Funktion. ;)

Edit: Im übrigen war das für mich ein guter Grund, ein ENUM zu verwenden, damit der Code auch verständlich bleibt.
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Ternary. 2 Doofe ein Gedanke. Habe ich auch benutzt, um vorher zu prüfen, wo die Nachbarzellen liegen. :)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #248
@KaPiTN:
Es gibt ja nur zwei Zustände bei den Nachbarzellen, entweder X - 1 oder + 1 oder 0 (ohne Wertung) - das gleiche für die Y Achse (gleich) oder eins hoch oder einen runter.

Ich denke das kann man auch nicht anders "sinnvoll" lösen...
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Laß uns über verschachtelte if-Abfragen sinnieren.:D
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #250
switch case for the win! ;) (Dank enum....)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #252
Wir driften ab ;)

Aber wenn du deine "Magie" hinter Namen wie dc, bf, dk verschachteln willst, nur zu :p
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #253
So, noch ein Update für heute, wie davor mit einem kleinen Video:

Im Grunde kann man jetzt schon etwas mehr kontrollieren und es werden Meldungen ausgegeben, aber sehr selbst:
Könnte etwas Spoilern! (Feature-technisch)...
https://www.picflash.org/picture.php?key=0DBYHI&action=show

Das mit dem einziechnen will ich auch unbedingt noch machen @ Kapitn! ;)

Weitere geplante Features:
Dazu noch etwas Initialisierung über die Kommandozeile für Startparamenter (Zellen, Fensterauflösung, Grid zum Start aus, Animation Switch... Random living field count und ähnliches) und nen CSV Reader/Parser für ein Spielfeld. Das Einzeichnen werde ich aber definitiv vorher einbauen. Der Rest ist schon "dynamisch" Zellgröße/Rendering bzw. Drawing und Co... ;)
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
So. Ein Pixel für jede Zelle war ja etwas sehr klein. Also habe ich jetzt Quadrate genommen. Das war ja nicht wesentlich mehr, als vorkommende Einsen mit einer Konstanten auszutauschen.

Ein wenig Arbeit hat jetzt das "Freihandmalen" gemacht, weil es das genau genommen ja gar nicht sein darf.

freihand.png

Ich nenne hier keine Lösung, aber vielleicht will ja auch jemand Stolpersteine selber entdecken. Lieber ein Spoilerbereich zu viel, als zu wenig.
Die Zellen sollen ja quadratisch sein. Also ist das freie Malen links nicht zu gebrauchen. Wir wollen ja ein Raster.Dann ergibt sich noch ein Problem, welches dem event-driven programming geschuldet ist. Normalerweise läßt sich das damit lösen, daß man eine Standardfunktion benutzt, die nicht naheliegend erscheint. Die ist aber für ein Raster ungeeignet, so daß man hier mal wieder selber etwas Code schreiben muß.
Und mit muß meine ich wirklich selber müssen.
Sonst findet man ja schon mal Snippets, die man adaptieren kann. ;)

Somit schaut der Prototyp derweil so aus:

 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #255
Ich versuche gerade ein Feature zu implementieren, bei dem von einem Bild die Pixel eingelesen werden, ich stehe allerdings auf dem Schlauch.

Im Grunde wird mittels IMG_Load (Bibliothek: SDL_image) ein Bild geladen, PNG oder JPEG. Daraus soll, so der Plan, aus den Pixeln ein Durschnittswert errechnet werden. Der Part scheint auch zu funktionieren. Was nicht funkioniert, der Index für die Pixel "j + (i * imgWidth)" wirfst einen "invalid read.
Das heißt scheinbar, ich greife auf Daten zu, die nicht vorhanden sind.

Es arbeitet mit SDL2 Surface, was aus IMG_Load erstellt wird.

Mag mal jemand darüber schauen? Und hat eine Idee, was ich falsch mache?

Könnte Features spoilern!!

[src=c]// Assign a surface and load the image
SDL_Surface* imageSurface = IMG_Load(droppedFilePath);

// Check if the file was loading properly
if (imageSurface == NULL) {
set_options_message(gameOptions, "Image loading error, check console.");
printf("[ERROR] Image loading errror:\n%s\n\n", IMG_GetError());
return false;
}


// Finally, work with the surface
if (imageSurface->format->BitsPerPixel < 24 ) {
SDL_FreeSurface(imageSurface);
set_options_message(gameOptions, "Only 24/32 bit images are supported.");
return false;
}

unsigned int imgWidth = imageSurface->w; // Width
unsigned int imgHeight = imageSurface->h; // Height

unsigned int xPixelPerCell = floor((float) imgWidth / gameBoard->cellsX);
unsigned int yPixelPerCell = floor((float) imgHeight / gameBoard->cellsY);

if (xPixelPerCell < 1 || yPixelPerCell < 1) {
SDL_FreeSurface(imageSurface);
set_options_message(gameOptions, "Image to small, size and height must match cell");
return false;
}
unsigned int totalPixelPerCell = xPixelPerCell * yPixelPerCell;

unsigned int index = 0;

unsigned int maxX = 0;
unsigned int maxY = 0;

unsigned int rValue = 0;
unsigned int gValue = 0;
unsigned int bValue = 0;
unsigned int rAverage = 0;
unsigned int gAverage = 0;
unsigned int bAverage = 0;

gameBoard->livingCells = 0;

SDL_LockSurface(imageSurface);
Uint32* pixelData = (Uint32 *)imageSurface->pixels; // Get the pixel data

while (maxY < imgHeight) {
maxY += yPixelPerCell;
maxX += xPixelPerCell;

// Reset the currentX position if we are at the image boundaries in X
if (maxX >= imgWidth - xPixelPerCell) {
maxX = 0;
}

rValue = 0;
gValue = 0;
bValue = 0;
for (unsigned int j = maxX - xPixelPerCell; j < maxX; ++j) {
for (unsigned int i = maxY - yPixelPerCell; i < maxY; ++i) {
// TODO: Why is this an invald read ??????????????????
rValue += ((pixelData[j + (i * imgWidth)] & imageSurface->format->Rmask) >> imageSurface->format->Rshift) << imageSurface->format->Rloss;
//gValue += ((pixelData[j + (i * imgWidth)] & imageSurface->format->Gmask) >> imageSurface->format->Gshift) << imageSurface->format->Gloss;
//bValue += ((pixelData[j + (i * imgWidth)] & imageSurface->format->Bmask) >> imageSurface->format->Bshift) << imageSurface->format->Bloss;
}
}

rAverage = rValue / totalPixelPerCell;
gAverage = gValue / totalPixelPerCell;
bAverage = bValue / totalPixelPerCell;

//printf("%d\n", (rAverage + gAverage + bAverage));

printf("X: %d - %d [cellX: %d]\nY: %d - %d [cellY: %d]\n", maxX, imgWidth, xPixelPerCell, maxY, imgHeight, yPixelPerCell);

// Turn the cell on living or dying, based on color threshold
if ((rAverage + gAverage + bAverage) >= gameOptions->colorThreshold) {
gameBoard->cells[index].isLiving = true;
gameBoard->cells[index].cellChanged = true;
++gameBoard->livingCells;
} else {
gameBoard->cells[index].isLiving = false;
gameBoard->cells[index].cellChanged = false;
}

printf("%d - %d\n", index, gameBoard->cellCount);
gameBoard->cells[index].size = 0;
++index;
}

printf("outside\n");
SDL_UnlockSurface(imageSurface);

// Free the image surface
SDL_FreeSurface(imageSurface);[/src]
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
[src=c]while (maxY < imgHeight) {
maxY += yPixelPerCell;
maxX += xPixelPerCell;[/src]

Was hat den maxX mit der Höhe zu tun? Wenn das Bild nicht quadratisch ist, ist es doch entweder zu klein oder zu groß.


Das habe ich auch nicht verstanden:
[src=c] if (maxX >= imgWidth - xPixelPerCell) {
maxX = 0;
}[/src]
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #257
@KaPiTN:

Vielleicht klärt das deine Fragen, ich setze es mal in einen Spoiler. :)

xPixelPerCell und yPixelPerCell leiten sich ja von den realen Pixeln des Bildes ab:
Sagen wir das Bild hat 200 x 250 Pixel, das Spielbrett hat in X 10 Zellen und in Y 10 (heißt wir haben Quadratischen Conway Zellen 10x10)

xPixelPerCell = 200 / 10 => 20 (Bildpixel in Breite (X) die gescannt werden pro Conway Zelle)
yPixelPerCell = 250 / 10 => 25 (Bildpixel in Höhe (Y) die gescannt werden, pro Conway Zelle)

Daraus sollte sich dann Ergeben: 20*25 reale Bildpixel = eine Conway Zelle (es ist kein 1 zu 1 Mapping, sondern 20 zu 1 in X und 25 zu 1 in Y)

Zu deinen Fragen daher, mit obigen Werten
Sagen wir fangen mit der erste Reihe, also X = 0, Y = 0 .
maxX (maximaler Scanbereich, Bildpixel, auf X Achse) = 0 bis 20 (20 xPixelPerCell!!)
maxX in Runde 2 = 20 bis 40
maxX in Runde 3 = 40 bis 60
maxX in Runde 10 = 180 bis 200

Gescannt werden sollte dann eigentlich:
Runde 2:
maxX += xPixelPerCell (= 40, Runde 2!)

im Scanning heißt es dann:
for (x = maxX - xPixelPerCell; x < maxX; ++x)

Es wird damit das "links obere" Bildpixel Offset ermittelt x = 20, y = 0...

Ich wandere in der Schleife jedoch etwas komisch... weil:
Scanrichtung ist von:
x 20 y 0
zu -> x 20 y 1
x 20 y 2
usw..
x 20 y 25
dann:
x 21 y 0
x 21 y 1
x 21 y 25
dann:
x 22 y 0
usw...

bis wir x 40 y 25 treffen (damit ist eine Zelle ermittelt)


Zur zweiten Frage:

maxX wird ja jedesmal erhöht - sind wir am Rechten Bildrand angekommen, muss maxX wieder "links" anfangen (also bei x = 0; y = 25) ( zweite Reihe Conway Zellen), in der vierten wäre es x = 0, y = 100 (4 * yPixelPerCell (25) = 100).
Die Schleife läuft dann so lange, bis wir auf der Y Achse im Bild unten angelangt sind.

Im Beispiel von oben also auf y 250 - eigentlich müsste da aber dann dennoch mit einfließen, in der While-Bedingung: Wenn wir an x 200 und y 250 (realen Bildpixeln) angelangt sind. Das ist definitiv noch ein Fehler.
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.504
Naja, jedenfalls betrittst du deine verschachtelte for-Schleife zwischen durch mit j < 0, was dazu führt, dass du versuchst auf negative indizes von pixelData zuzugreifen.

[src=c]if (maxX >= imgWidth - xPixelPerCell) {
maxX = 0; // at some point, maxX will be equal zero
}

rValue = 0;
gValue = 0;
bValue = 0;
for (unsigned int j = maxX - xPixelPerCell; j < maxX; ++j) { // when maxX is zero, j will be equal to minus xPixelPerCell in first iteration
[...]
}[/src]

Das cellchanged sieht komisch aus, wieso wird cellChanged abhängig von "isLiving" gesetzt?

[src=c]if ((rAverage + gAverage + bAverage) >= gameOptions->colorThreshold) {
gameBoard->cells[index].isLiving = true;
gameBoard->cells[index].cellChanged = true;
++gameBoard->livingCells;
} else {
gameBoard->cells[index].isLiving = false;
gameBoard->cells[index].cellChanged = false;
}[/src]


Würde das ganze in verschiedene Funktionen auslagern zwecks Übersicht. Die Variablenbezeichner sind für fremde jetzt auch nicht so der Brüller :D.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #259
@BurnerR:

Das ist etwas irreführend. maxX wird bevor die Schleifen auch nur einmal ausgeführt werden, schon größer 0 gesetzt (mindestens 0 + xPixelPerCell) (im oberen Teil der While Schleife) - und wir beginnen einfach die Schleife bei
Runde 1: 20 - 20 = 0
Runde 2: 40 - 20 = 20
Runde 3 :60 - 20 = 40
usw...

(das ist der Part den der Kaptin zitiert hat)

NOTE: Aber du hast Recht... das muss der Fehler sein, ich setzt mit dem "if" ja den Zähler auf 0 und nicht 0 + xPixelPerCell für maxX, dann ist der in der Tat negativ...
Edit: Bzw. habt ihr beide Recht, das hab ich dann nicht geblickt.

CellChanged ist ein Animationsparameter bzw. gibt auch den Status, ob eine Zelle sich verändert hat während einer Runde. :)

Die Variablen Namen sind wirklich nicht perfekt, aber ich hab auch noch nicht wirklich richtig gut kommentiert und den Code überarbeitet, das Feature wollte ich ziemlich schnell raushauen :D
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
@theSplit:

Sry, daß Du jetzt so eine lange Antwort schreiben mußtest. Ich habe da heute morgen nach dem Aufstehen 2 Sachen unterstellt, ohne darüber nachzudenken. :m
Eine Zelle war für mich quadratisch. Bei einem gleichen Verhältnis Gesamtpixel und Pixel=Zelle für x und y kann man das sicher in einer Schleife machen. Der alte Gegensatz Kürze und Lesbarkeit.

Der Klopfer aber kommt noch.(2. Frage)
Bei dieser Schreibweise, wo man die korrespondierenden Klammer so schlecht sieht, weil sie einmal rechts und einmal links steht, hatte ich unterstellt, daß man, sofern der Code als Block dasteht, die schließende Klammer weglassen kann. :o
Dachte da wohl an if mit einem Statement, wo man die Klammer ganz weglassen kann.

In beiden Fällen meine Blödheit
 
Oben