004
25.11.2013, 00:18 Uhr
Hans
Library Walker (Operator)
|
Hi,
habe das Programm jetzt wieder getestet und folgendes festgestellt:
1) Fehler beim Feld initialisieren. Bedenke, das Indizes bei 0 anfangen und bei eins vor der maximalen Grösse enden. Also: bei Feld[10] geht die Zählung von 0 bis 9. Du hattest field[10][10] definiert; d.h. Deine init-Schleifen dürfen nur bis 9 zählen, Du hast sie aber jeweils bis 10 zählen lassen. Das hatte zur Folge, das bei y=10 jedes mal schon das Element [x+1][0] beschrieben wurde. Und bei x=10 ist es bei mir in eine Endlosschleife geraten, weil an der Stelle wo field[10][5] liegen sollte, die Variable y im Speicher stand, die dann jedesmal auf Null gesetzt wurde.
2)
Zitat: |
- Schiffe werden auf manchmal auf gleiche Koordinaten gespawnt (Keine Idee für Problemlösung vorhanden)
|
Siehe Kommentar im Quelltext, da wo Du die Schiffpositionen initialisierst.
Du benutzt die Variable i nur in der Schleife, wo Du die Schiffe positionierst, ansonsten nicht mehr. Es ist aber Sinnvoll, wenn Du sie dann auch beim abschiessen der Schiffe weider herunter zählen würdest. Denn damit erhälst du eine eindeutige Möglichkeit zum fewststellen, wann das Spiel zu Ende ist. Denn weiter Koordinaten abfragen wenn keine Schiffe mehr da sind, ist wenig sinnvoll.
Hab ausserden noch ein paar weitere Kommentare in den Quelltext geschrieben, weshalb ich den hier mal wiederhole.
C++: |
/* Datei: Flottm1b.cpp
Flottenmanöver Version 2 Problematische Stellen von Hans, C/C++ Forum, durch Kommentare im Text erläutert. */
#include "stdafx.h" #include <iostream> #include <conio.h> #include <cmath> // C++ Version, aber wozu eigentlich? - soviel rechnest Du doch gar nicht. #include <windows.h> #include "ctime"
using namespace std;
void gotoxy(int x,int y) { HANDLE hConsole; COORD cursorLoc; std::cout.flush(); cursorLoc.X = x; cursorLoc.Y = y; hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hConsole, cursorLoc); }
/* Damit das Forumsfenster hier nicht unnötig breit wird, hab ich diese Funktion etwas umgestaltet... */ void zeilenloeschen() { // 0 1 2 3 4 5 6 7 8 // 1234567890123456789012345678901234567890123456789012345678902345678901234567890 std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; std::cout << " "\ " \n"; gotoxy(0,0); // wozu erst in die obere Ecke, wenn Du gleich danach in Zeile gotoxy(0,12); // 12 springst? - Wenn, dann gehört das gotoxy() hier an den // Anfang. } /* Und warum gibst Du in dieser Funktion eigentlich 134 Leerzeichen pro Zeile aus? - Normal wären 80 oder hast Du so eine breite DOS-Box? Ansonsten kann man hier auch wieder eine cout-Zeile in einer Schleife packen... */
int _tmain(int argc, _TCHAR* argv[]) { int x,y,i, test; int field [10][10]; // 1 mehr als gewünschtes Spielfeld, weil für die Grenzen auch 2 Felder benötigt werden char c; // Für Testmodus abfrage
/* Testmous abfragen und evtl. aktivieren */ cout<<"Testmodus? (J/N) "; cin >> c; if (c=='j' || c=='J') test = 1; else test = 0;
for (x=1; x<11; x++) { for (y=1; y<11; y++) { field[x][y] = 0; // Spielfeld = 0 gotoxy(x,y); cout << "~"; } }
srand((unsigned) time(NULL)); // Initialisieren des Zufallszahlengenerators
for(x=0; x<12; x++) // x-Grenzen { gotoxy(0,x); cout<<"#"; // obere x-Grenze gotoxy(11,x); cout<<"#"; // untere x-Grenze }
/* Das hier kannst du auch kürzer haben, indem Du auf der richtigen Zeile jeweils cout<<"############"; schreibst. */ for(y=0; y<12; y++) // y-Grenzen { gotoxy(y,0); // linke y-Grenze cout<<"#"; gotoxy(y,11); // rechte y-Grenze cout<<"#"; }
for(i=1; i<6; i++) { x = rand() %10 + 1; // Feldgrenzen beachten! y = rand() %10 + 1;
if(x>0 && y<12 && y>0 && y<12) { /* Hier muss die Abfrage hin, ob an dieser Postion schon ein Schiff steht. Wenn ja i verkleinern und Koordinaten neu berechnen. Der Elegante Weg, .d.h. ohne goto geht so: if (schon ein schiff da) { i--; continue; // An den Anfang der Schleife springen } */ field [x][y] = 1; gotoxy(x,y); if (test==1) // im Testmodus das Schiff anzeigen cout << "S"; else cout << "~"; } else { i--; } }
gotoxy(0,12);
cout << x << endl; cout << y << endl; // kommt weg, wenn Spiel fertig
int xcoord, ycoord;
Eingabe: cout << "Geben Sie eine X-Koordinate ein:"; // hier sollten noch Sicherheitsabfragen cin >> xcoord; // hin die prüfen, ob die Eingaben auch cout << "Geben Sie eine Y-Koordinate ein:"; // Sinnvoll sind, d.h. im zulässigen cin >> ycoord; // Bereich. Sonst gibt's einen crash, wenn // auf Speicher ausserhalb der Grenzen von // field[][] zugegriffen wird!
if (field[xcoord][ycoord] == 0) { gotoxy(0,12); // dieses gotoxy ist überflüssig, weil gleich danach // eine neue Psition angesprungen wird. gotoxy(xcoord, ycoord); cout << "-"; field[xcoord][ycoord] = 3; gotoxy(0,12); zeilenloeschen(); cout << "Ziel verfehlt!"; getch(); zeilenloeschen(); goto Eingabe; } else if (field[xcoord][ycoord] == 1) { gotoxy(xcoord, ycoord); cout << "X"; field[xcoord][ycoord] = 2; gotoxy(0,12); zeilenloeschen(); cout << "Sie haben ein Schiff versenkt!"; getch(); // hier fehlt was, deshalb wird das Programm hier beendet. } else if (field[xcoord][ycoord] == 2) { gotoxy(0,12); zeilenloeschen(); cout << "Auf diese Stelle haben Sie schon geschossen!\n"; getch(); zeilenloeschen(); goto Eingabe; } else if (field[xcoord][ycoord] ==3) { cout << "Ziel verfehlt!\nAuf dieses Feld hatten Sie bereits geschossen!"; getch(); // hier fehlt was, deshalb wird das Programm hier beendet. }
if(field[x][y] != 1) { gotoxy (0,12); zeilenloeschen(); cout << "Sie haben alle Schiffe versenkt!\nDruecken Sie eine beliebige Taste, um das Spiel zu beenden!"; }
getch(); return 0; }
|
Falls Dir die Formatierung des Quelltextes komisch vorkommen sollte: das ist die Art, die ich persönlich vorziehe und nicht ganz dem entspricht, was Visual Studio vorgibt. Es gibt ein Programm Namens AStyle, womit man Quelltexte nach dem persönlichen Geschmack formatieren kann.
Zuletzt wäre da noch das goto Eingabe; Die Konstruktion ist nicht falsch, aber goto gilt allgemein als verpönt, und sollte in einem Fall wie diesem hier auch vermieden werden. Stattdessen nimmt man hier besser die Schleifenkonstruktion
Die hat den Vorteil, dass man eine klare Abbruchbegingung definieren kann, das wäre hier dann etwa i=0, (alle Schiffe versekt) und die goto's ersetzt man durch continue, was ich oben auch schon mal genannt habe.
So, ich hoffe, ich hab mich jetzt nirgendwo vertan...
Hans -- Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung. Dieser Post wurde am 25.11.2013 um 01:03 Uhr von Hans editiert. |