Laden...

Forenbeiträge von DerKleineTomy Ingesamt 96 Beiträge

06.05.2012 - 19:35 Uhr

Das Problem ist wohl, dass das absolute Grundlagen sind.

public void MoveImage(Image image, Point bildVerschieben)
{
    image.SetValue(Canvas.LeftProperty, bildVerschieben.X);
    image.SetValue(Canvas.TopProperty, bildVerschieben.Y);
}
06.05.2012 - 18:09 Uhr

Nein es gibt keine Erweiterungseigenschaften. Du könntest dir aber z.B. sowas bauen:


public static class KlasseCExtensions
{
    private static Dictionary<KlasseC, Dictionary<String, Object>> _properties = new Dictionary<KlasseC, Dictionary<String, Object>>;

    public static Typ GetPropertyA(this KlasseC obj)
    {
         // Prüfung ob Dictionaryeinträge vorhanden sind
         // ...
         return _properties[obj]["PropertyA"];
    }

     public static Typ SetPropertyA(this KlasseC obj, Typ value)
     {
         // Prüfung ob Dictionaryeinträge vorhanden sind
         // ...
         _properties[obj]["PropertyA"] = value;
     }
}

Edit: Da war jemand schneller

01.05.2012 - 22:17 Uhr

Genau das ist der richtige Weg. Einmal IndexOf('(') und einaml IndexOf(')'), dann Substring(start, start - end) und schon hast du was du willst. Da ist jetzt nicht viel zu verbessern.

25.04.2012 - 14:27 Uhr

Wenn ich dich richtig verstehe, dann willst du dass jeder Button weiß zu welchem ListViewItem er gehört. Du kannst beim erstellen, dass ListViewItem in dem Tag des Buttons speichern. In der Button_Click Methode kannst du dann den sender-Parameter zu Button casten, auf das Tag zugreifen und dieses dann zum ListViewItem casten.

24.04.2012 - 16:26 Uhr

Da es sich dann wohl um beliebige Objekte handelt wirds garnicht so leicht. Du musst dann wohl rekursiv vergleichen (wie herbivore schon gesagt hat), sowohl bei Klassen als auch bei Strukturen. Nur bei primitiven Typen und Strings kannst du dann wirklich Equals benutzen um diese zu vergleichen. Arrays musst du dann ebenfalls gesondert behandeln, indem alle Elemente einzeln miteinander verglichen werden.

Um zu deiner ursprünglichen Frage zurückzukommen:

Gibt es eine performantere Möglichkeit das zu lösen?

Die korrekte Lösung ist nicht performanter, ganz im Gegenteil, sie wird viel länger brauchen, je nachdem wie genau du den Vergleich haben willst.

23.04.2012 - 15:21 Uhr

Wie gesagt, es müssen nicht die gleichen sondern die selben sein. Also wenn es sich um Klassen handelt und du auch wirklich die selben hinzufügst, kannst du Equals und == benutzen, wie bereits gesagt.
Sind es Wertetypen, dann solltest du nicht == benutzen, zumindest nicht, wenn der Parameter als Object deklariert ist. Da hilft allerdings wieder Equals() weiter.
Wenn du zwei Objekte erzeugst, die gleich sind (aber nicht dieselben), dann hilft weder == noch Equals weiter.
Solltest du den Typen kennen, dann macht es wenig Sinn, dass die Methode Parameter vom Typ Object erwartet. Hier kannst du entweder einfach selber alle Properties vergleichen, oder auch IEquatable<T> implementieren, vorrausgesetz es ist dein eigener Typ.

Es gibt noch ein paar weitere Möglichkeiten, allerdings macht es wenig Sinn alle aufzuzählen, also würde ich dich bitten etwas mehr Informationen zur Verfügung zu stellen.

  1. Ist es notwendig, dass die Parameter vom Type Object sind? (Kennst du den Typen von Anfang an schon?)
  2. Handelt es sich um Klassen, Strukturen oder beides?
  3. Sind es selbst-definierte Typen?
23.04.2012 - 14:36 Uhr

Wenn es für alle Objekte einsetzbar sein soll gibt es wohl keine performantere Lösung, allerdings würde ich Equals statt ToString benutzen.
Wenn es die selben Objekte sind, reicht ein == oder Equals. Sollten es nur Wertetypen sein (was allem anschein nicht so ist) reicht ebenfalls ein Equals.
Wenn es zur Compilezeit unbekannte Typen sind, die sich auch nicht im Verlauf des Programmes ändern (oder nur selten ändern) ist es auch möglich eine DynamicMethod zu benutzen, die ohne Reflection auskommt.

22.04.2012 - 12:39 Uhr

im Vergleich zur Bremswirkung durch lock kann man die Beschleunigung durch "burst-fähige" Speicherzugriffe komplett vernachlässigen.

Ich hab mich wohl nicht ganz klar ausgedrückt. Ich beziehe mich auf das Konstrukt bei dem nicht parallelisiert wird, sondern nur die normalen Schleifen benutzt werden. Da sollte das Lock dann ja entfallen. Ich habe letztens erst durch das Vertauschen den Zugriff auf ein 500x500 Array um 25% beschleunigt.

Noch als Hinweis: Die Geschwindigkeit solltest du auf jedenfall im Releasemodus testen (wenn du es nicht schon tust), denn da verschwinden die Probleme manchmal von ganz allein 😃

21.04.2012 - 23:31 Uhr

Versuch mal die beiden For-Schleifen zu vertauschen, also erst y, dann x. Wenn WorldManager.Terrain.Heightmap ein zweidimensionales Array ist, dann sollte es zu einer Verbesserung kommen (weniger Sprünge beim Speicherzugriff).

14.04.2012 - 22:26 Uhr

Eigentlich sollte das Projekt, welches die Daten serialisiert, diese auch wieder deserialisieren können. Auf jedenfall muss ein und dieselbe Klasse beim serialisieren/deserialisieren benutzt werden, deswegen sollte die Klasse in eine dll ausgelagert werden, die von beiden Projekten referenziert wird.
Alternativ sollte der SerializationBinder auch Abhilfe schaffen, allerdings rate ich nicht dazu.

11.04.2012 - 14:19 Uhr

Ich hätte mal die Beschreibung von Keys.Menu lesen sollen. Da steht sogar, dass es die ALT-Taste ist. Wie dem auch sei, bei mir funktioniert der oben gezeigt Code, wenn KeyPreview auf true gesetzt ist.

11.04.2012 - 13:48 Uhr

Jetzt seh ich ich warum das Keys.Menu ist. Ich habs einfach mal getestet und wenn ich Alt+Enter drücke, wird mein MenuStrip ausgewählt. Vielleicht solltest du mal versuchen Keys.Menu zu benutzen.

11.04.2012 - 13:35 Uhr

Ja, kann ich dir sagen. Wenn du dir mal die Enumwerte in Visual Studio ansiehst (Rechtsklick auf Keys und dann "Go to Definition") dann wirst du sehen, dass einige Tasten eine Kombination aus anderen sind. Das liegt daran, dass es zu viele verschiedene Keys gibt und deswegen können nicht alle ihren eigenen Bit bekommen.
Allerdings ist Keys.RButton | Keys.ShiftKey = Keys.Menu und nicht Keys.Enter. Das kann ich aber nicht erklären 🤔

10.04.2012 - 20:26 Uhr

Da es um Bilder geht:
Wenn du das Bild in 2 geschachtelten for-Schleifen (einmal für y, einmal für x) durchgehst, musst du darauf achten, dass die äußere Schleife die y-Schleife ist. Da läuft das ganze schon ein Stück schneller.

10.04.2012 - 14:08 Uhr

Die Methode wird nur durchlaufen, wenn ein Objekt vom Typ T erwartet wird, aber eine ViewModelProperty<T> übergeben wird. In deinem Fall wird aber kein Objekt vom Typ T erwartet, also findet auch keine implizite Konvertierung statt. Wie man das löst weiß ich aber nicht 🙂

07.04.2012 - 18:40 Uhr

Du solltest dir die Methoden vom GraphicsPath mal genauer angucken. Ich glaube die Methode, die du suchst, heißt "IsVisible".

28.03.2012 - 13:26 Uhr

Soweit ich weiß funktioniert das nicht automatisch. Du musst es so machen:

        private void ChangeLanguage(Control root, CultureInfo culture)
        {
            ComponentResourceManager resources = new ComponentResourceManager(GetType());
            foreach (Control control in root.Controls)
            {
                resources.ApplyResources(control, control.Name, culture);
                ChangeLanguage(control, culture);
            }

        }

Genau sowas macht auch der Designer. Wenn du im Designercode der Form nachguckst, siehst du, dass bei jedem erstellten Control resources.ApplyResources(...) aufgerufen wird. Du musst aber aufpassen, da z.B. MenuStrips in dem Code nicht erkannt werden.
Da ist dann auch egal, ob du CurrentCulture im Thread änderst (solltest du aber zusätzlich machen).

27.03.2012 - 17:11 Uhr

mit Transparenz ist das halt so eine Sache. Wenn man beispielsweise mit Rot in voller Transparenz auf einen weißen Hintergrund zeichnet, ist die Farbe der betroffenen Pixel eben immer noch Weiß komplett ohne Transparenz.

Dessen bin ich mir bewusst, deswegen auch der CompositingMode. Natürlich hab ich vorher getestet, ob der Mode nur für DrawImage angewandt wird, was nicht der Fall ist. Ich konnte problemlos mit Brush.Transparent auf ein weißes Panel zeichnen und habe danach den grauen Hintergrund gesehen. Somit hat der CompositingMode einen Einfluss auf alle Methoden des Graphics-Objektes. Demnach war meine Vermutung, dass die Bitmap nicht alle Farben unterstützt. Wäre es nur zum Anzeigen gedacht, wäre es kein Problem, da die starken Farbveschiebungen nur bei sehr kleinen Alphawerten auftreten und somit kaum bis garnicht erkennbar sind.

27.03.2012 - 14:15 Uhr

Ich zeichne ja in eine Bitmap mit PixelFormat.Format32bppArgb (diese unterstützt anscheinend auch nicht alle Farben) und ich kopiere diese Werte niemals in eine zweite Bitmap. Das Problem ist halt, dass mit graphics.Fill...(brush, ...) der Bereich nicht genau die Farbe, wie im Brush angegeben, erhält. Für mich ist es aber sehr wichtig, dass der Wert exakt ist und ich keine ähnlichen Farben bekomme, auch wenn diese beim Zeichnen nicht auffallen würden.

[Hintergrundinformationen]
Der Hintergrund ist, dass ich zusätzliche Informationen in der Farbe hinterlegen will (im Alphawert). Dadurch will ich identifizieren welche Pixel im Bild durch graphics.FillEllipse(...) betroffen sind, da manuelle Berechnungen zu Abweichungen geführt haben. Natürlich kann ich die Pixel in der Bitmap auch einzeln setzen, sodass ich genau weiß, welche betroffen sind, allerdings wollte ich nicht auf die komplexeren Brushes wie TextureBrush und co. verzichten.
Da dies ja anscheinend nicht möglich ist, habe ich eine eigene Abwandlung der MemBitmap genutzt und selber den TextureBrush implementiert, um direkt in dem Bytearray der Bitmap zu "malen" und somit genau weiß welche Pixel betroffen sind. Allerdings muss ich dann wohl auf HatchBrushes verzichten, da die etwas schwerer zu implementieren sind.[/Hintergrundinformationen]

27.03.2012 - 11:46 Uhr

Das geht so nicht. Du musst die Werte vom einen in das andere kopieren (manuel oder via IClonable interface). Hier musst du aber wissen ob du eine flache oder eine tiefe Kopie haben willst. Ansonsten gibt es noch die Möglichkeit sich den Zustand oder die Änderungen zu merken und später wiederherzustellen, allerdings ist das wohl aufwendiger.

26.03.2012 - 19:18 Uhr

Ok, habs selber herausgefunden. Die Bitmap unterstützt nicht alle Farben. Die Werte werden gerundet. In einem Testprojekt hab ich einmal die Bitmap mit Color.FromArgb(1, 127, 210, 79) und einmal mit Color.FromArgb(1, 128, 210, 79) ausgefüllt. Alle Werte unter 128 werden auf 0 gesetzt (außer Alpha) und alle Werte über 127 werden auf 255 gesetzt (außer Alpha). Somit sind die beiden Farben komplett unterschiedlich.
Wenn jemand weiß wie man das umstellen kann (wenn es überhaupt möglich ist) wär ich sehr dankbar.

26.03.2012 - 18:16 Uhr

Die sind schon korrekt. Es passiert ja nur, wenn der Alphawert nachträglich auf 255 erhöht wird. Benutze ich direkt den Wert 255, sind alle Farben korrekt. MSDN bestätigt auch die Reihenfolge.

26.03.2012 - 17:27 Uhr

Auf dem linken Bild war der Alphawert 1 und auf dem rechten 10. Danach habe ich die Alphawerte bei beiden auf 255 erhöht. Wie man sieht sind die Farben unterschiedlich, obwohl sie nur mit unterschiedlichen Alphawerten gemalt wurden.
Die Farben sind: AliceBlue, Aqua, Beige, BlueViolet, YellowGreen und Violet.

Edit: Lasst euch vom Grid nicht ablenken ^^

26.03.2012 - 16:56 Uhr

Wie im Code zu erkennen, werden die Daten aus der Bitmap in das Array kopiert. "Marshal.Copy(data.Scan0, bytes, 0, numBytes);".
Das Byte-Array wird nur einmal für das ganze Bild erstellt, da es zu viel Performance kostet, das immer wieder zu erstellen. Ich gehe in der Schleife auch nur durch den relevanten Bereich in der Bitmap. Wenn ich dort die Alpha werte manuell auf 255 setze und mir die Bitmap anzeigen lasse, sieht man, dass viele Stellen die gleichen RGB Werte haben obwohl sie mit unterschiedlichen Farben bemalt wurden. Verschiedene Grün-Farben werden z.B. zum gleichen grün.

Edit: Mir ist aufgefallen, dass die Farbwerte immer weniger passen, wenn der Alphawert sinkt. Wenn ich male und danach in der Bitmap die Alphawerte einzeln auf 255 setze, kommen falsche Farben heraus. Ich möchte aber, dass in der Bitmap genau (!) die Farbe steht mit der ich auch male und keine ähnliche. Das fällt extrem stark auf, wenn ich mit einem Alphawert von 1 zeichne und danach manuell auf 255 erhöhe. (Verschiedene Blautöne werden zum gleichen Blau, helle Farben werden weiß, ...)

26.03.2012 - 16:08 Uhr

Ich zeichne mit einem SolidBrush auf eine Bitmap und benutze dabei transparente Farben. Als CompositingMode habe ich SourceCopy, sodass auch wirklich Alphawerte in die Bitmap geschrieben werden.
So nun zum Problem:
Die Farbwerte passen überhaupt nicht zu der Farbe, die ich aufmale. Es scheint so als würden nicht alle Werte unterstützt werden. Einige Farben werden einfach weiß, andere werden auf die nächst beste Farbe gesetzt. Z.B. wenn ich mit AliceBlue auf die Bitmap male, werden die RGB-Werte auf 255 gesetzt, aber der Alphawert ist korrekt (Im Byte-Array, welches ich durch LockBits und MarshalCopy bekomme, sehe ich die Werte).
Nutze ich Farben mit einem Alphawert von 255 funktioniert alles einwandfrei.
Meine Vermutung ist nun, dass nicht alle Farbkombinationen erlaubt sind, jedoch hoffe ich, dass es nicht so ist 😁

            // Bitmap erstellen
            _bitmap = new Bitmap(mapSize.Width, mapSize.Height, PixelFormat.Format32bppArgb);
            _graphics = Graphics.FromImage(_bitmap);
            _graphics.FillRectangle(Brushes.White, 0, 0, _bitmap.Width, _bitmap.Height);
            _graphics.CompositingMode = CompositingMode.SourceCopy;
            //Zeichnen
            _graphics.FillRectangle(Brush, rect);
            // Auslesen der Pixel
            BitmapData data = _bitmap.LockBits(clipRectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            Int32 numBytes = data.Stride * clipRectangle.Height;

            if (bytes == null)
                bytes = new Byte[data.Stride * _bitmap.Height];

            Marshal.Copy(data.Scan0, bytes, 0, numBytes);

            Int32 width = clipRectangle.Width;
            Int32 height = clipRectangle.Height;
            for (Int32 x = 0; x < width; x++)
                for (Int32 y = 0; y < height; y++)
                {
                    Int32 index = x * 4 + y * data.Stride;
                    Color color = Color.FromArgb(bytes[index + 3], bytes[index + 2], bytes[index + 1], bytes[index]);
                    // Hier passen die Farbwerte nicht mit dem des SolidBrush überein.
                }

            _bitmap.UnlockBits(data);
20.03.2012 - 16:37 Uhr

Da wohl keiner Lust hatte die Aufgabe zu lösen, poste ich meine Lösung. Somit ist das Programmierspiel wieder freigegeben (so wie es auch im ersten Post beschrieben ist, da keine Antwort innerhalb einer Woche kam).

        // input => Wort
        // index => Der aktuelle Buchstabe im Wort
        // stack => Der Stack
        // finalStates => Die Endzustände
        // Gibt <true> zurück, wenn das Wort abgearbeitet ist, der Stack leer ist und der letzte Zustand ein Endzustand war
        public Boolean ChangeState(List<String> input, Int32 index, Stack<String> stack, List<State> finalStates)
        {
            // Wenn das Wort abgearbeitet ist, nichts mehr auf dem Stack liegt und der momentane Zustand ein Endzustand ist...
            if (index >= input.Count && stack.Count == 0 && finalStates.Contains(this))
                return true; // Dann wurde das Wort erkannt

            // Alle Übergänge durchgehen
            foreach (var transition in Transitions)
            {
                // Wenn das Wort abgearbeitet ist, sind nur noch Epsilonübergänge erlaubt, andernfalls muss die Bedingung überprüft werden
                Boolean condition = index >= input.Count ? transition.IsEpsilon : transition.CheckConditions(input[index], stack);
                if (condition)
                {
                    String element = null;
                    // Den Stack ändern, außer bei Epsilonübergängen und leeren Stacks
                    if (stack.Count > 0 && !transition.IsEpsilon)
                        element = stack.Pop();

                    // Den Output vom Übergang auf den Stack legen
                    foreach (String str in transition.Output)
                        stack.Push(str);
                    // ------------

                    // Zum nächsten Zustand wechseln. Wenn es ein Epsilonübergang war, darf nicht zum nächsten Element im Wort gesprungen werden!
                    if (transition.NextState.ChangeState(input, index + (transition.IsEpsilon ? 0 : 1), stack, finalStates))
                        return true;

                    // Alle Änderungen auf dem Stack rückgängig machen
                    for (Int32 i = 0; i < transition.Output.Count; i++)
                        stack.Pop();

                    if (element != null)
                        stack.Push(element);
                    // ------------
                }
            }

            // Alle Übergange wurden geprüft und keiner hat zum Ziel geführt
            return false;
        }
14.03.2012 - 18:39 Uhr

Du sollst niemals ganze Controls serialisieren. Die Daten in deinem Property Grid kommen ja von irgendeinem Datenobjekt (propertyGrid.SelectedObject) und dieses kannst du serialisieren. Anschließend kannst du dieses Objekt laden und wieder im Property Grid anzeigen lassen. Zum Serialisieren gibt es mehrere Möglichkeiten z.B. XmlSerializer und BinaryFormatter. Wie das geht kannst du in der Doku nachschauen.

12.03.2012 - 14:55 Uhr

MSDN sollte dir die Antwort liefern. String.Intern

Edit: Außerdem Operator ==

10.03.2012 - 23:37 Uhr

Du kannst auch sowas machen, wenn du den Text hinter "WertX" setzen willst :


text = text.Replace("WertX:" + new String(' ', newText.Length), "WertX:" + newText);
10.03.2012 - 23:26 Uhr

Speicher die ComboBox in einer Membervariablen, damit zu Zugriff hast. Ansonsten kannst du die ChildControls vom Parentcontrol deiner ComboBox durchgehen und die ComboBox suchen, obwohl das wesentlich umständlicher wär.

10.03.2012 - 14:36 Uhr

Leider hab ich einen Fehler im vorgegebenen Code gefunden, zumindest stimmt es nicht mit der Beschreibung überein. Ich korrigiere den Fehler und mache die Stelle kenntlich. Hoffe niemand hat sich daran den Kopf zerbrochen 😦

Hier sind drei Test-Automaten:


        // Gleich viele "a" wie "b"
        private static PushDownAutomaton GleichVieleAundB()
        {
            PushDownAutomaton automat = new PushDownAutomaton();
            State startUndEndZustand = new State();

            // (eingabe, stack, ausgabe)
            // Wichtig zu beachten: Das was auf dem Stack liegt wird vom Stack genommen!
            Transition a_1 = new Transition("a", null, startUndEndZustand, "a"); // (a, leer, a) => a auf den Stack legen
            Transition a_2 = new Transition("a", "a", startUndEndZustand, "a", "a"); // (a, a, aa) => a verdoppeln (1 a wird zu 2 a)
            Transition a_3 = new Transition("a", "b", startUndEndZustand, null); // (a, b, nichts) => b vom Stack nehmen
            Transition b_1 = new Transition("b", null, startUndEndZustand, "b"); // (b, leer, b) => b auf den Stack legen
            Transition b_2 = new Transition("b", "b", startUndEndZustand, "b", "b"); // (b, b, bb) => b verdoppeln
            Transition b_3 = new Transition("b", "a", startUndEndZustand, null); // (b, a, nichts) => a vom Stack nehmen

            startUndEndZustand.Transitions.AddRange(new Transition[] 
            {
                a_1, a_2, a_3, b_1, b_2, b_3
            });

            automat.FinalStates.Add(startUndEndZustand);
            automat.StartState = startUndEndZustand;

            return automat;
        }

        // Es gibt mehrere mögliche Übergänge.
        // Anzahl von a = (2 + 4k) => 2, 6, 10, 14, ...
        // Ein etwas komplizierter Automat
        private static PushDownAutomaton MehrereÜbergänge()
        {
            PushDownAutomaton automat = new PushDownAutomaton();
            State startZustand = new State();
            State endZustand = new State();

            // (eingabe, stack, ausgabe)
            Transition start_1 = new Transition("a", null, startZustand, "a"); // (a, leer, a)
            Transition start_2 = new Transition("a", "a", startZustand, "a", "a"); // (a, a, aa)
            Transition start_3 = new Transition("a", "a", endZustand, null); // (a, a, nichts)

            Transition end_1 = new Transition("a", null, endZustand, "a"); // (a, leer, a)
            Transition end_2 = new Transition("a", "a", endZustand, "a", "a"); // (a, a, aa)
            Transition end_3 = new Transition("a", "a", startZustand, null); // (a, a, nichts)

            startZustand.Transitions.AddRange(new Transition[] 
            {
                start_1, start_2, start_3
            });

            endZustand.Transitions.AddRange(new Transition[] 
            {
                end_1, end_2, end_3
            });

            automat.FinalStates.Add(endZustand);
            automat.StartState = startZustand;

            return automat;
        }

        // Gerade Anzahl an a
        private static PushDownAutomaton EpsilonÜbergänge()
        {
            PushDownAutomaton automat = new PushDownAutomaton();
            State startZustand = new State();
            State endZustand = new State();

            // (eingabe, stack, ausgabe)
            Transition start_1 = new Transition("a", null, startZustand, "a"); // (a, leer, a)
            Transition start_2 = new Transition("a", "a", startZustand, "a", "a"); // (a, a, aa)
            Transition start_3 = new Transition(null, null, endZustand, null); // Epsilonübergang

            Transition end = new Transition("a", "a", endZustand, null); // (a, a, nichts)

            startZustand.Transitions.AddRange(new Transition[] 
            {
                start_1, start_2, start_3
            });

            endZustand.Transitions.AddRange(new Transition[] 
            {
                end
            });

            automat.FinalStates.Add(endZustand);
            automat.StartState = startZustand;

            return automat;
        }

        public static void Main(String[] args)
        {
            PushDownAutomaton automat = GleichVieleAundB();


            while (true)
            {
                String input = Console.ReadLine();
                List<String> word = new List<String>();
                foreach (Char c in input)
                    word.Add(c.ToString());

                Console.WriteLine(automat.CheckWord(word));
            }
        }
10.03.2012 - 13:28 Uhr

Weil es anscheinend nicht voran geht und Herbivore mich gebeten hat ein paar Sachen zu klären:

  1. Warum bekommt ChangeState eine List<String> und keinen normalen String:
    Ich wollte die Freiheit lassen, "Buchstaben" zu benutzen, die mehr als einen Zeichen lang sind. Wer will kann gerne einen normalen String nutzen und die einzelnen Chars durchgehen.

  2. Endzustände sind wie alle anderen Zustände zu behandeln. Der einzige Unterschied ist, dass nach abarbeiten des Wortes der letzte Zustand ein Endzustand sein muss, damit das Wort als gültig angesehen werden kann (zusammen mit der Bedingung, dass der Stack leer sein muss).

  3. Bei der Codevorgabe habe ich an eine rekursive Implementierung von ChangeState gedacht.

Tipp: Bei "Epsilonübergängen", also Übergängen die unabhängig von den Bedingungen immer (!) möglich sind, dürft ihr nicht zum nächsten Buchstaben weiter gehen. Der aktuelle Buchstabe wird sozusagen nicht verbraucht.

Ich werde nachher etwas Test-Code posten, damit ihr eure Implementierung testen könnt.

Außerdem hab ich bei der Code-Vorgabe noch ein paar Kommentare eingefügt.

06.03.2012 - 19:28 Uhr

Die Aufgabe ist es einen nichtdeterministischen Kellerautomaten (Push Down Automaton) zu programmieren. Er funktioniert so:


1) Er besitzt einen Stack (dieser ist am Anfang leer)
2) Er besitzt beliebig viele Zustände (q0, q1, ..., qn)
  - Einen Startzustand
  - Mindestens einen Endzustand
3) Jeder Zustand kann beliebig viele Zustandsübergänge haben (Auch wieder zu sich selbst)
4) Ein Übergang hat 3 Parameter (input, onStack, output)
- input => Der momentan betrachtete Buchstabe
- onStack => Der Buchstabe auf dem Stack (keiner ist auch möglich)
- output => Die Buchstaben (also auch mehrere), die auf den Stack gelegt werden, wenn der Zustand gewechselt wird.
- Der Übergang ist möglich, wenn der aktuell betrachtete Buchstabe == <input> ist und auf dem Stack <onStack> liegt. Wird der Übergang benutzt, wird <output> auf den Stack gelegt
- Wenn <input> leer ist ("" oder null) kann der Übergang immer (!) benutzt werden. In diesem Fall wird <onStack> ignoriert und auch nichts vom Stack entfernt. <output> wird ganz normal auf den Stack gelegt. Dieser Übergang ist eine Epsilonübergang.
5) Eine Eingabe (Wort) ist gültig, wenn zu jedem Buchstaben im Wort ein Übergang gegangen wurde, der Stack leer ist und der momentane Zustand ein Endzustand ist
6) Es kann auch mehrere mögliche Zustandsübergänge geben. Wenn mindestens (!) einer das Wort als gültig ansieht, ist es gültig.

Hier ist eine Codevorgabe

public class PushDownAutomaton
    {
        private Stack<String> stack = new Stack<String>();
        public State StartState;
        public List<State> FinalStates = new List<State>();

        public Boolean CheckWord(List<String> word)
        {
            stack.Clear();
            return StartState.ChangeState(word, 0, stack, FinalStates);
        }

    }

    // =================
    public class State
    {
        public List<Transition> Transitions = new List<Transition>();

        // input => Wort
        // index => Der aktuelle Buchstabe im Wort
        // stack => Der Stack
        // finalStates => Die Endzustände
        // Gibt <true> zurück, wenn das Wort abgearbeitet ist, der Stack leer ist und der letzte Zustand ein Endzustand war
        public Boolean ChangeState(List<String> input, Int32 index, Stack<String> stack, List<State> finalStates)
        {
              // Hier kommt euer Code hin
        }

    }

    // =================
    public class Transition
    {
        public String Input;
        public String OnStack;
        public List<String> Output = new List<String>();
        public State NextState;

        public readonly Boolean IsEpsilon;

        public Transition(String input, String onStack, State nextState, params String[] output)
        {
            Input = input;
            OnStack = onStack;
            NextState = nextState;

            IsEpsilon = String.IsNullOrEmpty(input);

            if (output != null)
                Output.AddRange(output);

        }

        // Überprüft, ob alle Bedingungen für den Zustandswechsel erfüllt sind.
        public Boolean CheckConditions(String input, Stack<String> stack)
        {
            if (String.IsNullOrEmpty(Input)) // Epsilonübergang
                //return Peek(OnStack, stack); // FEHLER BEHOBEN!!!
                return true;
            else // Normaler Übergang
                return Input == input && Peek(OnStack, stack);
        }

        // Kleine Hilfsmethode 
        private static Boolean Peek(String str, Stack<String> stack)
        {
            // Auf dem Stack darf nichts liegen, wenn <str> leer ist
            if (String.IsNullOrEmpty(str))
                return stack.Count == 0;

            // Ist <str> nicht leer, dann muss <str> auf dem Stack liegen
            return stack.Count > 0 && stack.Peek() == str;
        }
    }

Ich hoffe die ganzen Erklärungen schrecken euch nicht ab 😛. Es sind nicht mal 30 Zeilen Code nötig ⚠

06.03.2012 - 18:39 Uhr

Ah, jetzt versteht ichs 🙂. Hab gedacht NUR die aktuellen Nachbarn werden übersprungen 😁

Edit: Hab den Code editiert.

06.03.2012 - 18:08 Uhr

Hmm, irgendwie hab ich da wohl einen Denkfehler. Ich hoffe das kann mir jemand erklären:

  1. Wenn bei "string" die Elemente rechts und links vom 'r' übersprungen werden, müsste das Ergebnis doch 4 und nicht 3 sein oder?

  2. Da die Elemente der Reihe nach ausgewertet werden (vom 's' bis zum 'g') wird das 't' immer ausgewertet bevor bei 'r' SkipSiblings zurückgegeben wird oder gibt es da irgendeinen Kniff 🤔 Denn bereits bei 't' könnte SkipSiblings zurückgegeben werden und somit das 'r' übersprungen, was dann zur Folge hätte, dass ich das 't' vor dem 'r' auswerten muss.

06.03.2012 - 16:51 Uhr

So hab die Aufgabe gelöst, allerdings wird das Root-Objekt nicht an den Delegaten übergeben.


public static NodeResult SearchAsTree(this IEnumerable root, Func<object, NodeResult> evaluateNode)
        {
            Boolean skip = false;
            foreach (var child in root)
            {
                if (skip)
                {
                    //skip = false;
                    //continue;
                    break; // <-- Editiert!
                }
                NodeResult result = evaluateNode(child);

                if (result == NodeResult.Exit)
                    return NodeResult.Exit;

                if (result == NodeResult.SkipSiblings || result == NodeResult.SkipContainedAndSiblings)
                    skip = true;

                IEnumerable childNode = child as IEnumerable;
                if (childNode != null)
                {
                    if (result != NodeResult.SkipContained && result != NodeResult.SkipContainedAndSiblings)
                        if (childNode.SearchAsTree(evaluateNode) == NodeResult.Exit)
                            return NodeResult.Exit;
                }
            }

            return NodeResult.Continue;
        }

29.02.2012 - 16:04 Uhr

Mit Genauigkeit des Mouse-Events wird er die Zeit zwischen den Events meinen. Es wird ja nicht für jeden einzelnen Pixel ein Event ausgelöst was ja beim schnellen bewegen unglaublich viele wären. Deswegen kannst du es auch vergessen die Pixel einzeln zu Zeichnen, da du dann Lücken zwischen den Punkten hättest. Also ich würde Th69 zustimmen und Splines versuchen. Sie sind zwar auch nicht 100% korrekt aber trotzdem solltest du gute Kurven hinbekommen.

27.02.2012 - 18:33 Uhr

Was mir noch spontan einfällt sind die Enumerator-Objekte, die bei jeder foreach Schleife erstellt werden. In dem Codeauschnitt düften das ja die einzigen Objekte sein, die vom GC weggeräumt werden können. Du kannst ja die foreach Schleifen durch For Schleifen ersetzen und sehen was sich ändert.

Dann müsstest du allerdings massig viele Foreach schleifen durchlaufen lassen, damit ein Overflow kommt 🤔

26.02.2012 - 21:31 Uhr

Es sollte ja kein Problem sein einfach ein Interface zu deklarieren welches Convariant ist (IInterface<out T>). Dieses kannst du dann in der Klasse A<T> implementieren und gut ist. Dann musst du natürlich IInterface<Object> statt A<Object> benutzen.

26.02.2012 - 17:48 Uhr

Ergänzend zur Antwort von Coder007:
Covarianz funktioniert aber nicht mit Klassen, du müsstest ein Interface dafür benutzen.

24.02.2012 - 21:58 Uhr

Form1_Load wird nur einmal aufgerufen und zwar wenn die Form geladen wird (wie der Name bereits sagt 😛). Zu dem Zeitpunkt hat die Variable einen anderen Inhalt. Du müsstest direkt in dem Event Handler die Daten laden bzw. eine Methode aufrufen, die das übernimmt.

24.02.2012 - 21:08 Uhr

Der GC sammelt unreferenzierte Objekte ein. In deinem Fall zeigt die Variable bei jedem Schleifendurchlauf auf ein neues Objekt, also kann das alte Objekt (wenn es von keinem anderen Objekt referenziert wird) eingesammelt werden.

22.02.2012 - 18:01 Uhr

Deine Aussage bezueglich der Methoden ist nicht ganz richtig - es kommt darauf an, ob die Methode by Reference oder by Value aufgerufen wird.

Ich hab mich auf das Standardverhalten bezogen. Natürlich kann man die per Referenz übergeben. Aber gut, dass du es erwähnst, da meine Formulierung nicht eindeutig war und es zu Missverständnisses kommen könnte 😃.

22.02.2012 - 16:25 Uhr

Das kann gut sein denke ich, da Klasseninstanzen mehr Speicher verbrauchen, weil sie noch zusätzliche Headerdaten anlegen (wie z.B. eine Referenz zum zugehörigen Type). Structs hingegen verbrauchen keinen extra Platz wodurch sie schneller erstellt werden können. Der extra Speicher ist vor allem merklich, wenn du Klassen mit nur 2 Feldern benutzt.
Das dürfte aber nur beim Erstellen der Objekte eine Rolle spielen.
Du solltest nur beachten, dass Structs immer wieder kopiert werden und nicht per Referenz übergeben werden. Also wenn du sie ziemlich oft an verschiedene Methoden übergibst, kann es sein dass es etwas mehr Zeit kostet.
Sonst könntest du noch versuchen die Klasse als "sealed" zu markieren, mich würde es interessieren, ob dann Optimierungen möglich sind 😃

17.02.2012 - 22:15 Uhr

Der worst-case meiner Methode ist 2n Schleifendurchläufe, wenn im Array nur Elemente der Category First sind, was ebenfalls in O(n) liegt und somit in linearer Zeit fertig wird. Hab den code noch mal angepasst damit es nun auch konstant ist mit genau n durchläufen.

public static void Sort<T>(T[] items) where T : ICategorizable
 {
      Int32 start = 0;
      Int32 end = items.Length - 1;
      Int32 i = 0;
 
     while(i <= end)
      {
          T item = items[i];
          if (item.Category == Category.First && i > start)
              Swap(items, i++, start++);
          else if (item.Category == Category.Third)
              Swap(items, i, end--);
          else
               i++;
      }
 }

Edit:
@inflames2k: Das ist immernoch keine lineare Zeit 😛
@ dN!3L: Da war ich ein Stück scheller 😛

17.02.2012 - 20:19 Uhr

Erstmal hi 🙂

@inflames2k: Ja, das linear hat etwas zu bedeuten 😜

Hier ist meine Lösung:


public static void Sort<T>(T[] items) where T : ICategorizable
{
     Int32 start = 0;
     Int32 end = items.Length - 1;
     Int32 i = 0;

     while(i <= end)
     {
         T item = items[i];
         if (item.Category == Category.First && i > start)
             Swap(items, i, start++);
         else if (item.Category == Category.Third)
             Swap(items, i, end--);
         else
              i++;
     }
}

Ich möchte keine neue Aufgabe stellen bzw. es fällt mir keine ein, also kann jemand anderes gerne eine neue Aufgabe stellen 🙂