IT-Talents.de Code Competitions

Erzähl ;)

Entweder kann ich nicht inne halten, oder du willst dein Wissen herausposaunen, und dann sage ich dir das es nicht geht, oder so ähnliches ;)

Aber behalte dir vor,. ich bestimme die Zelle an den X und Y Koordinaten :)
 
@theSplit
Ich kann dein Problem einwandfrei nachvollziehen. Ich verstehe aber nicht, warum du es hast.

Was du ja im Detail machen müsstest ist, eine Linie von der alten zur neuen Mausposition zu berechnen, die du anschließend auf ein Pixelgrid oder gleich die Conway-Zellenstruktur quantisierst. Dann müsstest du feststellen, welche Zellen die Linie schneidet.

Das ist alles andere als trivial. Aber es darf überhaupt nicht als Problem auftauchen, denn diesen Low-Level-Kram muss dir dein Grafik-Toolkit abnehmen. Auf der Ebene alles selbst zu machen, wird zur Lebensaufgabe. Auf dem richtigen Abstraktionsniveau für ein Anwendungsprogramm bist du dann, wenn du sowas schreiben kannst:
Code:
Expand Collapse Copy
// grober Pseudocode
possibly_affected_cells =
        all_cells_in(Rect(last_mouse_pos, current_mouse_pos))

mouse_move_line = Line(last_mouse_pos, current_mouse_pos)

for cell in possibly_affected_cells:
    if mouse_move_line.intersects(cell.rect()):
        cell.setAlive()
Du nutzt SDL2 und Cairo, oder? Ich kenne die beiden nicht im Detail, aber die sollten doch wirklich Abstraktionen für solchen Code anbieten.
 


Stimmt. Ich bräuchte da eigentlich auch keinen eigenen Code, fällt mir gerade wieder ein. Das war, weil ich zuerst mit einer Bitmap-Klasse gearbeitet hatte und da kann man nur Pixel setzten oder lesen.

Wenn Split so etwas wie DrawLine zur Verfügung hat, dann macht es das natürlich einfacher.

Ansonsten:

MouseDown Event liefert den einen Punkt, MouseMove den zweiten

Zellenkoordinaten:
Die Koordinaten der Zelle bekommt man aus x = (e.X / Zellegröße) * Zellegröße;
Hä, das kürzt sich doch weg? Nein. Schmutziges Abrunden. Bei Teilen von int fällt der Nachkommateil weg.

Linie zeichnen:

ZeichneLinie(int x1,int x2,int y1,int y2)
{
Wenn (x1 == x2 && y1 == y2) dann raus;

SetzeZelle(x1, y1);
Solange ((Absolutgröße von (x1 - x2) != Zellegröße && Absolutgröße von (x1 - x2) !=0) || (Absolutgröße von (y1 - y2) != Zellegröße && Absolutgröße von (y1 - y2) !=0))
{
wenn (x1 + Zellegröße < x2)
{
x1 += Zellegröße;
}
sonst wenn (x1 + Zellegröße > x2)
{
x1 -= Zellegröße;
}

wenn (y1 + Zellegröße < y2)
{
y1 += Zellegröße;
}
sonst wenn (y1 + Zellegröße > y2)
{
y1 -= Zellegröße;
}

SetzteZelle(x1, y1);


}
SetzteZelle(x2, y2);
}
 
Guten Morgen :)

Also, wie ich es im Detail aktuell mache:

Was gezeichnet wird, entscheidet der Zellenstatus "lebend" (aktiv) oder nicht. Dabei wird in einem Array der Index im Zellenarray gesetzt. Es gibt keine Pixelmanipulation oder eine "Map" einer Pixelgrafik, die auf die Zellen ge"mapped" wird, und wo "Pixel" Schwarz = Zelle aktiv, oder "Pixel" weiß, inaktiv bedeutet. Das heißt, ich kann nicht mit simplen Grafikoperationen wie dem zeichnen einer Linie von MOVE1 x und y ZU MOVE2 x und y - zeichnen.

Das heißt ein "drawLineTo" funktioniert in so fern nicht direkt. Um dann zu wissen, wie die Zellen aktiv gesetzt werden oder nicht.

Zugegeben, wenn ich eine 1 zu 1 Pixel (auf 10x10 Zellen) Map hätte, hätte ich das Problem nicht, aber den Index im Array von Zellen, bestimme ich so:

[src=c]index = (floor(appEvent->button.x / (float) gameBoard->cellWidth)) + (floor(appEvent->button.y / (float) gameBoard->cellHeight) * gameBoard->cellsY);

cells[index].isAlive = true;

///usw....[/src]

Statt "SDL_EVENT->button (MOUSEBUTTONPRESSED/RELEASED) kann man auch SDL_EVENT->motion.x verwenden, letzteres spricht halt den MOUSEMOVE bzw. MOTION Event an - die alle von SDL_EVENT abgeleitet werden... (wie auch Keyboard Shortcuts und Co) und noch eigene Attribute haben, je nach Event Typ.
Für die relative X bzw Y Koordinate bietet der SDL_EVENT "MOTION" Typ bzw. SDL_EVENT->motion.xrel bzw. .yrel an (für die relative Mausbewegeung, seit dem letzten MOTION Event, also wenn die Maus im Fenster bewegt wird.)

Zu den SDL Events:
und
Zu Cairo Zeichenoperationen:
 


Aber das Prinzip bleibt doch das gleiche.

Im Handler von SDL_MouseButtonEvent fragst Du den Event-Typ ab und unterscheidest

SDL_MOUSEBUTTONDOWN:
1.den Zustand speichern: gedrückt =true
2. Die Koordinaten als letzte Position speichern

SDL_MOUSEBUTTONUP:
1.den Zustand speichern: gedrückt =false

DANN IN SDL_MOUSEMOTION:
1.Denn Index der Zellen berechnen. Mindestens für die 2 Punkte, sonst wie beschrieben auch die dazwischen.
2. Die Move-Koordinaten als neue letzte Position speichern
 


Aber das Prinzip bleibt doch das gleiche.

[...]

DANN IN SDL_MOUSEMOTION:
1.Denn Index der Zellen berechnen. Mindestens für die 2 Punkte, sonst wie beschrieben auch die dazwischen.
2. Die Move-Koordinaten als neue letzte Position speichern

Und dabei gibt es meiner Meinung nach ein Problem bei deiner Lösung - du veränderst ja "x" und "y" immer gleichzeitig im "Pseudocode".

Sagen wir, wir haben zwei Punkte: x20 y5 und x50 y30 (Differenz: x30, y25 (okay ist sehr hoch....)) und einen Zellengröße von 10x10 Pixeln.
Eigentlich müssten wir ja den größeren Wert nehmen von den beiden, abs(int) = +int.

Das Verhältnis in dem y zu x erhöht wird ist 1,2 in x und 1 in y. Korrekt?
Hier würde ich die größte Distanz einer Achse als Maßstab nehmen, und immer um das Verhältnisse, Schrittweise erhöhen.

Sonst glaube ich, das vielleicht etwas übersprüngen wird? - Hab das noch nicht damit ausgearbeitet.

[src=c]
int steps = abs(x) > abs👍 ? abs(x) : abs👍;

float inceaseX = (float) x / y; // Alles positive zahlen im Beispiel, hier checken ob eine Zahl negativ ist und dann korrigieren?
float increaseY = 1 // oder -1;

for (int i = 0; i < steps; ++i) {
// Koordinaten an Zeichenfunktion die testen ob wir einen Index an der Stelle haben und diese "aktiv" setzen, falls noch nicht aktiv, Minus, weil wir aktuell nur mit positiven Zahlen arbeiten
paintIfCellIsntLiving(currentX - (inceaseX * steps), currentY - (increaseY * steps));
}[/src]

Ich glaube so könnte es gehen, ist vermutlich das gleiche was du gemacht hast, jedoch würde ich den Weg "prozentual" abwandern, nicht um die gesamte Zellengröße vorranschreiten. Ist vielleicht etwas komplizierter, aber so würde es für mich Sinn machen.
 
Hab's jetzt nur grob verfolgt, aber bringt es euch weiter, wenn ich einwerfe, dass es für Linienzeichnen verschiedene Strategien bzw. Algorithmen gibt? Hatte das Gefühl, darauf will theSplit letztendlich hinaus.

Natürlich gilt das, was Brother John geschrieben hat.
 
Hm, sehr guter Einwand, die Mathematik dahinter und die der anderen Algorithmen, muss ich mir mal antun.
Ich habs jetzt mal ganz einfach gelöst - und auch mit "floats", was natürlich auch Rundungsfehler enthalten könnte, das habe ich im "Beispiel" auch nicht mit eingebracht. Also ohne die Verwendung von "floor", "ceil" oder "round".
 
Habe mal versucht, das mit dem Painting zu intergrieren, aber ich scheine da immer noch Probleme zu haben.

Es ist nicht 100%.... und das macht sich bei sehr schnellen Mausbewegungen bemerkbar. Obwohl ich in meinem Code die, "relativen" Pixel verwende:



Ich habe auch mal einen Integer Algorithmus von Wikipedia implementiert, aber das Ergebnis hatte auch nicht gepasst.

Und hier der Code dazu:
[src=c]

// Check if xDistance or y distance is either zero so we fill one axis
if (xDistance == 0 || yDistance == 0) {

// How much do we increase
int stepWidth = 0;

// How many steps do we take?
int steps = abs(xDistance) > abs(yDistance) ? abs(xDistance) : abs(yDistance);

if (xDistance == 0) {
// We only have movement in the y-axis
stepWidth = yDistance < 0 ? -1 : 1; // Positive or negative multiplicator

// Paint all relevant indexes
for (int i = 0; i < steps; ++i) {
index = (floor(appEvent->motion.x / (float) gameBoard->cellWidth)) + (floor((appEvent->motion.y + (stepWidth * i)) / (float) gameBoard->cellHeight) * gameBoard->cellsY);

// The index is valid, paint the cell living and increase living cell count by one
if (index < gameBoard->cellCount && !gameBoard->cells[index].isLiving) {
gameBoard->cells[index].isLiving = true;
++gameBoard->livingCells;
}
}
} else {
// We only have movement in the x-axis
stepWidth = xDistance < 0 ? -1 : 1; // Positive or negative multiplicator

// Paint all relevant indexes
for (int i = 0; i < steps; ++i) {
index = (floor((appEvent->motion.x + (stepWidth * i)) / (float) gameBoard->cellWidth)) + (floor(appEvent->motion.y / (float) gameBoard->cellHeight) * gameBoard->cellsY);

// The index is valid, paint the cell living and increase living cell count by one
if (index < gameBoard->cellCount && !gameBoard->cells[index].isLiving) {
gameBoard->cells[index].isLiving = true;
++gameBoard->livingCells;
}
}
}

// CUT....

// The largest distance determines how many steps we take
int steps = abs(xDistance) > abs(yDistance) ? abs(xDistance) : abs(yDistance);
//steps *= 2;

// How much do we increase x and y in every stepped round?
float stepWidthX = xDistance / steps; // Positive or negative additition for the x-axis
float stepWidthY = yDistance / steps; // Positive or negative additition for the y-axis

// Store the increment of x and y
float increaseX = 0.0;
float increaseY = 0.0;

for (int i = 0; i < steps; ++i) {
// Get the index, increase x by step and y by a rounded float increament each time
index = (floor((appEvent->motion.x + round(increaseX)) / (float) gameBoard->cellWidth)) + (floor((appEvent->motion.y + round(increaseY)) / (float) gameBoard->cellHeight) * gameBoard->cellsY);

// The index is valid, paint the cell living and increase living cell count by one
if (index < gameBoard->cellCount && !gameBoard->cells[index].isLiving) {
gameBoard->cells[index].isLiving = true;
++gameBoard->livingCells;
}

// Increase x and y by it stepwidth factor
increaseX += stepWidthX;
increaseY += stepWidthY;
}[/src]
 
Zuletzt bearbeitet:
Ich habe gerade nur kurz drauf geguckt und habe da erst einmal eine Frage, bevor ich weiter schaue.

Wieso bewertest Du abs(yDistance) "höher" als abs(xDistance), bei der Berechnung der Steps?
Die steps entsprechen der jeweils höheren Distance, aber, wenn sie beide gleich sind, dann wird yDistance genommen.

[src=c] int steps = abs(xDistance) > abs(yDistance) ? abs(xDistance) : abs(yDistance);[/src]
 
Sagen wir so, die "steps" geben an, wie viele Schritte in der For-Schleife zu gehen sind, genau. - Die Bevorzugung ob wir X oder Y nehmen, spielt in so fern keine direkte Rolle, meines Wissen nach. Selbst bei Gleichheit.
Wichtig, so war Idee, zu ermitteln welche Strecke die höhere von beiden ist damit wir die Bewegung nachempfinden können, egal welche der Achsen "führend" ist und die "Hauptrichtichtung" angibt wie die Maus bewegt wurde. (In relativen Pixeln zum letzten MOTION (MOVE) Event).

Eine Achse hat immer 1 Pixel Schrittweite, die andere idealerweise 0,25 oder ähnliches um die dann erhöht wird pro Schritt/Step.

Update:

So, ich habe gerausgefunden was mir die Lücken hereingehauen hat, jedenfalls die meisten, die Bewegung plus die zurückgelegte Distanz haben einen anderen Codebereich getriggert, der dann die Distanz auf eine Zelle bzw. 0 gesetzt hat für die Achsen.

Das habe ich nun beheben können. Das Problem, warum der Code drin war, wenn man mit der Maus das Fenster rechts oder links verlassen hat, während des Zeichnens, wurde die gegenüberliegen de Zellen(die einen Index weiter bzw. davor kommen im Array kommen) auch noch Lebendig gesetzt, da musste ich dann etwas tricksen um das Phänomen zu verhindern.



Update2: Habe nun herausgefunden wie ich die Lücken minimieren kann kein "rounding" von X und Y vornehmen, sondern in dem Fall ein "ceil"....
Und zwei Variablen mussten noch "zu" float "gecastet" werden, da waren wohl noch "ints" am Werk, dann scheints fast perfekt zu sein! :)

 
Zuletzt bearbeitet:
Habe ich die Frage oben wirklich gestellt? :D :m
Meine Fresse. Da war das Hirn wohl schon im Schlafmodus. In dem Moment kam mir das wie eine logische Überlegung vor.

Ich wollte mir den Code gerade ansehen.

Freut mich, daß Du den Fehler gefunden hast.
 
Du kannst dir den Code ja trotzdem ansehen ;)

Hänge gerade schon wieder an einer anderen Baustelle, haben PNG Export der Scene durch Cairo, ist da eine "Toy-API" und wirklich schnell realisiert, habe nur das Problem, ich kann die Szenen nicht rückimportieren über den Bildimport, da diese ohne Alpha Kanal ausgegeben werden, also als 24 Bit statt 32 bit PNGs.

Eine Variante wäre LibPNG "irgendwie" zu verwenden, aber da müsste ich dich Doku nochmal wälzen (umfangreich) oder den Pixelzugriff über SDL2 mit 24 Bit zu bewerkstelligen.

Laut Anleitung sind die Farbwerte als Tuple hinterlegt im 24 Bit verbund, aber ich weiß nicht genau wie ich darauf zugreifen muss.

Für 8 Bit und 32 Bit gibt es in der SDL2 Dokumentation eine schöne Dokumentation, nur 24 Bit ist mir nicht so verständlich. Entweder "pixelData[offset].r" (also im Struct) - oder so? "pixelData[offset][0] bis [2]" für RGB ?

Frage mich, warum steht das nicht dabei, IDRTFM.... :D

Ein , was das Problem zeigt das ich gerade habe, es wäre alles extrem cool ansonsten.

--- [2017-09-24 16:25 CEST] Automatisch zusammengeführter Beitrag ---

Update:

So, also, ich hab jetzt libPNG ins Boot geholt und damit funktioniert das speichern der Spielszene als PNG mit "Alpha" - dieses kann ich dann auch wieder direkt in das Spiel importieren. Allerdings ist das mit der Rasterung etwas unschön und es ist nicht ganz perfekt - aber es geht schon einmal direkt, ohne Umwege über Gimp. :)
 
So, Competition Beitrag für die IT-Talente ist abgegeben, irgendwie hab ich mir was aus den Fingern gesaugt was ich hätte dazu schreiben können, aber nun ja.
Und ich hab festgestellt, gleicher Code der eigentlich funktionieren sollte, selbst wenn es nicht für ein System getargetted ist, funktioniert gern mal absolut unterschiedlich bzw. unerwartet. :o

Habe heute Nacht mal ein Windows Build gebaut und getestet, das Feature was mich unter anderem mit die meisten Nerven gekostet hat.... funktioniert nur bedingt richtig. Das ist verdammt. ärgerlich/ernüchternd.
Hatte dann überlegt, es komplett rauszunehmen und einfach die "normale" Routine werken zu lassen, bei der ich mir denke, hätte einigermaßen funktionieren können - aber dann hatte ich auch keinen Bock mehr mir dafür mühe zu geben. Bevor ich aus irgendwelchen Gründe komplett vergesse, den Beitrag einzureichen und dann die Arbeit für umme gewesen wäre....

So bin ich jetzt erst mal dabei und hoffe das die jenigen, die den Code testen, wenigstens nen Linux Setup haben und NICHT ausschließlich Windows nutzen - sonst sehe ich etwas "schawärz" dafür, um nicht zu sagen Schwarz.
 
Ich denke schon, dass da irgendwo Linux läuft - und sei es auch nur in einer VM ;-)

Du hast da echt viele schöne Features eingebaut. Da wirst du vermutlich eine ganz schöne Bewertung kriegen :)
Da hat dich mein jüngster "Erfolg" ja richtig angespornt.
 
Genau, Ansporn ist gut :) - und wir wollen doch hier "Pokale" ins Forum"Regal" stellen. :T

Ansonsten, bin mal gespannt was dabei raus kommt.... muss aber sagen, so rein von der Problemstellung, war das etwas netter als der Versuch mit "Big Data" zu arbeiten, weil man zumindest gleich was gesehen hat, bei Big Data war es meiner Meinung nach viel schwerer, irgendwas zu visualisieren oder schnell Ergebnisse zu haben.

Hat mir auch Spaß gemacht, aber heute Nacht noch irgendwelche Windows Probleme zu "debuggen", dafür hatte ich aktuell leider keine Motivation mehr, Ich wollte das nun auch erst mal abschließen, weil auch die Dokumentation schreiben, Readmes, Hilfen über die Konsole, Startparameter usw...., man hätte, wenn man sich noch die Woche über hätte bemühen wollen, noch diverse andere Sachen einbauen können vermutlich. Aber ich dachte, bevor ich irgendwelche halbfertigen Features einbringe, die dann ja auch noch getestet und Dokumentiert und Code kommentiert werden will/wollen usw... erst mal genug. Die Faulheit hat gesiegt. ;)
 
Hilfe. Meine geistigen Fehlleistungen häufen sich hier.

Da habe ich in #303 gesagt, ich hätte die Standard DrawLine benutzen können. Dabei hatte ich doch bereits in #254 festgestellt, daß dem nicht so ist, weil ich ja nicht die Koordinaten der Maus mit einem Strich mit Breite einer Zellengröße verbinden, sondern das durch die Zellen vorgegebene Raster verwenden will.

attachment.php

Das zeigt mir
a) daß ich alt werde
und
b) das meine Beiträge nicht gelesen werden. (Hat ja keiner gemerkt :D)

;)
 
Ich glaube du wirst wirklich alt, bezogt sich das DrawLine nicht darauf, die "Interpolation" automatisch durchführen zu lassen?

Also im Grunde den Strich zu zeichnen und entsprechend "Rastern" zu lassen und damit indirekt auch Lücken zu füllen? :unknown:

Klang für mich fast so :D

Aber in deinem Beispiel von #254 ging doch alles?! - Vielleicht ist es deswegen niemanden aufgefallen :p
 
Ich lese zwar aber gerade bei dieser Diskussion nur halbherzig ;-)
 
Code Competition für Oktober 2017: Kampf gegen Mühlen

So, neuer Monat, neues Glück, neue Competition von IT-Talents.de!

Kampf gegen Mühlen 2017
Entwickle Deine Mühle-KI!

{ABOUT}

Deine Aufgabe bei diesem Hackathon ist es, das Spiel "Mühle" zu programmieren. Es soll eine Anzeige geben, auf der der Spieler seinen Zug machen und sehen kann. Ob Du dafür die Konsole nutzt, oder ein eigenes GUI, ist Dir überlassen. Das Besondere ist, dass Du nicht gegen eine andere Person spielst, sondern gegen eine KI. Eine KI, die Du selbst entwickelst und die ihren eigenen Zug berechnet. Wie schlau die KI ist, liegt ebenfalls bei Dir, Deine KI kann relativ "dumm" sein, oder mit ausgetüftelten Strategien arbeiten.


Zeitlicher Ablauf:

Abgabetermin:
31. Oktober 2017 - 23:59Uhr

Auswertung:
November 2017/Dezember 2017

Siegerehrung:
Dezember 2017/Januar 2018


Hier geht es zur Competition Seite mit weiteren Informationen.


Es winken wie immer auch Gewinne als Ansporn! :)

Allen Teilnehmern schon jetzt viel Erfolg, gutes Gelingen und je Menge Spaß!
 
Zurück
Oben