Thema des Monats: Programmieraufgaben / JavaBLOG Pause
5 Kommentar(e). Veröffentlicht von Christian Ullenboom am Mittwoch, Dezember 10, 2008.Anders als bei den üblichen kleinen Beispielen für eine bestimmte API und Technologie sollen nun drei Aufgaben zur Auswahl stehen. Jeder kann nach Lust, Zeit und Laune eine/jede Aufgabe lösen.
Aufgabe 1
Brainfuck (http://de.wikipedia.org/wiki/ Brainfuck) und Ook! (http://de.wikipedia.org/wiki/ Ook!) sind einfache Turing-vollständige Sprachen, für die sich sehr leicht Interpreter in Java schreiben lassen. Für Brainfuck gibt es mittlerweile sogar eine IDE: http://hardtware.de/products/ brainfuck.php. Die Aufgabe ist, unter Java 6 einen eleganten Compiler zu bauen, der aus einem Brainfuck- oder Oak!-Programm ein ausführbares Java-Programm in Form einer .class-Datei generiert. Der Aufruf kann so aussehen:
$ java BrainfuckC Application.bf
Successfully generated Application.class
$ java Application
Aufgabe 2
Gegeben ist eine potenziell sehr große ASCII-Datei mit Ganzzahlen im Wertebereich +-1000000, die durch Leerzeichen, Tab oder Return getrennt sind. Über die Datei soll eine Statistik gefahren werden, sodass am Ende die größte und kleinste Zahl sowie die maximale Teilsumme ausgegeben wird. Gesucht ist das schnellste Programm.
$ java Stat numbers.txt
Min: 3, Max: 199933, Maximale Teilsumme 4785
PS: Die maximale zusammenhängende Teilsumme von zum Beispiel
{-18,5,-3,9,4,-12} ist 5 + -3 + 9 + 4 = 15.
Aufgabe 3
Microsoft PowerPoint kann Folien im XML-Format speichern. Dazu verwendet Microsoft Zip-Dateien mit der Endung pptx. Im Zip-Archiv befindet sich ein Order ppt/slides und jede PowerPoint-Folie liegt dort als XML-Datei vor. Schreibe ein Swing-Programm, mit dem man einfache Text-Folien darstellen kann. Der Rückgriff auf beliebige Java-OpenSouce-Bibliotheken ist ausdrücklich gewünscht.
Lösungen können gerne in dem Blog gepostet werden (oder Verweise auf die Lösungen).
Blog-Pause
In den letzten Wochen gab es keine Posts, da ich auf den Philippinen, Brunei und Indonesien (ja, auch Java) war. Nach der Reise habe ich interessante Java-Neuigkeiten in den Blog nachgetragen. Nun wird es voraussichtlich für einige Wochen wieder keine weiteren Einträge geben, da ich nach Afrika fliege und Namibia, Südafrika, Swaziland, Lesotho, Botswana, Zambia, Mozambique, Malawi, Tansania, Kenia, Ruanda besuchen werde. Wollen wir hoffen, dass dies hier nicht der letzte Blog-Eintrag ist ;)
Aufgabe 1
Brainfuck (http://de.wikipedia.org/wiki/
$ java BrainfuckC Application.bf
Successfully generated Application.class
$ java Application
Aufgabe 2
Gegeben ist eine potenziell sehr große ASCII-Datei mit Ganzzahlen im Wertebereich +-1000000, die durch Leerzeichen, Tab oder Return getrennt sind. Über die Datei soll eine Statistik gefahren werden, sodass am Ende die größte und kleinste Zahl sowie die maximale Teilsumme ausgegeben wird. Gesucht ist das schnellste Programm.
$ java Stat numbers.txt
Min: 3, Max: 199933, Maximale Teilsumme 4785
PS: Die maximale zusammenhängende Teilsumme von zum Beispiel
{-18,5,-3,9,4,-12} ist 5 + -3 + 9 + 4 = 15.
Aufgabe 3
Microsoft PowerPoint kann Folien im XML-Format speichern. Dazu verwendet Microsoft Zip-Dateien mit der Endung pptx. Im Zip-Archiv befindet sich ein Order ppt/slides und jede PowerPoint-Folie liegt dort als XML-Datei vor. Schreibe ein Swing-Programm, mit dem man einfache Text-Folien darstellen kann. Der Rückgriff auf beliebige Java-OpenSouce-Bibliotheken ist ausdrücklich gewünscht.
Lösungen können gerne in dem Blog gepostet werden (oder Verweise auf die Lösungen).
Blog-Pause
In den letzten Wochen gab es keine Posts, da ich auf den Philippinen, Brunei und Indonesien (ja, auch Java) war. Nach der Reise habe ich interessante Java-Neuigkeiten in den Blog nachgetragen. Nun wird es voraussichtlich für einige Wochen wieder keine weiteren Einträge geben, da ich nach Afrika fliege und Namibia, Südafrika, Swaziland, Lesotho, Botswana, Zambia, Mozambique, Malawi, Tansania, Kenia, Ruanda besuchen werde. Wollen wir hoffen, dass dies hier nicht der letzte Blog-Eintrag ist ;)
Labels: Die wöchentliche Dosis Java

Hallo, Aufgabe 2 hatte es mir gleich angetan. Also schnell noch einen Kaffee gemacht und ran an die Arbeit...
Heraus kam dabei folgender Code:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Stat {
public static void main(String[] args) {
if(args.length < 1) {
// usage
System.out.println("usage: $ java Stat dateiname");
return;
}
InputStream is;
try {
is = new BufferedInputStream(new FileInputStream(args[0]), 16 * 1024); // 16k
} catch (IOException e) {
System.err.println(String.format("Datei '%s' konnte nicht geöffnet werden.", args[0]));
e.printStackTrace();
return;
}
try {
int teilMax = 0;
int summMax = 0;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
int num;
int index = 0;
char[] buf = new char[16];
int b;
while( true )
{
b=is.read();
if(b <= ' ') {
if(index > 0) {
// try {
num = parseInt(buf, index);
// } catch (NumberFormatException e) {
// System.err.println("Format Fehler! '" +
// new String(buf, 0, index)+"' ist keine Zahl!" );
// continue;
// }
// System.out.println(String.format("found %d", num));
summMax = Math.max(0, summMax + num);
if(summMax > teilMax) teilMax = summMax;
// Gesucht ist das schnellstes Programm,
// daher nicht min = Math.min(min, num)
if(num < min) min = num;
if(num > max) max = num;
}
index = 0;
if(b == -1) break; // end of file
} else {
buf[index++] = (char) b;
}
}
System.out.println(String.format("Min: %d, Max: %d, Maximale Teilsumme %d", min, max, teilMax));
} catch (IOException e) {
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Format Fehler! Maximale Anzahl Zeichen pro Zahl überschritten!");
e.printStackTrace();
}
}
public static int parseInt(final char[] ch, final int length) throws NumberFormatException
{
if(length <= 0)
throw new NumberFormatException("No number: " + new String(ch, 0, length));
int result = 0;
int i = 0;
boolean negative = false;
if (ch[0] == '-') {
negative = true;
i++;
if(i == length) /* Only got "-" */
throw new NumberFormatException("No number: " + new String(ch, 0, length));
}
int digit;
while (i < length) {
digit = ch[i++] - '0';
if (digit < 0 || digit > 9)
throw new NumberFormatException("No number: " + new String(ch, 0, length));
result *= 10;
result += digit;
}
return (negative) ? -result : result;
}
}
Da das schnellste Programm gesucht wurde habe statt einiger Standard Java Funktionen eigenen Code verwendet. Zum Beispiel statt min = Math.min(min, num); habe ich if(num < min) min = num; verwendet.
Ausserdem verwende ich nicht Integer.toString(num), da diese Funktion ein String Objekt erwartet. Meine eigene Funktion wandelt direkt aus dem übergebenen Array. Nachteil: Es werden keine Überläufe behandelt. Das heißt es wird angenommen, dass keine Zahl übergeben wird, die nicht im Integer Zahlenbereich liegt. Vorteil: das Array muss nicht erneut geprüft und kopiert werden. Direkter Zugriff auf das Array ist schneller als die String.charAt(i) Methode.
Auch die try-catch Anweisung um den parseInt(num) Aufruf habe ich auskommentiert um etwas Laufzeit zu sparen :) Sollte nicht sichergestellt werden können, dass die Datei wirklich nur sauber formatierte Zahlen enthält, müsste die Anweisung wieder einkommentiert werden.
Ausserdem werden die gelesenen Bytes in einem Array abgelegt, so dass nicht erst String Objekte verkettet, oder ausgewertet werden müssen.
Hallo,
für BrainFuck habe ich auch einmal einen Interpreter geschrieben.
Dabei unterstützt mein Interpreter Methodem, Rekursion und geschachtelte Schleifen.
Hier mal ein Beispiel, welches mein Interpreter verarbeiten kann.
/ Prints the corresponding ASCII character of a cell value /
printASCII (
/ clear used cells /
>[-]>[-]>[-]<<<
/ add 32 to cell[start+2] 32 = first printable char " " /
>++++[>++++++++<-]
/ goto start cell /
<
/ add value of start cell to cell[start+2 and start+3] /
[>>+>+<<<-]
/ set start cell back to start value /
>>>[<<<+>>>-]
/ print out cell[start+2]/
<.
/ go back to start cell /
<<
)
/ prints all printable ASCII characters from 32 to 126 /
main (
/ add 95 to cell2 /
+++++++++[>++++++++++<-]>+++++
/ add 95 one by one to cell3 and print content /
[>printASCII()+<-]
)
main()
Den Source kann man hier finden:
http://forum.byte-welt.net/showthread.php?t=1128
bye Saxony
Hallo,
Aufgabe 1 habe ich mir in den letzten Tagen mal zu Gemüte geführt und auch gleich ein Projekt daraus gemacht. Den EsoTransformer.
https://developer.berlios.de/projects/esotransformer/
Das erste snapshot release kann aus Brainfuck C, C++ und Java Code erzeugen und (so ein Compiler vorhanden) auch bauen.
Viel Spaß beim Ausprobieren. Feedback wäre super.
Zum Snappshot (jar-file):
https://developer.berlios.de/project/showfiles.php?group_id=10594&release_id=15769
Hallo tuergeist. Du hast nach einem Kommentar gefragt. Die Idee zur Transformation ist interessant, wobei die Frage ist, was man für eine Abstraktion wählt, wenn man diverse Programmiersprachen zusammenfassen möchte. Bisher machst du das ja nicht, sondern wählst einen konkreten Parser aus und übersetzt das Programm nicht in ein Zwischenformat, was dann im nächsten Schritt in C++, Java, sonst was umgesetzt wird. Ein Zwischenformat für einen abstrakten Syntaxbaum wäre eine interessante Idee, so dass der Parser (Frontend) und der Generator (Backend) getrennt sind. Die Abstraktion über verschiedene Generatoren finde ich gut.
Ein paar Code-Ideen:
Beim BrainfuckParser statt das byte-Feld kann dir ein ByteArrayOutputStream nutzen; davon kann man dann das byte-Feld ableiten.
Statt append() in einen StringBuffer kannst du alternativ direkt in einem PrintWriter schreiben und dann kannst du printf() verwenden, was dir ein %n für das Newline bietet.
Der Compiler-Aufruf könnte noch etwas Verzeichnis-Unabhängiger werden, etwa mit eine CCompiler-Klasse.
Fehler sind auf dem err Kanal vielleicht besser aufgehoben als auf dem out Kanal.
Wenn du sowieso ab Java 5 verwendest, kannst du StringBuffer durch StringBuilder ersetzen.
Interessant wäre eine Abstraktion der Dateipfade, also weg von File zum Beispiel zu URI.
Hallo Christian,
danke für die Durchsicht und die Kommentare. Ich habe einfach mal ohne Konzept angefangen und drauf los gebastelt.
Eine Zwischensprache (Bytecode *g*) wäre wohl langfristig die bessere Lösung. Für die einzelnen Sprachen sollte ggf ein Plug-in Konzept benutzt werden um den Code nicht ändern zu müssen, wenn eine neue Sprache mit dazu kommt.
Der CCompiler, danke für den Hinweis, ist natürlich notwendig und die logische Konsequenz aus JCompiler..
OSGi könnte auch eine Lösung sein, wenn man noch ein GUI hat und nicht alle Plugins benötigt...
Wie auch immer. Vielen Dank. Vielleicht entwickelt sich das Projekt ja zum Guten ;)