Hoi Zämen
ich soll eine Funktion schreiben, bei deren Aufruf ein ausgefuelltes
Rechteck aus dem Charakterzeichen C1 gezeichnet wird. Die obere ecke des
Rechtecks hat die Koordinaten (X1,Y1) und die untere rechte Ecke
(X2,Y2).
Ich habe erstmal mit einer Fläsche von 8X8
Bitte um Hilfe, denn was ist erhalten ueber den Bildschirm(PUTTY) sind
seltsame Zeichnen; ich denke wegen
Putty kann das Verhalten einiger Terminals emulieren.
Jedes dieser Terminals hat besondere Zeichenkominationen zur Steuerung
des "sichtbaren" Outputs. Du musst dich für eines dieser Termnials
entscheiden, und dann die Kommandos for goto_xy() implenentieren.
>>> \x1b\x59(posx)(posy)
das hier ist genau der Versuch ein solches Steuerkommando zu senden:
\x1b dürfte eine ESC sein (ESCAPE = 27 dez)
\x59 (dez 89) ist wohl der Kommandocode für bewege Cursor zu posx,posy
nun musst du nur noch den passeneden Terminal emulator einschalten.
Stichworte: VT100, VT400 usw. da musst Du dann wieder googeln.....
Gruß Thilo
Ich habe für dich mal den Gockel gefragt.
Dein Code passt zum Terminal-Emulator VT52. Ich glaube aber der sollte
auch im VT100 mode funktionieren.
Der Code ist eine Escape Sequenz zur Cursor - Kontrolle
ESC Y (Ps) (Ps)
Gruß T.
Hallo Thilo,
ich gebe dir Recht!
Leider muss ich den PUTTY als Terminal benutzen, den ich Windows 7
verwende.
Die von dir genannten Terminal Emulator betrifft ehe die Windows XP
Version, was ich nicht habe. Google führt mich zu keiner passenden
Antwort...
Da ich auch noch auf die Richtigkeit meines Programms Zweifeln habe,
kannst du mir sagen, ob es so richtig ausklingt?
Danke und Gruss
Francis
Mal angenommen, die Espace sequencen stimmen,
deine Funktion "rect()" füllt kein Rechteck, sondern setzt die linke
obere und rechte untere Ecke.
Es macht wenig Sinn, für jeden (doppelt gezeichneten) Punkt immer den
Cursor neu zu setzen.
Setze den Cursor besser 1x pro Zeile, und drucke dann soviele Sterne,
wie das Rechteck breit ist.
Was Easylife sagt ist richtig.
Zudem kannst Du auch die erste und letzte Linie einfach ohne neue
Cursor-Positionierung erzeugen, indem du immer '*' ausgibst. Der Cursor
rückt selbstandig um eine Position weiter.
Deine Funktion 'rect' ergibt Sinn wenn Du sie abwandelst zu einer
Funktion 'leftandright' wobei Sie den linken '*' ausgibt mit ESC Y 0
ypos und dann den rechten mit ESC Y xmax ypos, wobei xmax die Position
des rechten Randes ist.
Dann könnteste du die Schleifen so bauen:
1. Schleife: Gib an ypos = 0 x-mal den '*' aus
2. Schleife: von ypos = 1 bis ypos < ymax rufe 'leftandright' auf
3. Schleife: Gib an ypos = ymax x-mal den '*' aus.
Gruß Thilo
Hoi Zäme,
Danke fuer die Inputs(!)
bin mehr die Idee von Easylife eingegangen, da rect() mir vorgeschrieben
ist.
Folgendes habe ich verbessert, aber bin irgendwie nicht so ueberzeugt.
Hab den Cursor mit (x1,y1) gesetzt, aber bin immer noch verwirrt wie ich
den (x2, y2) reinbringen!
Habt ihr gewusst, dass es einen riesigen Unterschied zwischen
printf("\x1b\x48\x1b\x4a");// Bildschirm löschen und Cursor auf Home-Position
50
printf("\n Funktionen, -> MIT Uebergabewert, OHNE Rueckgabewert!\n");
51
52
for(i=0;i<=5;i++)
53
{
54
rect(5,5,9,9,c1);
55
}
56
57
58
59
while(1);// Endlosschleife zum ordnungsgemäßen Abschluß des Programms
60
}// Ende des Hauptprogramms, d.h. Ende des gesamten Programms
In den main() hab eine einfache for Schleife(keine verschlachtete mehr)
benutzt. Desweiteren bin in rect() und hab die Idee von Easylife
eingesetzt.
Danke fuer die weiteren Inputs
Francis Chaleu schrieb:> Habt ihr gewusst, dass es einen riesigen Unterschied zwischen> for(i=0; i<=5; i++)rect(5, 5, 9, 9, c1);> und> for(i=0; i<=5; i++)> {> rect(5, 5, 9, 9, c1);> }> gibt?
Da gibt es exakt keinen.
Francis Chaleu schrieb:> Hab den Cursor mit (x1,y1) gesetzt, aber bin immer noch verwirrt wie ich> den (x2, y2) reinbringen!
x2 und y2 brauchst du nur um dir auszurechnen, wie breit bzw. wie hoch
das Rechteck sein muss. Ansonsten taucht es im Code überhaupt nicht auf.
Wenn du die richtige Anzahl an Zeilen hinmalst, mit der jeweils
richtigen Anzahl an * in jeder Zeile, dann ergibt sich die rechte untere
Ecke ganz von alleine.
Mal doch einfach mal mit der Hand ein gewünschtes Rechteck auf
karriertem Papier! Das wird sowieso unterschätzt, sich erst mal klar zu
machen, wie man ein Problem selbst mit der Hand lösen würde.
Wie machst du denn das?
Hier sei deine Zeichenfläche
1
01234567
2
+--------+
3
0 | |
4
1 | |
5
2 | |
6
3 | |
7
4 | |
8
5 | |
9
6 | |
10
7 | |
11
+--------+
und du sollst jetzt ein Rechteck von den Koordinaten 2/3 zu den
Koordinaten 5/5 malen.
Was machst du? Das erste was du machst ist, du rechnest dir aus, wie
breit bzw. wie hoch das Rechteck ist. Breit ist es 5-2+1 gleich 4
Zeichen und hoch ist es 5-3+1 gleich 3 Zeichen.
Also beginnst du in der Zeile 2 (weil x1 gleich 2 ist) in der Spalte 3
(weil y1 gleich 3 ist) mit der ersten Zeile aus *-nen. Du malst dort 4
Sterne hin
1
01234567
2
+--------+
3
0 | |
4
1 | |
5
2 | |
6
3 | **** |
7
4 | |
8
5 | |
9
6 | |
10
7 | |
11
+--------+
Da dein Rechteck aber 3 Zeilen hoch sein muss, kommt eine weitere Zeile
darunter. Das ist dann logischerweise die Zeile 3 (weil ja die erste
Zeile die Zeile mit der Nummer 2, wegen x1, war) und sie beginnt genau
wie die erste Zeile in Spalte 3 (weil y1 ja 3 war).
Wieder werden 4 *-ne (weil die Breite 4 war hingemalt
1
01234567
2
+--------+
3
0 | |
4
1 | |
5
2 | |
6
3 | **** |
7
4 | **** |
8
5 | |
9
6 | |
10
7 | |
11
+--------+
Da die errechnete Höhe des Rechtecks 3 war, kommt noch eine Zeile dazu.
Wieder beginnt sie in der Spalte y1, also in der SPalte 3 und ist 4 *-ne
breit
1
01234567
2
+--------+
3
0 | |
4
1 | |
5
2 | |
6
3 | **** |
7
4 | **** |
8
5 | **** |
9
6 | |
10
7 | |
11
+--------+
Die zuvor durch die Höhe errechnete Anzahl an Zeilen ist in der
entsprechenden Breite ausgegeben worden, wobei jede Zeile in der jeweils
korrekten Spalte beginnt.
Und sieh die mal die rechte untere Ecke an. Sie liegt genau an der
Position 5/5. Genau so wie es von x2/y2 gefordert wurde.
Wenn ich mich mal zurücklehne und rekapituliere, was ich da eigentlich
gemacht habe, dann lande ich ganz automatisch bei der Strategie:
1
um ein Rechteck von x1/y1 nach x2/y2 zu malen:
2
3
breite = x2 - x1 + 1;
4
hoehe = y2 - y1 + 1;
5
6
for( i = 0; i < hoehe; i++ ) {
7
positioniere den Cursor auf x2+i, y1
8
for( j = 0; j < breite; j++ ) {
9
male ein '*' hin
10
}
11
}
Ja. Manchmal muss man doch tatsächlich in einem Computerprogramm auch
mal ein bischen rechnen und sich selbst was ausdenken bzw. einfach mal
sich selbst beobachten, wie man selbst Dinge löst und das dann in Code
giessen. Das soll vorkommen.
Hinweis: das alles ist noch nicht der Weisheit letzter Schluss, denn was
passiert, wenn die Funktion den Auftrag kriegt ein Rechteck von den
Koordinaten 6/7 zu den Koordinaten 3/4 zu malen? D.h die 'linke' Ecke
ist eigentlich weiter rechts als die 'rechte' Ecke. Sinngemäss auch für
oben und unten. Die Fälle wollen noch behandelt werden.
Francis Chaleu schrieb:> In den main() hab eine einfache for Schleife(keine verschlachtete mehr)> benutzt.
Was Blödsinn ist. Denn um ein Rechteck zu zeichnen, benötigst du
verschachtelte for-Schleifen.
Deine Funktion rect() macht alles mögliche, nur eben kein Rechteck
zeichnen. Lass Funktionen das machen, was ihr Name suggeriert. Dann
machst du dir deinen Job als Programmierer um ein ganzes Stück leichter.
Vielen vielen Dank lieber Moderator!
Ich hoffe, dass ich irgendwann auf solche logische Schritte kommen
werde, wie du.
Ich werde auf jeden Fall mein Programm posten.
Viele Grüsse
Francis
Francis Chaleu schrieb:> Natuerlich bin ich offen fuer Verbesserung!
Der nächste wichtige Schritt besteht darin, sich mal zurückzulehnen und
zu überlegen, ob es im Code grundlegende 'Bausteine' gibt, die für sich
alleine nützlich wären.
So zum Beispiel das hier
1
....
2
printf("\x1b\x59%c%c",(32+(x2+i)),(32+y1));
3
....
das positioniert den Cursor, um damit an einer anderen 'Zeichenposition'
etwas ausgeben zu können.
Das stinkt aber schon geradezu danach, dass es sich hier um eine
allgemeinere Funktionalität handeln könnte, die für sich alleine
nützlich sein wird. Willst du einen Kreis ausgeben, dann wird zwar die
Anfangskoordinate einer Zeile anders berechnet und auch die Nummer der
auszugebenden Zeile mag eine andere sein, aber die Grundfunktionalität
'Positioniere den Cursor in Zeile y und Spalte x' wird auch dort
gebraucht werden. Genauso wie in vielen anderen Aufgaben, die dir in
diesem Zusammenhang begegnen werden.
Es würde daher Sinn machen, diese Funktionalität in eine eigene Funktion
zu 'verbannen', so dass man sich an der verwendenden Stelle keine
Gedanken mehr darum machen muss, wie diese Positionier-Aktion genau
abläuft.
Ein traditioneller Name für diese Funktion ist zb. gotoXY
printf("\x1b\x48\x1b\x4a");// Bildschirm löschen und Cursor auf Home-Position
3
...
das Zeug zu einem Grundbaustein hat. Die Funktionalität 'Bildschirm
löschen und Cursor Home' wirst du noch öfter benötgen. Daher wäre es
vernünftig, die in eine Funktoin zu verbannen, so dass man nicht
jedesmal nachsehen muss, wie das genau geht. Ein Aufruf einer Funktion
Clear() in main() (auch in zukünftigen main()s) muss reichen ohne dass
man sich ständig an die Details erinnern muss oder will.
Auf die Art entsteht ganz automatisch ein Grundstock an nützlichen
Funktionen, die von einem Projekt zum nächsten weitergegeben und
verwendet werden können, ohne dass man in jedem Projekt erneut nach den
Details suchen muss.
Und irgendwann wirst du dann auch soweit sein, wie man den Cursor auch
dann positionieren kann, wenn die Spaltenanzahl größer als 9 ist. Eine
entsprechende Änderung in der Funktion gotoXY kommt dann automatisch
allen anderen Programmen die gotoXY verwenden zugute.
so etwas
1
...
2
// Definitionen der benötigten Variablen
3
inti,j;
4
...
ist bei aller Liebe ein sinnloser Kommentar. Wenn jemand nicht sieht,
dass es sich bei den nächsten Zeilen um Variablendefinitionen handelt,
dann soll er zum Optiker gehen oder in die VHS um einen Grundkurs
'Lesen' zu machen.
Wenn du etwas kommentierst, dann kommentiere das, was man als Leser
nicht sowieso im Code sieht. Jeder C Programmierer, der mehr als 30
Minuten C Unterricht hatte, erkennt, dass es sich bei
1
inti,j;
2
unsignedcharbreite,hoehe;
um die Definition von Variablen handelt. Das brauchst du nicht
dazuschreiben.
Ein Kommentar soll einem Leser des Codes das WARUM erklären und nicht
das WIE! Das 'WIE' findet sich im Code, aber nur durch Codelesen erfährt
man nicht warum etwas im Code gemacht wird.