Game Of Life - Einlesen / Ausgeben einer tabellarischen .txt

...

So? Ich mein: Es funktioniert.

Oder vielleicht so?

...

Funktioniert auch ...
Weder noch.

Eine Zeile die mit einem # beginnt ist völlig OK; nur ein Kommentar.

Andere Zeilen müssen aus 2 Zahlen bestehen. Falls nicht ist die Datei fehlerhaft.

C:
while(fgets(name, MAX, ein)){
  if (name[0] == '#') continue;

  if (sscanf(name,"%d %d",&i, &j) == 2) {
     ...
  } else {
    // FEHLER!
    ...
    return EXIT_FAILURE;
  }
}
 
Weder noch ist natürlich auch gut :)
Ich denke dank deiner Hilfe hab ichs nun aber:

C:
while(fgets(name, MAX, ein)){
			if (name[0] == '#') continue;

			if (sscanf(name,"%d %d",&i, &j) == 2) {
				if (i >= 0 && i <= MAX && j >= 0 && j <= MAX){
				printf("%d %d\n", i, j);
				fprintf(aus, "%d %d\n", i, j);
				b[n][m] = a[i][j];
				n++;
				m++;
				} else { ... // Nicht im Zahlenbereich
			} else {
			printf("Fehler!\n");
			system("PAUSE");
			return EXIT_FAILURE;			
			}
		}

Gleichzeitig dann noch prüfen, ob die Zahlen im Definierten Bereich liegen.
Sollte dem so richtig sein, kommt direkt das nächste Problem.
 
Habe jetzt gut was geschafft. Zwar lange noch nicht am Ziel, aber bisher läufts gar nicht sooo schlecht.

Damit wäre ich auch direkt bei meinem nächsten Problem:
Ich soll das Programm über die Konsole aufrufen und gleichzeitig ein paar Parameter angeben.
Und zwar die Spalten n, die Zeilen m, die Schritte und den Dateinamen aus dem ausgelesen werden soll. Wie das beim Aufruf angegeben wird, weiß ich. Nur das verarbeiten ist mir noch ein Rätsel.

Seh ich das richtig, dass die Parameter in argv[ ] gespeichert werden? Wie bekomme ich die daraus, bzw es sind ja auch Zahlen und nicht nur chars. Ich möchte erstmal keine Lösung ;) Vielleicht ein Beispiel oder das Prinzip. Das wäre echt super :)
 
In argc steht die Anzahl der Parameter.
argc=4 würde bedeuten es gibt argv[0], argv[1], argv[2], argv[3]
Jedes dieser argv-Elemente ist eben ein char-Array,
wobei argv[0] der Programmname ist. Erst ab [1] beginnen die Params.

Und wenn man ein char-Array hat, dessen char´s die Ziffern einer Zahl darstellen...
bei deinem fgets bekommst du uA. eine char-mäßige-Zeile mit zwei Zahlen.
Wie liest du die aus...?
 
sscanf. Na das hilft weiter :]
Da will mich gleich mal wieder ans Werk machen. Danke!

edit:

Irgendwo ist ein Fehler. Nicht besonders genaue Angabe, ich weiß, aber naja.
Bevor ich das gleich folgende eingefügt habe, hats funktioniert. Nun leider nicht mehr :/

C:
int main(int argc, char *argv[]) {
	    
	int i, j, schritte;
	int zeilen, spalten;
	int runde = 1;
	char name[MAX];
	char datein[20];
	int a[MAX][MAX] = {0};
	
	const char LIFE[] = "life.txt";				
	const char LIFEOUT[] = "lifeout.txt";
	FILE *ein = fopen (LIFE, "r");
	FILE *aus = fopen (LIFEOUT, "w");
	
	
	printf("7.2 Conway's Game Of Life\n\n");
	
	// Parameter auslesen
	printf("Anzahl der Parameter... %d\n", argc-1);
	sscanf(argv[1], "%d", &zeilen);		// Zeilen
	sscanf(argv[2], "%d", &spalten);	// Spalten
	sscanf(argv[4], "%d", &schritte);	// Iterationen
	scanf (argv[3], "%s", datein);	// Datei

Der Fehler tritt zwar erst später auf, aber er tritt halt auf, weil ich die letzten Zeilen (die mit sscanf und so) eingefügt habe. Ich fürchte, dass es ein total einfacher Fehler ist, finde ihn aber nicht oO Erstmal müßte ich nun in Erfahrung bringen, ob das da oben bisher stimmt ...

edit 2:

Ist sowas wie:
C:
const char LIFE[] = {scanf (argv[3], "%s", datein)};
möglich?
 
Zuletzt bearbeitet:
Hi

sowas wie die einzelne Codezeile unten ist nicht möglich.
Der Returnwert von scanf ist eine Zahl, wieviel Werte erfolgreich eingelesen wurden
(bei einem %s im Idealfall 1).
Die Eingabe slebst bekommt man nicht, da ist wirklich nur eine Zahl.

Die Fehler beim längeren Code:

a) scanf statt sscanf.
sscanf liest aus Strings = char-Arrays
fscanf aus Files
Und nur scanf von der Tastatur.

Noch dazu gibt man einem Tastaurscanf ja nicht im ersten Parameter mit,
welcher String ausgelesen werden soll.
Für das, was "%s" sein sollte, nimmt dein scanf den Dateinamen.
Und angenommen, da gibts zwei %d, %s... drin, würden die in die Variablen
"%s" und datein gespeichert.
Da "%s" nicht wirklich eine Variable ist...

b)
Für den Dateinamen brauchst du überhaupt kein (s)scanf.
Die argv-Parameter kommen alle als char-Array.
Beim Dateinamen willst du %s wieder ein char-Array.
...warum nicht argv[3] direkt verwenden?


Was Anderes:
Am Programmanfang, vor der Verwendung von argv[irgendwas],
musst du prüfen, ob überhaupt genug Parameter mitgegeben wurden.
Wenn du argv[3] verwendest, obwohl zB. nur ein Parameter eingegeben wurde
kann man die seltsamsten Programmfehler bekommen.

Du verwendest max. argv[4], dh. argc muss min. 5 sein.
Wenn argc<5 dann Fehlermeldung und Ende...
 
Hi

sowas wie die einzelne Codezeile unten ist nicht möglich.
Der Returnwert von scanf ist eine Zahl, wieviel Werte erfolgreich eingelesen wurden
(bei einem %s im Idealfall 1).
Die Eingabe slebst bekommt man nicht, da ist wirklich nur eine Zahl.
Ok. Hatte gehofft, dass das in dem Fall vielleicht anders ist :/


b)
Für den Dateinamen brauchst du überhaupt kein (s)scanf.
Die argv-Parameter kommen alle als char-Array.
Beim Dateinamen willst du %s wieder ein char-Array.
...warum nicht argv[3] direkt verwenden?
Oh ja. Natürlich. Das ist mir nun ein wenig peinlich ;)


Was Anderes:
Am Programmanfang, vor der Verwendung von argv[irgendwas],
musst du prüfen, ob überhaupt genug Parameter mitgegeben wurden.
Wenn du argv[3] verwendest, obwohl zB. nur ein Parameter eingegeben wurde
kann man die seltsamsten Programmfehler bekommen.

Du verwendest max. argv[4], dh. argc muss min. 5 sein.
Wenn argc<5 dann Fehlermeldung und Ende...
Klingt einleuchtend und wird umgesetzt.

Die Fehler beim längeren Code:

a) scanf statt sscanf.
sscanf liest aus Strings = char-Arrays
fscanf aus Files
Und nur scanf von der Tastatur.

Noch dazu gibt man einem Tastaurscanf ja nicht im ersten Parameter mit,
welcher String ausgelesen werden soll.
Für das, was "%s" sein sollte, nimmt dein scanf den Dateinamen.
Und angenommen, da gibts zwei %d, %s... drin, würden die in die Variablen
"%s" und datein gespeichert.
Da "%s" nicht wirklich eine Variable ist...
Da bin ich mir jetzt unschlüssig und muss noch drüber nachdenken. So richtig verstanden habe ich das glaube ich noch nicht.

edit::

Wie wäre es damit?:
C:
int main(int argc, char **argv) {
	    
	int i, j, schritte;
	int zeilen, spalten;
	int runde = 1;
	char name[MAX];
	char datein[20];
	int a[MAX][MAX] = {0};
	
	const char LIFE[] = "life.txt";				
	const char LIFEOUT[] = "lifeout.txt";
	FILE *ein = fopen (LIFE, "r");
	FILE *aus = fopen (LIFEOUT, "w");
	
	
	printf("7.2 Conway's Game Of Life\n\n");
	
	if(argc < 5) {
		printf("Nicht genuegend Parameter.\n");
		printf("\n\n\n");
		system("PAUSE");
		return EXIT_FAILURE;
	}

	// Parameter auslesen
	sscanf(argv[1], "%d", &zeilen);		// Zeilen
	sscanf(argv[2], "%d", &spalten);		// Spalten
	sscanf(argv[4], "%d", &schritte);	// Iterationen
	printf("Dateiname... %s\n", argv[3]); printf("Zeilen... %d\n", zeilen); printf("Spalten... %d\n", spalten); printf("Schritte... %d\n", schritte);

Immerhin schmeißt er mir in der letzten Zeile das wieder aus, was ich auch beim aufruf eingegeben habe. Also auf dem Bildschirm natürlich
 
Zuletzt bearbeitet:
Zur genaueren Erklärung von a) noch:
Ein normales scanf könnte zB. so ausschauen:
C++:
int i, j;
float f;
scanf("%d %d %f", &i, &j, &f);
Zuerst die %-Kombination, welche Variablenarten gemeint sind,
dann die Varablennamen zu jedem %.

Aus einem String (zB. argv[3]) statt von der Tastatur:
C++:
int i, j;
float f;
sscanf(argv[3], "%d %d %f", &i, &j, &f);
Der erste Parameter ist also der Quellstring, dann das Selbe wie bei scanf.

Du hattest jetzt ein scanf mit Parametern wie sscanf.
scanf sucht die %-Sachen im ersten Parameter, wo bei dir argv[3], also der Dateiname, war.
Und die 4 Zielvariablen für %´s aus dem Dateinamen sind
"%d %d %f", i, j und f.
"%d %d %f" ist keine Variable -> Problem.

Außerdem natürlich noch das Problem, dass ja nicht von der Tastaur gelesen werden soll.

Aber wie gesagt, beim Dateinamen ist scanf sowieso unnötig.

Zum edit: Sehr gut :)
 
Ach dann hatte ich es vermutlich doch richtig im Kopf :)
Na besten Dank! Dann hab ich jetzt alles, um das fertig zu machen. Mal sehen, ob ich das heute noch schaffe.
Viel gelernt. sscanf war mir z.b. total unbekannt. Parameter beim Aufruf über die Konsole? War mir auch neu. Und der Rest, wie man ja weiter oben lesen kann, auch.
Dann soweit nochmal Dankeschön :]

Gelöst ist das ganze natürlich noch nicht, aber nun komm ich erstmal klar und werde meine "Lösung" natürlich noch kundtun.
 
So. Ich denke ich bin fertig.

C:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
 

// Update
void update_array (int a[MAX][MAX],int *zeilen, int *spalten){
	
	int b[MAX][MAX] = {0};			
	int i, j, n;					

	// Hilfsvariable b werden Werte aus a zugewiesen
	// um die diese dann zu verarbeiten
	for(i = 0; i < (*zeilen); i++) {
		for(j = 0; j < (*spalten); j++) {
			b[i][j] = a[i][j];
		}
	}

	// Angrenzende lebende Zellen zaehlen
	// Da es nur 8 angrenzende Zellen gibt, gibt es nur 8 Bedingungen (inkl. Prüfung, ob noch innerhalb der Matrix)
	for(i = 0; i < (*zeilen); i++) {
		for(j = 0; j < (*spalten); j++) {
			n = 0;

			if(b[i-1][j-1] == 1 && i > 0			&& j > 0			) n++;
			if(b[i  ][j-1] == 1						&& j > 0			) n++;
			if(b[i+1][j-1] == 1 && i <= (*zeilen)	&& j > 0			) n++;
			if(b[i-1][j  ] == 1 && i > 0								) n++;
			if(b[i+1][j  ] == 1 && i <= (*zeilen)						) n++;
			if(b[i-1][j+1] == 1 && i > 0			&& j <= (*spalten)  ) n++;
			if(b[i  ][j+1] == 1						&& j <= (*spalten)  ) n++;
			if(b[i+1][j+1] == 1 && i <= (*spalten)	&& j <= (*spalten)	) n++;

			// Unterbevölkert / Überbevölkert -> Sterben
			if(n < 2 || n > 3) a[i][j] = 0;	

			// Weder ... noch ... -> Neues Leben
			if(n == 2 || n == 3) a[i][j] = 1;	
			
		}
	}
}

// Ausgabe
void display_array(int a[MAX][MAX], int *zeilen, int *spalten) { 
    
	int i, j = 0;
	
	// Ausgabe der aktuellen Matrix
	for(i = 0; i < (*zeilen); i++) { 
        for(j = 0; j < (*spalten); j++) { 
            printf(" %d", a[i][j]); 
        } printf("\n"); 
    } printf("\n"); 
} 

// Main
int main(int argc, char **argv) {
	    
	int i, j, schritte, zeilen, spalten;
	int runde = 1;
	char name[MAX], datein[20];
	int a[MAX][MAX] = {0};
	
	const char LIFEOUT[] = "lifeout.txt";
	FILE *ein = fopen (argv[3], "r");
	FILE *aus = fopen (LIFEOUT, "w");
	
	
	printf("7.2 Conway's Game Of Life\n\n");
	
	// Genug Parameter eingegeben?
	if(argc < 5) {
		printf("Nicht genuegend Parameter.\n");
		printf("\n\n\n");
		system("PAUSE");
		return EXIT_FAILURE;
	}

	// Parameter auslesen
	sscanf(argv[1], "%d", &zeilen);		// Zeilen
	sscanf(argv[2], "%d", &spalten);	// Spalten
	sscanf(argv[4], "%d", &schritte);	// Iterationen
	// Zur Überprüfung nochmals ausgeben
	printf("Dateiname... %s\n", argv[3]); printf("Zeilen... %d\n", zeilen); printf("Spalten... %d\n", spalten); printf("Schritte... %d\n", schritte);
		
	// Eingabeüberprüfungen
	if ((ein == NULL) || (aus == NULL)) {				// Können Dateien geöffnet werden?
		printf("Fehler beim Oeffnen der Datei\n");		// Nein? Fehler.
		fclose(ein); fclose(aus);						// Dateien schließen
		return EXIT_FAILURE;							// Fehler zurückgeben
	} else {										// Ja?
		while(fgets(name, MAX, ein)){				// Datei auslesen
			if (name[0] == '#') continue;			// # zu Beginn der Zeile?

			if (sscanf(name,"%d %d", &i, &j) == 2) {				// 2 Zahlen in der Zeile?
				if (i >= 0 && i <= zeilen && j >= 0 && j <= spalten){		// Innerhalb des Zahlenbereichs?
				printf("%d %d\n", i, j);							// Inhalt der Datei (ohne #-Zeilen) am Bildschirm ausgeben
				fprintf(aus, "%d %d\n", i, j);						// Inhalt der Datei (ohne #-Zeilen) in 2. Datei schreiben
				a[i][j] = 1;										// Koordinate auf 1 (lebendig) setzen
				} else printf("Zahlen nicht im Zahlenbereich!\n");
			} else {
			printf("Fehler!\n");		// Keine 2 Zahlen in der Zeile
			system("PAUSE");			// Kommandozeile anhalten
			return EXIT_FAILURE;		// Fehler zurückgeben
			}
		}
	}

	// Originalmatrix ausgeben
	printf("\n\nDie eingegebene Matrix:\n\n");
	display_array(a, &zeilen, &spalten);
	
	// Ausführen / Berechnen und Ausgeben
	for(i = 0; i < schritte; i++) {				
		update_array(a, &zeilen, &spalten);		
		printf("\n\nRunde %d\n", i + 1);		
		display_array(a, &zeilen, &spalten);	
	}
	
	// Letzte Runde in Datei ausgeben
	fprintf(aus, "\n\nRunde %d\n", schritte);
	for(i = 0; i < zeilen; i++) { 
        for(j = 0; j < spalten; j++) { 
            fprintf(aus, " %d", a[i][j]); 
        } fprintf(aus, "\n"); 
    } fprintf(aus, "\n"); 

	// Dateien schließen
    fclose(ein); fclose(aus);
    
    printf("\n\n\n");
    system("PAUSE");
    return 0;
}

Benötigt werden 2 Dateien. Eine zu einlesen, eine zum reinschreiben.
Die erste sieht z.b. so aus:

Code:
#Life 1.06
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10

Die zweite, naja, je nachdem, was passiert ;)

Aufgerufen wird das Ganze über die Kommandozeile (heißt das überhaupt so? CMD):
Als Beispiel: "bla bla bla.exe" 10 10 life.txt 10
Dann sollte es eine 10 x 10 Matrix geben, Die in der Datei angegebenen Koordinaten werden auf 1 gesetzt, das Game Of Life läuft ab und zwar für 10 Runden / Schritte. Die Runden werden sowohl im stdout ausgegeben als auch (die letzte Runde) in lifeout.txt

Besten Dank nochmals für eure Hilfe! Falls ihr noch irgendwie über einen Fehler stolpern solltet, lasst es mich bitte wissen ;)
 

Neue Beiträge

Zurück