Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Lennart
myCSharp.de - Member



Dabei seit:
Beiträge: 429
Herkunft: Bawü

beantworten | zitieren | melden

Ich befürchte ich kenne kein Rätsel was den Anforderungen hier entspricht, euch also nicht total unterfordert ;). Etwas aus dem Internet raussuchen find ich auch irgendwie doof deswegen würde ich sagen wer was interessantes auf Lager hat darf das einfach an meiner Stelle posten.

gruß
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hall zusammen,

ich hätte was kleines feines wenn Lennart verzichtet.

Gesucht ist die Funktion Machwas() aus folgendem Code:


public static void Main(string[] args)
		{
			var matrix = new List<List<double>> {
				new List<double> { 1.0, 1.1, 1.2, 1.3 },
				new List<double> { 2.0, 2.1, 2.2, 2.3 },
				new List<double> { 3.0, 3.1, 3.2, 3.3 },
				new List<double> { 4.0, 4.1, 4.2, 4.3 }
			};
			
			var sentence = "Dies ist ein Beispielsatz";
			
			var iter = matrix.Machwas(...);
			
			var iter2 = sentence.Machwas(...);
				
			foreach( var item in iter ) {
				Console.WriteLine( item );
			}
			
			Console.WriteLine("\n");
			
			foreach( var item in iter2 ) {
				Console.WriteLine( item );
			}
		}
welcher folgende Ausgabe liefert:
Zitat
1
2
3
4
1,1
2,1
3,1
4,1
1,2
2,2
3,2
4,2
1,3
2,3
3,3
4,3


Dies
ist
ein
Beispielsatz

Ein paar Hinweise: Es ist offensichtlich eine Extension Method und es werden verschiedene Parameter übergeben um das Verhalten zu steuern - aber keiner der Parameter ist das Objekt auf das die Methode aufgerufen wird!

Ich hätte nun gerne den Code der Machwas() Methode und die Parameter mit denen er in den beiden Fällen aufgerufen wird. Die Aufgabe ist bissle was zum knobeln, technisch ist nichts arg kompliziertes dabei. Ich kann mir vorstellen das verschiedene Lösungen möglich sind, daher werde ich meine dann auch präsentieren (die wahrscheinlich nicht mal die schönstmögliche ist).

PS: Der Code ist übrigens einem Beispiel aus einem Buch nachempfunden. Für jemanden der dieses Buch hat und somit die Methode und die Parameter für die Matrix kennt, hoffe ich das die Parameter für den String noch ein bissle Spaß bringen ;)
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
DaemNice
myCSharp.de - Member



Dabei seit:
Beiträge: 67
Herkunft: Oberösterreich

beantworten | zitieren | melden

Sollen es 2 extensionmethods werden (klingt fast zu einfach) oder soll es wie ich vermute nur eine werden (auch wenn ich mir noch nicht vorstellen kann wie eine extensionmethod sowohl auf string als auch auf list<list<double>> angewendet werden soll).
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hallo,

genau eine Extension Method, auch nicht überladen oder so. In beiden Fällen wird genau die gleiche Funktion aufgerufen. Das man sich das im ersten Moment vielleicht nicht vorstellen kann ist mit ein Reiz des Rätsels ;)
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Hi,

hier mal meine Lösung... es geht sicher schöner, vor allem die matrixFunc, aber ich hab so lange kein C# mehr gemacht, dass ich gerade nur eine funktionierende Lösung haben wollte ;-)


public static void Main (string[] args)
		{
			
			var matrix = new List<List<double>> {
                new List<double> { 1.0, 1.1, 1.2, 1.3 },
                new List<double> { 2.0, 2.1, 2.2, 2.3 },
                new List<double> { 3.0, 3.1, 3.2, 3.3 },
                new List<double> { 4.0, 4.1, 4.2, 4.3 }
            };

            var sentence = "Dies ist ein Beispielsatz";

            var iter = matrix.MachWas(matrixFunc);

            var iter2 = sentence.MachWas(stringFunc);

            foreach( var item in iter ) {
                Console.WriteLine( item );
            }

            Console.WriteLine("\n");

            foreach( var item in iter2 ) {
                Console.WriteLine( item );
            }
		}
		
		public static IList<String> matrixFunc(IEnumerable list) {
			if(!(list is List<List<double>>)) {
				throw new ArgumentException("Expected List<List<double>>.");
			}
			List<List<double>> l = (List<List<double>>)list;
			IList<String> tmp = new List<String>();
			for(int i = 0; i < l[0].Count; i++) {
				for(int j = 0; j < l.Count; j++) {
					tmp.Add(l[j][i].ToString(CultureInfo.CreateSpecificCulture("de-DE")));
				}
			}
			
			return tmp;
		}
		
		public static IList<String> stringFunc(IEnumerable str) {
			if(!(str is String)) {
				throw new ArgumentException("Expected string");
			}	
			return ((String)str).Split(' ');
		}
		
		public static IList<String> MachWas(this IEnumerable obj, Func<IEnumerable, IList<String>> f) {
			return f(obj);
		}
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hallo,

Dein Code erzeugt ohne Frage die gewünschte Ausgabe, da kann man nichts gegen sagen. Aber ehrlich gesagt hab ich mit was ganz anderem gerechnet und schön ist der Code nicht wirklich (was nicht heißen soll das meine Lösung zwangsweise schöner ist *gg*).

Die statischen Funktionen grad mit dem rumgecaste in der matrixFunct sind nicht wirklich schön. Und das die Funktion bei ner double Matrix strings zurückgibt ist erst recht nicht schön.

Ich weiß das das keine Bedingung war, aber wenn du es nicht sehr eilig mit einer neuen Aufgabe hast (die du ja aufgrund der korrekten Ausgabe ja stellen darfst), dann würde ich gerne eine Lösung haben die vollkommen typsicher ist - sprich es gibt keinen einzigen Cast und die Aufzählung die von der Machwas() Methode zurückkommt, besitzt als Typparameter im allgemeinen den Typ der Elemente die man aus dem Ursprungsobjekt anzeigt(sprich, hier strings und double). Und eine weitere, wichtige Forderung die zugegebener Maßen nicht aus den beiden Beispielen ersichtlich wird -> Die Klasse auf dessen Objekt die Methode Machwas angewendet wird, muss nicht IEnumerable implementieren! Sie muss keine der .Net Aufzählungstypen sein. Folgendes ist mit meiner Lösung auch Problemlos möglich:

			var iter3 = 1.Machwas(...)
				
			foreach( var item in iter3 ) {
				Console.WriteLine( item );
			}
Und er gibt als Ausgabe die Zahlen von z.B. 1-10 aus. Oder auch 1-100, je nachdem wie man die Parameter wählt. Die Funktion Machwas ist dabei nachwievor genau die selbe.

Ich hoffe du nimmst mir die weiteren Forderungen nicht böse und dich packt nochmal der Ehrgeiz, weil wichtige Punkte und mögliche Lösungen dieser, hast du in der Fragestellung ganz richtig erkannt :)
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Hi,

so, hier die angepasste Lösung (etwas schöner, aber die Methode für die Matrix gefällt mir immernoch nicht, geht sicher schöner, aber das ist ja hier nicht gefragt, sondern die Lösung für das allgemeine Problem ;-) ):


public static void Main (string[] args)
		{
			
			var matrix = new List<List<double>> {
                new List<double> { 1.0, 1.1, 1.2, 1.3 },
                new List<double> { 2.0, 2.1, 2.2, 2.3 },
                new List<double> { 3.0, 3.1, 3.2, 3.3 },
                new List<double> { 4.0, 4.1, 4.2, 4.3 }
            };

            var sentence = "Dies ist ein Beispielsatz";

            var iter = matrix.MachWas((List<List<double>> l ) => {
				IList<double> tmp = new List<double>();
				for(int i = 0; i < l[0].Count; i++) {
					for(int j = 0; j < l.Count; j++) {
						tmp.Add(l[j][i]);
					}
				}
				return tmp;	});
			
			
			
            var iter2 = sentence.MachWas((string s) => { return s.Split(' '); });

            foreach( var item in iter ) {
                Console.WriteLine( item );
            }

            Console.WriteLine("\n");

            foreach( var item in iter2 ) {
                Console.WriteLine( item );
            }
		}
		
		public static TReturn MachWas<TReturn, T>(this T obj, Func<T, TReturn> f) {
			return f(obj);
		}
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hallo,

ich hätt wahrscheinlich noch mehr vorgeben müssen um eine Lösung in die Richtung zu bekommen wie ich eigentlich gewollt hätte, aber was solls, dein Code löst ja wie gesagt zumindest die Probleme die ich als Beispiel genannt hatte :) Nächstmal werd ich noch genauer sein :) Dachte durch die Verwendung von foreach und zwei völlig unterschiedlichen Objekten kommt man auf die Idee nen eigenen Iterator zu schreiben .

Hier mal meine Lösung die ein wenig anders arbeitet als deine:

public static IEnumerable<TItem>
			MakeCustomIterator<TCollection, TCursor, TItem>(
				this TCollection collection,
				TCursor cursor,
				Func<TCollection, TCursor, TItem> getCurrent,
				Func<TCursor, bool> isFinished,
				Func<TCursor, TCursor> advanceCursor) {
					while( !isFinished(cursor) ) {
						yield return getCurrent( collection, cursor );
						cursor = advanceCursor( cursor );
					}
				}
Das ist die Erweiterungsmethode. Am Namen sieht man schon gleich worauf ich eigentlich hinaus wollte. Einen allgemein für alles mögliche einsetzbaren Iterator. Und dieser ist so allgemein gehalten damit man mit Angabe der passenden Parameter über alles iterieren oder ihn auch als Generator nutzen kann wie mein 3. Beispiel mit der 1 zeigen wird.

Mein Code für die Aufrufe sieht nun so aus:

var iter = matrix.MakeCustomIterator(
				// Cursor zum Merken der Position
				new int[] { 0, 0, int.MaxValue},
				// Aktuelles Element zurückgeben
				(coll, cur) => {
					cur[2] = coll.Count;
					return coll[cur[0]][cur[1]];
				},
				// Prüfen ob fertig
				(cur) => cur[0] ≥ cur[2] || cur[1] ≥ cur[2],
				// Nächstes Element wählen
				(cur) => { 
					if(++cur[0] ≥ cur[2]){
						cur[0] = 0;
						cur[1]++;
					}
					return new int[] { cur[0],cur[1],cur[2]};
				});
			
			var iter2 = sentence.MakeCustomIterator(
				// Cursor zum Merken der Position
				new int[] { 0, 0, int.MaxValue },
				// Aktuelles Element zurückgeben
				(coll, cur) => {
					cur[2] = coll.Length;
					var idx = coll.IndexOf(" ",cur[1]);
					return coll.Substring(cur[0],(cur[1] = idx > -1 ? idx : coll.Length)-cur[0]);
				},
				// Prüfen ob fertig
				(cur) => cur[1] ≥ cur[2],
				// Nächstes Element wählen
				(cur) => {
					return new int[] { cur[0]=++cur[1], cur[1], cur[2]};
				}
			);
			
			var iter3 = 1.MakeCustomIterator(
				// Cursor zum Merken der Position
				new int[] {1},
				// Aktuelles Element zurückgeben
				(coll, cur) => coll*cur[0],
				// Prüfen ob fertig
				cur => cur[0] > 10,
				// Nächstes Element wählen
				cur => new int[] { ++cur[0]} );
wie man sieht ist diese Lösung extrems generalisiert und egal was man macht, es werden immer die gleichen Schritte ausgeführt. Und das ist eigentlich das schöne an dieser Lösung. Es werden nicht komplett unterschiedliche Funktionen aufgerufen wie in deiner Lösung sondern man gibt nur die Funktionalität der einzelnen Schritte vor. Durch das Cursorobjekt hat man auch den Vorteil das keinerlei temporäre Variablen nötig sind um irgendwelche Zwischenergebnisse sich zu merken wie bei mit der List in der Matrix Funktion.

Es stellt sich natürlich die Frage unter welchen Umständen ein solch generalisierter Code überhaupt sinnvoll erscheint, oder ob es nicht einfach overengineered ist. Nichtsdestrotz zeigt meiner Meinung nach so ein Code wie mächtig hier Generics und anonyme Methoden zusammenwirken.

Das Beispiel wurde übrigend dem Buch "Accelerated C#" aus dem Apress Verlag entnommen. Dort ist es für die Matrix aufgeführt.
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Ah, okay... da ich momentan fast nur noch funktional programmiere und da natürlich keine Iteratoren, geschweigedenn Schleifen verwende, bin ich garnicht auf die Idee gekommen es so zu lösen ;-)

Eine neue Aufgabe muss ich mir noch überlegen, werde aber so schnell wie möglich eine stellen.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

So, habe mir gerade eine hübsche Aufgabe überlegt.
Erstelle ein Banktransktionssystem, welches die Möglichkeit bietet Beträge von KontoA zu KontoB zu transferieren und die jeweiligen Kontostände abzufragen. Das ganze soll Threadsafe, aber OHNE Locking oder Synchronisation in dem Transaktionssystem erstellt werden. Es dürfen aber andere Strukturen benutzt werden, die schon Threadsafe sind (Listen, Queues...). Die Aufgabe ist nicht auf C# beschränkt, allerdings sollten keine Sprachen/Systeme benutzt werden, die STM bieten, wie z.B. Clojure oder Frameworks wie z.B. Akka für Scala.

Viel Spaß ;-)
private Nachricht | Beiträge des Benutzers
Floste
myCSharp.de - Member

Avatar #avatar-2376.jpg


Dabei seit:
Beiträge: 1158
Herkunft: Norddeutschland

beantworten | zitieren | melden

Schade, dass es hier nicht weitergeht, aber ich habe ehrlichgesagt auch keine lust obige aufgabe zu lösen.
Vielleicht fällt ja jemandem eine bessere ein.
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

Ich finde du hast recht. Hiermit erkläre ich die obige Aufgabe für nicht mehr gültig, weil obsolet. Jemand darf nun eine neue Aufgabe stellen. Der Erste der postet hat gewonnen.
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo zusammen,

ich würde einen Schritt weiter gehen und sagen, dass der Thread grundsätzlich wieder frei für eine neue Aufgabe ist, wenn eine Woche seit dem letzten Beitrag vergangen ist (egal ob dieser letzte Beitrag nun eine Aufgabe, eine Nachfrage oder eine Lösung ist und egal ob die Lösung richtig oder falsch war, also einfach: eine Woche Inaktivität = neue Aufgabe erlaubt).

herbivore
private Nachricht | Beiträge des Benutzers
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Wenn Corpsegrinder noch eine Lösung für seine eigene Aufgabe hätte, wäre das auch nicht schlecht :)
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Also ich habe jetzt keine programmierte Lösung parat, aber es wäre relativ einfach gewesen. Alle Transaktionen kommen in eine Queue und werden nacheinander abgearbeitet, so ist kein Lock und keine Synchronisation nötig ;-).

edit: lesen des aktuellen Kontostandes geschieht natürlich direkt...
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Corpsegrinder am .
private Nachricht | Beiträge des Benutzers
Arithmetika
myCSharp.de - Member



Dabei seit:
Beiträge: 69

beantworten | zitieren | melden

sorry aber eine Queue ist nicht Threadsafe und daher ist Synchronisation und Locking notwendig.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Zitat von Arithmetika
sorry aber eine Queue ist nicht Threadsafe und daher ist Synchronisation und Locking notwendig.

Wenn du meine Aufgabe gelesen hättest, dann wüsstest du, dass ich erlaubt habe Strukturen zu benutzen, die schon Threadsafe sind. Also auch eine Threadsafe Queue.

Hier aber nochmal eine Lösung, die ich eben erstellt habe:

import scala.actors.Actor
import scala.collection.immutable.HashMap

object Main {

  /**
   * @param args the command line arguments
   */

  def main(args: Array[String]) = {
    TransactionSystem ! ('create, "foo", 4000.)
    TransactionSystem ! ('create, "bar", 0.)
    TransactionSystem ! ('transfer, "foo", "bar", 2000.)
    println(TransactionSystem !? Tuple2('balance, "foo"))
    println(TransactionSystem !? Tuple2('balance, "bar"))
    TransactionSystem ! 'exit
  }

  object TransactionSystem extends Actor {
    start
    case class Account(val amount: Double)
    def act {
      act(HashMap[String, Account]())
    }
    def act(accs: HashMap[String, Account]): Unit = {
      react {
        case ('transfer, from: String, to: String, amount: Double)
          if(accs.contains(from) && accs.contains(to) &&
             accs(from).amount ≥ amount) => {
            act(accs.filter((acc) => acc != from && acc != to) ++
                HashMap(from -> Account(accs(from).amount - amount),
                        to -> Account(accs(to).amount + amount)))
        }
        case ('create, name: String, amount: Double) if(!accs.contains(name)) => act(accs ++ HashMap(name -> Account(amount)))
        case ('balance, name: String) if(accs.contains(name)) => reply(Some(accs(name).amount)); act(accs)
        case 'exit => exit
        case _ => println("Operation could not be completed."); act(accs)
      }
    }
  }

}
private Nachricht | Beiträge des Benutzers
Floste
myCSharp.de - Member

Avatar #avatar-2376.jpg


Dabei seit:
Beiträge: 1158
Herkunft: Norddeutschland

beantworten | zitieren | melden

So, da immernoch keine neue aufgabe da ist, habe ich mal versucht eine zu machen (besonders kreativ is sie nicht, aber lösbar):

Aufgabe:
Schreibe ein programm, das das gemeinsame kgv (= kleinste gemeinsame vielfache) aller Zahlen in der liste im anhang in unter 10 sekunden findet. Das programm soll also genau eine zahl ausgeben.

Optional / Wünschenswert ist:
-lösen aufgabe in unter 1 sec
-möglichst simpler code
-eine gute nächste aufgabe in petto haben
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Floste am .
Attachments
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1380
Herkunft: Berlin

beantworten | zitieren | melden

Mit .NET 4.0 würd ichs wie folgt machen:

using System;
using System.Numerics;
using System.IO;
using System.Linq;

public class LeastCommonMultiple
{
	public static void Main()
	{
		Console.Write(
			File
			.ReadAllLines("numbers.txt")
			.Select(s => BigInteger.Parse(s))
			.Aggregate((oldLCM, nextNumber) => 
				(oldLCM * nextNumber) / BigInteger.GreatestCommonDivisor(oldLCM, nextNumber)
			)
		);
	}
}

ergibt:
231448880682398148

beste Grüße
zommi
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von zommi am .
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7548
Herkunft: Waidring

beantworten | zitieren | melden

Hallo zommi,

wenn statt ReadAllLines ReadLines verwendet wird sollte es noch ein wenig schneller gehen da nicht zuerst die ganze Datei gelesen werden muss bevor mit Select fortgefahren werden kann. ReadLines enumeriert die Zeilen während ReadAllLines ein Array von Zeilen zurückgibt.

Sonst: Super Ansatz!


mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
Floste
myCSharp.de - Member

Avatar #avatar-2376.jpg


Dabei seit:
Beiträge: 1158
Herkunft: Norddeutschland

beantworten | zitieren | melden

o.O, so war das nicht geplant, die funktion gibts in .net 3.5, das ich noch verwende ned.


Das ergebnis sieht aber richtig aus.
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1380
Herkunft: Berlin

beantworten | zitieren | melden

Mhh.. aus Flostes Antwort konnte ich jetzt nicht herauslesen, wie zufrieden er mit der Lösung ist. Aber ich sehs mal als gelöst an :D

Also meine neue Aufgabe:
Zitat von dem neuem Aufgabensteller
Es wird Hacky:
Ihr sollt ein bischen Code schreiben, der aus einem gegebenen int[]-Array ein kleines Teilstück als neues int[]-Array extrahiert. Quasi ein SubArray. Aber so, dass Veränderungen am SubArray real im Ausgangsarray zu bemerken sind. Das SubArray muss also noch immer, speichermäßig, irgendwie, im großen Array "drin" liegen.

Ich gebe folgende Programmrahmen vor:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

class Program
{
	static void Main(string[] args)
	{
		// Zahlen Array erzeugen und im Speicher festpinnen
		int[] numberArray = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
		GCHandle gch = GCHandle.Alloc(numberArray, GCHandleType.Pinned);

		// Aufruf der magischen Funktion, die ein .NET Array erzeugt,
		// das ein reales Unter-Array ist
		int[] subArray = SubArrayMaker.GetSubArray(numberArray);

		// Sicherstellen, dass das Array an Position 5 und 6 noch intakt ist.
		if (numberArray[5] != 5 || numberArray[6] != 6)
			return;

		// das Unter-Array komplett mit Nullen füllen
		lock(subArray) // nur aus Spaß gelockt, ihr seht schon warum ;)
			Array.Clear(subArray, 0, subArray.Length);

		// Überprüfen ob die 5te Stelle nun 0 ist, aber die 6te noch unverändert
		if (numberArray[5] == 0 && numberArray[6] == 6)
			Console.WriteLine("SUCCESS");
	}
}

public class SubArrayMaker
{
	// ... ToDo: Implement! ... //
}

Ihr sollt der Klasse SubArrayMaker Leben einhauchen, sodass "SUCCESS" ausgegeben wird.
Man erkennt schon, dass das SubArray von seiner Länge her bis zum 6. Element des Ausgangsarrays gehen muss.

Kern der Aufgabe ist zu experimentieren, wie man ein managed .NET Objekt "konstruieren" kann, ohne jemals "new" aufgerufen zu haben und das dann auch noch in eine echte Objekt-Referenz zu pressen.

Das ganze ist tricky und erfordert wahrscheinlich unsafe-Pointer-Arithmetik. Man muss schon etwas über die CLR-Internas nachlesen und in ihren Eingeweiden rumfummeln ;)
Aber alles wichtige ist im Abschnitt "Object Instances" unter Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects zu finden.

PS: Ich empfehle ein 32-Bit System. Da ich selbst kein 64-Bit System verwende, kann ich nich garantieren, dass es dort auch eine Lösung gibt / machbar ist.

Ich wünsche viel Vergnügen und spannende Einsichten ;-)
Und bei Fragen, einfach fragen.

beste Grüße
zommi
Dieser Beitrag wurde 6 mal editiert, zum letzten Mal von zommi am .
private Nachricht | Beiträge des Benutzers
Floste
myCSharp.de - Member

Avatar #avatar-2376.jpg


Dabei seit:
Beiträge: 1158
Herkunft: Norddeutschland

beantworten | zitieren | melden


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Modus: "+(IntPtr.Size*8)+"bit");
            // Zahlen Array erzeugen und im Speicher festpinnen
            int[] numberArray = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
            GCHandle gch = GCHandle.Alloc(numberArray, GCHandleType.Pinned);

            // Aufruf der magischen Funktion, die ein .NET Array erzeugt,
            // das ein reales Unter-Array ist
            int[] subArray = SubArrayMaker.GetSubArray(numberArray);

            // Sicherstellen, dass das Array an Position 5 und 6 noch intakt ist.
            if (numberArray[5] != 5 || numberArray[6] != 6)
                return;

            // das Unter-Array komplett mit Nullen füllen
            lock (subArray) // nur aus Spaß gelockt, ihr seht schon warum ;)
                Array.Clear(subArray, 0, subArray.Length);

            // Überprüfen ob die 5te Stelle nun 0 ist, aber die 6te noch unverändert
            if (numberArray[5] == 0 && numberArray[6] == 6)
                Console.WriteLine("SUCCESS");

            Console.ReadLine();
        }
    }

    public class SubArrayMaker
    {
        delegate IntPtr pRefToPtr(ref object reference);
        static pRefToPtr RefToPtr=MakeRefToPtr();

        private static pRefToPtr MakeRefToPtr()
        {
            DynamicMethod meth = new DynamicMethod("GetAddr", typeof(IntPtr), new Type[1] { typeof(object).MakeByRefType() },typeof(SubArrayMaker),true);
            ILGenerator gen= meth.GetILGenerator();
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Conv_I);
            gen.Emit(OpCodes.Ret);
            return (pRefToPtr)meth.CreateDelegate(typeof(pRefToPtr));
        }

        struct ArrayHeader
        {
            public IntPtr Syncblock1;
            public IntPtr TypeId;
            public IntPtr Length;
        }

        public static unsafe int[] GetSubArray(int[] numberArray)
        {
            ArrayHeader* oldArray = &(((ArrayHeader*)Marshal.UnsafeAddrOfPinnedArrayElement(numberArray, 0))[-1]);
            ArrayHeader* newArray=&(((ArrayHeader*)Marshal.UnsafeAddrOfPinnedArrayElement(numberArray, 5))[-1]);
            *newArray = *oldArray;
            newArray->Length = (IntPtr)1;

            object array = null;
            IntPtr* pArrayVar = ((IntPtr*)RefToPtr(ref array));
            *pArrayVar = (IntPtr)(&(newArray->TypeId));
            return (int[])array;
        }
    }

Geht unter 32 und 64 bit!
( aber auch nur, weil .net von m$ die letzten 4 bytes der arraylänge ignoriert, weil arrays mit 32 bit ints indiziert werden.)
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Floste am .
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1380
Herkunft: Berlin

beantworten | zitieren | melden

Sehr schön

Meine Implementierung (für 32Bit) war:

public class SubArrayMaker
{
    public unsafe static int[] GetSubArray(int[] array)
    {
        fixed (int* ptr = array)
        {
            ptr[0] = 0;         // SyncBlock
            ptr[1] = ptr[-2];   // TypeInformation übernehmen
            ptr[2] = 3;         // Length

            return ConvertPointerToIntArrayReference(ptr + 1); 
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    unsafe struct IntArrayHolder
    {
        public int[] array;
        public int* ptr;
    }

    unsafe static int[] ConvertPointerToIntArrayReference(int* ptr)
    {
        IntArrayHolder ah = new IntArrayHolder();
        (&ah.ptr)[-1] = ptr; // Referenz überschreiben
        return ah.array;
    }
}

Dann ist der Ball jetzt wohl wieder bei Floste
private Nachricht | Beiträge des Benutzers
Floste
myCSharp.de - Member

Avatar #avatar-2376.jpg


Dabei seit:
Beiträge: 1158
Herkunft: Norddeutschland

beantworten | zitieren | melden

Etwas skurril, aber ich stells mal trotzdem:

Schreibe ein programm, das folgendes tut:
wenn das programm ohne adminrechte läuft soll es nach diesen fragen. (runas)
danach soll es cmd.exe auf dem interactive service desktop starten.
Wichtig ist:
-das zu keinem zeitpunkt ein autostart installiert wird (darunter verstehe ich eine komponente/service/programm das beim systemstart automatisch geladen wird)
-der pc nicht neugestartet wird und weiterhin funktioniert
-am ende keinerlei listen- oder serviceeinträge übrigbleiben (wenn erstellt, müssen diese hinterher wieder entfernt werden.)
-keine dateien außerhalb des programmordners geschrieben werden. (am besten garkeine)
Außerdem soll das ganze am besten sofort und nicht erst nach einer minute passieren.

Es dürfen sämtliche .net und windows boardmittel benutzt werden, inklusive sämtlicher kommandozeilenprogramme.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Floste am .
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo zusammen,

nachdem (mehr als) eine Woche ohne Antwort vergangen ist, ist entsprechende der Regeln die letzte Aufgabe (leider) obsolet und der Ball ja wieder frei. Ich nutze diesen Umstand für eine neue, hoffentlich populärere Aufgabe.

Es geht darum eine Methode zu schreiben, die ein Array von fünf Integers bekommt, das das Ergebnis von fünf Spielwürfelwürfen repräsentiert und als Ergebnis ein Array aller bei diesem Wurf möglichen Punkte nach den Kniffelregeln liefert.

Vorgegeben ist folgender Enum


public enum Scores
{
   Ones,            // Sum of Ones
   Twos,            // Sum of Twos
   Threes,          // Sum of Threes
   Fours,           // Sum of Fours
   Fives,           // Sum of Fives
   Sixes,           // Sum of Sixes
   ThreeOfAKind,    // Sum of all dice
   FourOfAKind,     // Sum of all dice
   FullHouse,       // 25
   SmallStraight,   // 30
   LargeStraight,   // 40
   Yahtzee,         // 50
   Chance           // Sum of all dice
}

der die Indexwerte für das zurückgelieferte Array definiert. Das zurückgelieferte Array hat also eine Länge von Enum.GetValues (typeof (Scores)).Length und enthält als Werte die Punkte, die durch den übergebenen Wurf in jeder der Kategorien erzielt werden können.

Die Signatur der Methode ist ebenfalls vorgegeben:

public static int [] GetPoints (int [] dice)

Getestet werden kann mit der folgenden Methode, die indirekt auch alle Zweifelsfälle bei der Interpretation von Ein- und Ausgabe der GetPoints-Methode klären sollte, insbesondere, dass die Werte der Würfelwürfe nicht als 1..6 sondern zerobased als 0..5 repräsentiert werden.


public static void Main (string [] astrArg)
{
   Random rand = new Random ();

   int [] dice = new int [5];

   for (int i = 0; i < dice.Length; ++i) {
      dice [i] = rand.Next (6); // also Werte von einschließlich 0 bis einschließlich 5
   }

   int [] points = GetPoints (dice);

   foreach (Scores score in Enum.GetValues (typeof (Scores))) {
      Console.WriteLine ("{0,15} {1}", score, points [(int)score]);
   }
}

Jetzt noch ein Beispiel. Das Eingabe-Array { 0, 4, 4, 0, 4 }, sprich zwei Einer und drei Fünfer (sic!), würde folgende Ausgabe produzieren:
         Ones 2
         Twos 0
       Threes 0
        Fours 0
        Fives 15
        Sixes 0
 ThreeOfAKind 17
  FourOfAKind 0
    FullHouse 25
SmallStraight 0
LargeStraight 0
      Yahtzee 0
       Chance 17

Es werden also alle Punkte angezeigt, die bei diesem Wurf möglich sind.

Es soll kein komplettes Kniffelspiel implementiert werden, sondern nur die eine wichtige Hilfsmethode GetPoints. Der Code meiner Implementierung dieser Methode ist knapp über 50 (normal formatierte) Zeilen lang. Die Aufgabe sollte also keine besondere Hürde darstellen, aber trotzdem Spaß machen!

herbivore
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

public static int [] GetPoints (int [] dice)  {
    int[] result = new int[Enum.GetValues(typeof(Scores)).Length];

    var getCount = new Func<int, int>((i) => dice.Where((d) => d == dice[i]).Count());

    Array.Sort(dice);

    result[(int)Scores.Ones] = dice.Where((d) => d == 0).Count() * 1;
    result[(int)Scores.Twos] = dice.Where((d) => d == 1).Count() * 2;
    result[(int)Scores.Threes] = dice.Where((d) => d == 2).Count() * 3;
    result[(int)Scores.Fours] = dice.Where((d) => d == 3).Count() * 4;
    result[(int)Scores.Fives] = dice.Where((d) => d == 4).Count() * 5;
    result[(int)Scores.Sixes] = dice.Where((d) => d == 5).Count() * 6;
    result[(int)Scores.ThreeOfAKind] = getCount(0) ≥ 3 || getCount(2) ≥ 3 || getCount(4) ≥ 3 ? dice.Sum((d) => d + 1) : 0;
    result[(int)Scores.FourOfAKind] = getCount(0) ≥ 4 || getCount(4) ≥ 4 ? dice.Sum((d) => d + 1) : 0;
    result[(int)Scores.FullHouse] = result[(int)Scores.ThreeOfAKind] > 0 ? (getCount(0) == 2 || getCount(4) == 2 ? 25 : 0) : 0;

    bool largeStraight = true;
    var num = dice[0];

    for (int i = 0; i < 5; i++) {
        largeStraight = largeStraight && (dice[i] == i + num);
    }

    result[(int)Scores.LargeStraight] = largeStraight ? 40 : 0;

    bool smallStraight = false;
    var arr = dice.Distinct().ToArray();

    if (arr.Length ≥ 4) {
        var slice = arr.Take(4).ToArray();
        
        num = slice[0];
        smallStraight = true;

        for (int i = 0; i < 4; i++) {
            smallStraight = smallStraight && (slice[i] == i + num);
        }
        
        if (!smallStraight && arr.Length == 5) {
            slice = arr.Skip(1).ToArray();
            smallStraight = true;
            num = slice[0];

            for (int i = 0; i < 4; i++) {
                smallStraight = smallStraight && (slice[i] == i + num);
            }
        }
    }

    result[(int)Scores.SmallStraight] = smallStraight ? 30 : 0;
    result[(int)Scores.Yahtzee] = getCount(0) == 5 ? 50 : 0;
    result[(int)Scores.Chance] = dice.Sum((d) => d + 1);

    return result;
}
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von TheBrainiac am .
Attachments
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo TheBrainiac,

deine Lösung ist korrekt [EDIT=bis auf, dass Yahtzee auch als Fullhouse zählt (siehe Anmerkung von N1ls)[/EDIT]. Du bist mit der nächsten Aufgabe dran.

Hier zum Vergleich noch, wie ich mir das vorgestellt hatte [EDIT=korrigiert, dass Yahtzee auch als Fullhouse zählt[/EDIT]. Basierend auf dem Vorschlag in Kniffelspiel: Ermitteln, was geworfen wurde (z.B. Full House), ohne alle Kombinationen abzufragen habe ich zunächst ein Array aufgebaut, in dem für jede Augenzahl steht, wie oft die jeweilige Augenzahl gewürfelt wurde, um die anschließenden Berechnungen zu vereinfachen:


   public static int [] GetPoints (int [] dice)
   {
      int [] diceCounts = new int [6];
      int [] points = new int [Enum.GetValues (typeof (Scores)).Length];
      int    sumOfAllDice = 0;
      int    straight = 0;
      int    maxStraight = 0;
      bool   full = false;
      bool   house = false;

      for (int i = 0; i < dice.Length; ++i) {
         ++diceCounts [dice [i]];
         sumOfAllDice += dice [i] + 1;
      }

      for (int i = 0; i < diceCounts.Length; ++i) {
         points [i] = diceCounts [i] * (i + 1);
         if (diceCounts [i] > 0) { ++straight; }
         else { if (straight > maxStraight) { maxStraight = straight; } straight = 0; }
         if (diceCounts [i] == 2) { full = true; }
         if (diceCounts [i] ≥ 3) { points [(int)Scores.ThreeOfAKind] = sumOfAllDice; house = true; }
         if (diceCounts [i] ≥ 4) { points [(int)Scores.FourOfAKind] = sumOfAllDice; }
         if (diceCounts [i] ≥ 5) { points [(int)Scores.Yahtzee] = 50; points [(int)Scores.FullHouse] = 25; }
      }
      if (full && house) { points [(int)Scores.FullHouse] = 25; }
      if (straight > maxStraight) { maxStraight = straight; }
      if (maxStraight ≥ 4) { points [(int)Scores.SmallStraight] = 30; }
      if (maxStraight ≥ 5) { points [(int)Scores.LargeStraight] = 40; }
      points [(int)Scores.Chance] = sumOfAllDice;

      return points;
   }

herbivore
private Nachricht | Beiträge des Benutzers
m0rius
myCSharp.de - Member

Avatar #avatar-3125.png


Dabei seit:
Beiträge: 1043

beantworten | zitieren | melden

Hallo herbivore,

wenn ich mir deine Technik zum Ermitteln eines Full Houses ansehe, muss ich gerade über meinen eigenen Code lachen, den ich vor 1 1/2 Jahren dazu geschrieben habe :D ...
Die Kernidee war dabei folgende:

for (int index = 0; index < pipsOccurrences.Length; index++)
{
    int occurrence = pipsOccurrences[index];

    if (occurrence != 0)
    {
        occurrencesProduct *= occurrence;
    }
}

// The product of the occurrences of the non-zero values needs to be 6
// e.g. 4-4-4-6-6 is a valid Full House because we have 3 fours and 2 sixes
// => 2*3 = 6 (6 is only factorizable into 1*6 and 2*3; 1*6 cannot appear)
if (occurrencesProduct != 6)
{
    return false;
}

m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Die neue Aufgabe:

Entwickle einen simplen Kompressions-Algorithmus!

Vorgegeben ist folgendes Snippet (Vollständige Vorlage siehe Anhang):

using System;
using System.Text;

public class Compression
{
    public static void Main() {
        string input = /*Gekürzt! Siehe Anhang!*/"";
        byte[] uncompressed = Encoding.ASCII.GetBytes(input);
        byte[] compressed = Compress(uncompressed);
        byte[] decompressed = Decompress(compressed);
        string output = Encoding.ASCII.GetString(decompressed);
        double ratio = (1d - (double)compressed.Length / (double)uncompressed.Length) * 100;
        bool equal = input == output;
        bool success = ratio > 10d && equal;
        
        Console.WriteLine("Uncompressed Length: {0}", uncompressed.Length);
        Console.WriteLine("Compressed Length: {0}", compressed.Length);
        Console.WriteLine("Decompressed Length: {0}", decompressed.Length);
        Console.WriteLine("Compression Ratio: {0:0.0000}%", ratio);
        Console.WriteLine("Input equals output: {0}", equal);
        Console.WriteLine("Successful: {0}", success);
        
        Console.ReadKey(true);
    }
    
    public static byte[] Compress(byte[] input) {
        // Hier der Kompressions-Algorithmus
    }
    
    public static byte[] Decompress(byte[] input) {
       // Hier der Dekompressions-Algorithmus
    }
}

Bedingungen:
  • Frameworks- / 3rd-Party-Klassen, die selbst Komprimierungsalgorithmen in irgend einer Form bereitstellen, sind verboten!
  • Die Kompressionsrate muss zum Erfolgreichen bestehen mindestens 10% betragen!
  • Die Kompression muss verlustfrei sein! (D.h. der Output von der Dekompressions-Methode muss gleich dem Input der Kompressions-Methode sein!)

Tipps:
  • Am Anfang war das Wort!
  • Ein Wörterbuch kann auch nicht schaden!

Gruß & Viel Spaß, Christian.
Dieser Beitrag wurde 5 mal editiert, zum letzten Mal von TheBrainiac am .
Attachments
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers