Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Moderationshinweis von herbivore
(18.01.2010 - 10:01)
Bitte beachtet folgenden Hinweise und Regeln:
So ein Thread erfordert Disziplin! Bitte nur Aufgaben und Lösungen posten! Keine Kommentare!
Denn wenn zu jeder Lösung 20 Beiträge kommen, die auf irgendwelche Kleinigkeiten hinweisen, die man anders machen könnte oder sogar alles in eine endlose prinzipielle Diskussion über Programmierstil (sagen wir z.B. über den Gebrauch von goto) abgleitet, wird der Thread vollkommen unübersichtlich. Also bleibt streng bei der Sache. Eine Aufgabe gilt als gelöst, wenn der Code das vorgegebene Problem löst, egal wie wie gut oder schlecht der Programmierstil ist.
Postet nur eine Lösung, wenn ihr schon eine neue Aufgabe in petto habt. Nach 24 Stunden ohne neue Aufgabe durch den ersten, der die Aufgabe gelöst hat, darf auch jemand anders die neue Aufgabe stellen.
Bitte postet nur Aufgaben zur Unterhaltung der anderen und nicht welche zu eurem Vorteil. Die Aufgaben sollten in nicht mehr als 50 Zeilen gelöst werden können.
Wenn eine Woche seit dem jeweils letzten Beitrag vergangen ist, ist der Thread wieder frei für eine neue Aufgabe (egal wer die neue Aufgabe stellen möchte und 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).
Schreibt mir (herbivore) bitte eine PM, wenn euch noch was einfällt, das geregelt sein sollte.
Hier noch eine Liste der bisher gespielten Aufgaben. Herzlichen Dank an m0rius, der sich diese Mühe - für alle Aufgaben bis zum 1.6.2011 - gemacht hat. Links auf spätere Aufgaben und Lösungen wurden von verschiedenen Moderatoren ergänzt.
PS: Wenn euch die Aufgaben in diesem Thread nicht reichen: Auf http://pexforfun.com/, einer Art "automatisiertem Programmierspiel", gibt es noch viele weitere interessante Aufgaben.
Dort bekommt man einen Quellcode-Rahmen angezeigt, den man entsprechend der Aufgabe ausfüllen muss, nur dass die Aufgabe nicht als Text vorgeben ist, sondern man den Code auf Verdacht ändert und sich nach jeder Code-Änderung anzeigen lassen kann, mit welchen Testdaten der White-Box-Testdatengenerator PEX das eigene Programm füttert, welche Ausgabe es daraus errechnet und was das jeweils erwünschte Ergebnis ist. Das Prinzip hat ein bisschen was von Mastermind, wo man auch eine mögliche Lösung ausprobiert und vom Gegenüber Hinweise bekommt, was schon stimmt und was noch nicht.
Hier soll von nun an ein Programmierspiel gestartet werden.
Es wird eine kleine Aufgabe vorgegeben, die der nachfolgende Poster zu bewältigen hat. Wie er die Problemlösung damit umsetzt, ist egal.
Hauptsache der Code liefert das gewünschte Ergebnis.
Derjenige, der die Aufgabe am schnellsten löst, darf dann eine eigene stellen.
Regeln:
Lediglich kleine Aufgaben, keine "Projekte" wie: Programmiere ein Gästebuch.
Jegliche Quellen müssen angegeben werden. Wer kann, sollte jedoch darauf verzichten.
Ein schön eingerückter Code, sodass es anderen Usern möglich ist, zu sehen, wie man an das Ergebnis gekommen ist.
Also hier mal die erste Aufgabe:
Eine Pyramide soll je nach Benutzereingabe erstellt werden.
Diese Benutzereingabe soll die Basis für die Pyramide sein:
Benutzereingabe "H":
[frame]
[CENTER]
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
ABCDEFEDCBA
ABCDEFGFEDCBA
ABCDEFGHGFEDCBA[/CENTER]
[/frame]
Viel spaß
Dieser Beitrag wurde 6 mal editiert, zum letzten Mal von abra_joe am .
Eine Zahl soll in eine Zeichenkettenrepräsentation überführt werden, die diese Zahl in römischen Ziffern darstellt.
Einschränkungen: Ziffern I bis M. Subtraktionsregel.
Beispiel: 1984 -> MCMLXXXIV
[edit] Mist, hab ich doch glatt das mit der Subtraktionsregel übersehen
Hehe, das wäre hier doch der ideale Platz, um mal TDD zu üben.
Der Fragensteller gibt zur Aufgabenstellung ein Interface und einen Test (oder mehrere vor), die bestanden werden müssen... :D
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dN!3L am .
Hehe, das wäre hier doch der ideale Platz, um mal TDD zu üben.
Da kann man sich mal über die Effizienz amüsieren ;) Zwei Aufgaben und zweimal in der ersten Lösung die gepostet wurde ein elementarer Fehler, der mit einer Überprüfung der Aufgabenstellung vor dem Post hätte gesehen werden können.
Wäre wohl mit weniger Code gegangen, aber ist das was mir auf die Schnelle so gelungen ist ;)
EDIT: ujr hat mich auf einen 'kleinen' Bug in meiner Lösung aufmerksam gemacht, welchen ich mittlerweile beseitigt habe. Das alte Beispiel mit dem Fehler wurde durch ein neues ersetzt ;)
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von edsplash am .
Die gesetzten Pixel/Buchstaben ergeben sich jeweils aus dem direkt über diesem liegendem Feld und dem links darüberligendem.
Die Linke obere Ecke ist als Ausgangspunkt bekannt.
Viel Spass und Vielen Dank an Floste für den Tipp
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von edsplash am .
Erstellt einen sog. Tromino Tiling Algorithmus.
Der ein 2^n mal 2^n großen Array mit den einzelnen Trominos aufteilt.
Ein Tromino wäre also sowas
0000
0220
0210
0000
Am Anfang muss ein Loch (1) an einer beliebigen Position gesetzt werden.
Dann wird die ganze Fläche schön mit den Trominos ausgefüllt.
Gestartet wird mit der 2, weiter gehts mit der 3 usw. Am Ende muss es halt schön foll sein.
Am Bild seht ihr wie der Array zu beginn aussieht. Also nur das Loch (1) ist bekannt.
Am Ende muss es dann so wie rechts gezeigt ausgegeben werden
Die Ausgabe sollte in der Konsole sein (wenn sich das Zeug aufgrund der unterschiedlichen Zeichenlänge nicht zusehr verschiebt).
Da ich überhaupt nicht verstanden habe was MichlG mir mit den Trominos sagen wollte, habe ich mal Google konsultiert und eine grafische Erklärung gefunden.
Die wollte ich euch nicht vorenthalten:
Ganz schön schwer, wenn man sich selbst was ausdenkt.
Ich hab einfach mal brute force try und error gemacht, braucht ewig für n≥5, aber die in dem bild da sind eh nur n=3:
public static void Main()
{
while (true)
{
int xpos, ypos, n;
do { Console.Write("X="); }
while (!int.TryParse(Console.ReadLine(), out xpos));
do Console.Write("Y=");
while (!int.TryParse(Console.ReadLine(), out ypos));
do Console.Write("N=");
while (!int.TryParse(Console.ReadLine(), out n));
int num = 1 << (byte)n;
int[,] feld = new int[num, num];
feld[xpos, ypos] = -1;
if (!BruteForce(feld, num, 1))
{
Console.WriteLine("Nicht gelöst");
}
else
{
for (int y = 0; y < num; y++)
{
for (int x = 0; x < num; x++)
{
Console.Write(feld[x, y].ToString().PadRight(3));
}
Console.WriteLine();
Console.WriteLine();
}
}
}
}
private static bool BruteForce(int[,] feld, int num, int tiefe)
{
for (int y = 0; y < num; y++)
for (int x = 0; x < num; x++)
if (feld[x, y] == 0)
{
Point[] points = new Point[3];
for (int square = 0; square < 4; square++)
{
int sx = (square & 1) + x - 1;
int sy = ((square & 2) >> 1) + y - 1;
for (int ep = 0; ep < 4; ep++)
{
int i = 0;
for (int p = 0; p < 4; p++)
{
if (p != ep)
points[i++] = new Point(
(p & 1) + sx,
((p & 2) >> 1) + sy);
else if (((p & 1) + sx == x) && (((p & 2) >> 1) + sy) == y) goto bad_ep;
}
if (TrominoTesten(feld, num, tiefe, points)) return true;
bad_ep: { }
}
}
return false;
}
return true;
}
private static bool TrominoTesten(int[,] feld, int num, int tiefe, IEnumerable<Point> points)
{
foreach (Point p in points)
{
if (p.X < 0 || p.X ≥ num) return false;
if (p.Y < 0 || p.Y ≥ num) return false;
if (feld[p.X, p.Y] != 0) return false;
}
foreach (Point p in points)
feld[p.X, p.Y] = tiefe;
if (BruteForce(feld, num, tiefe+1)) return true;
foreach (Point p in points)
feld[p.X, p.Y] = 0;
return false;
}
Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!
programmiere eine einzige Methode f(n) zum Berechnen der Quadratzahl n^2.
Allerdings sind * und / nicht zugelassen. Was als arithmetische Operation zugelassen ist, sind: + und - .
Ahso und lokale/temporäre Variablen sind natürlich auch nich zugelassen ;)
programmiere eine einzige Methode f(n) zum Berechnen der Quadratzahl n^2.
Allerdings sind * und / nicht zugelassen. Was als arithmetische Operation zugelassen ist, sind: + und - .
Ahso und lokale/temporäre Variablen sind natürlich auch nich zugelassen ;)
beste Grüße
zommi
Also ich bezweifel, dass es mit nur einer Methode möglich ist ;-) du musst ja irgendwie ne Laufvariable und ne tmp mitgeben. Hab das aber mal in Scala gelöst mit nur "einer" Methode :D
Derjenige, der die Aufgabe am schnellsten löst, darf dann eine eigene stellen.
Meine Aufgabe ist es einen iterativer Durchlauf eines Binärbaums in Inorder-Reihenfolge zu kreieren. Der rekursive Algorithmus sieht mit der angegebenen Datenstruktur so aus:
public class Node
{
public Node Left { get; set; }
public Node Right { get; set; }
public int Key { get; set; }
public Node()
{
Left = null;
Right = null;
}
}
public void Inorder(Node n)
{
if(n != null)
{
Inorder(n.Left);
Console.WriteLine(n.Key);
Inorder(n.Right);
}
}
Eure Aufgabe ist es einen Algorithmus zu basteln der ohne rekursivem Aufruf auskommt. Sehr hilfreich sind dabei die Stack- sowie die Queue-Datenstrukturen.
Viel Spaß
Dieser Beitrag wurde 7 mal editiert, zum letzten Mal von der-schlingel am .
As a man thinketh in his heart, so he is.
- Jun Fan Es gibt nichts Gutes, außer man tut es.
- Erich Kästner Krawutzi-Kaputzi
- Kasperl
ich liebe iterative Umsetzung von rekursiven Funktionen genauso wie rekursive Funktionen selbst. Deshalb habe ich mich mal ran gemacht.
Ich habe deine Node-Klasse für .NET 2.0 angepasst und eine Komfort-Änderung vorgenommen, aber das Prinzip ist gleich geblieben.
Hier meine Lösung:
using System;
using System.Collections.Generic;
public class NodeDirection
{
public NodeDirection (Node node)
{
_node = node;
_fLeft = true;
}
public bool Left
{
get { return _fLeft; }
set { _fLeft = value; }
}
private bool _fLeft;
public Node Node
{
get { return _node; }
}
private Node _node;
}
public class Node
{
public Node Left
{
get { return _nodeLeft; }
set { _nodeLeft = value; }
}
private Node _nodeLeft;
public Node Right
{
get { return _nodeRight; }
set { _nodeRight = value; }
}
private Node _nodeRight;
public int Key
{
get { return _iKey; }
set { _iKey = value; }
}
private int _iKey;
public Node (int iKey)
{
_nodeLeft = null;
_nodeRight = null;
_iKey = iKey;
}
public void Inorder ()
{
Stack <NodeDirection> stk = new Stack <NodeDirection> ();
// Wurzel zur Bearbeitung setzen
stk.Push (new NodeDirection (this));
// Solange noch Knoten zu bearbeiten sind ...
while (stk.Count > 0) {
// Anstehenden Konten holen
NodeDirection nd = stk.Peek ();
// Prüfen, ob von dem anstehenden Knoten der linke oder rechte
// Unterknoten bearbeitet werden muss.
if (nd.Left) {
// Linken Unterknoten als schon berücksichtigt kennzeichnen
nd.Left = false;
// Linken Unterknoten (falls vorhanden) zur Bearbeitung setzen
if (nd.Node.Left != null) {
stk.Push (new NodeDirection (nd.Node.Left));
}
} else {
// Knoten selbst behandeln
Console.WriteLine (nd.Node.Key);
// Rechten Unterknoten als schon berücksichtigt kennzeichnen
stk.Pop ();
// Rechten Unterknoten (falls vorhanden) zur Bearbeitung setzen
if (nd.Node.Right != null) {
stk.Push (new NodeDirection (nd.Node.Right));
}
}
}
}
}
static class App
{
public static void Main (string [] astrArg)
{
Node node = new Node (1);
node.Left = new Node (2);
node.Right = new Node (3);
node.Left.Right = new Node (4);
node.Right.Left = new Node (5);
node.Inorder ();
}
}
dann hätte ich gerne ein iteratives Türme von Hanoi. Natürlich eine selbst entwickelte Lösung, möglichst ganz ohne Verwendung einer Stack(artigen)-Klasse (ja, das geht).
Zitat von Wikipedia
Das Spiel besteht aus drei Stäben A, B und C, auf die mehrere gelochte Scheiben gelegt werden, alle verschieden groß. Zu Beginn liegen alle Scheiben auf Stab A, der Größe nach geordnet, mit der größten Scheibe unten und der kleinsten oben. Ziel des Spiels ist es, den kompletten Scheiben-Stapel von A nach C zu versetzen.
Bei jedem Zug darf die oberste Scheibe eines beliebigen Stabes auf einen der beiden anderen Stäbe gelegt werden, vorausgesetzt, dort liegt nicht schon eine kleinere Scheibe. Folglich sind zu jedem Zeitpunkt des Spieles die Scheiben auf jedem Feld der Größe nach geordnet.
EDIT: Die zu schreibenden Methode Move soll Ausgaben der Form
"Nr. 4 von 1 nach 3"
machen, was bedeutet, dass in diesem Zug, die Scheibe Nummer 4 von Stab 1 (bzw. A) auf Stab 3 (bzw. C) verschoben wird. Die Scheibe Nummer 1 ist die kleinste, die Scheibe Nummer n ist die größte, wobei die Höhe n des Ausgangsturms als Parameter an Move übergeben wird.