"Gra w życie" - problem z wczytywaniem stanu początkowego z pliku do wskaźnika planszy

0

Mam problem z wczytywaniem stanu poszczególnych komórek z pliku do wskaźnika planszy. Jest to modyfikacja programu z losowymi "życiami" generowanymi z srand().

  1. Inicjalizuję planszę o rozmiarze zgodnym z danymi w pliku (20x12).
  2. Wczytuję dane z pliku do kolejnych miejsc w pamięci wskaźnika *map za pomocą for'a.
  3. W międzyczasie wypisuję sobie wczytywane dane, żeby mieć pewność, że to nie problem z plikiem.
  4. Wyświetlam stan początkowy pokolenia 0, który jest niezgodny z wejściem z pliku.

Zauważyłem, że na każdy wiersz z pliku, program dopisuje mi jeden bajt znaku z tego wiersza. Czyli dla wejścia

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

wychodzi mi

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0

Nie wiem co mam zmienić, żeby tak się nie działo. Strzelam, że coś jest nie tak ze wskazywaniem kolejnych adresów po wskaźniku, ale nie mam aż takiej wiedzy, żeby wiedzieć co jest nie tak. Ewentualnie jest błąd w pętli wpisywania danych z pliku.
EDIT: dla siatek kwadratowych (x=y) wszystko jest w porządku, a dla nieparzystych dopisuje znaki.
life.h

#pragma once
#ifndef LIFE_H
#define LIFE_H

class CLife {
	int Nx, // liczba wierszy
		Ny, // liczba kolumn
		N;  // Nx*Ny
	int i, x, y, c, l;
	int *map, // wskaźnik planszy                   // 1 - żywa komórka, 0 - martwa komórka
		*buf; // wskaźnik bufor planszy do obliczeń 
	int nr, // numer pokolenia (zliczanie od 0)
		nn; // liczba sąsiadów komórki
public:
	CLife();
	CLife(int Nx, int Ny);
	~CLife();
	void Initialize();
	void Show();
	void Next();
	int X(int x);
	int Y(int y);
	void Set(int x, int y);
};

#endif // LIFE_H

life.cpp

#include "pch.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include "life.h"
using namespace std;

CLife::CLife() {
	int nr = 0;
	Nx = x;
	Ny = y;
	N = Nx * Ny;
	map = new int[N];
	buf = new int[N];
}

CLife::CLife(int Nx, int Ny) {
	int nr = 0;
	this->Nx = Nx;
	this->Ny = Ny;
	N = Nx * Ny;
	map = new int[N];
	buf = new int[N];
}

void CLife::Initialize() {
	int data;
	ifstream file;
	file.open("game.txt");
	for (int i = 0; i < N; i++) {
		file >> data;
		
		*(map + i) = data;
		cout << *(map+i) << " ";
		if ((i + 1) % 20 == 0) cout << endl;
	}
}

void CLife::Show() {
	cout << endl;
	cout << "Pokolenie: " << nr << endl;
	for (int y = 0; y < Ny; y++) {
		for (int x = 0; x < Nx; x++) {
			cout << *(map + y * Ny + x) << " ";
		}
		cout << endl;
	}
}

void CLife::Next() {
	for (int x = 0; x < Nx; x++) {
		for (int y = 0; y < Ny; y++) {
			nn = 0;

			for (int c = -1; c < 2; c++) {
				for (int l = -1; l < 2; l++) {
					if (((c != 0) || (l != 0)) && (*(map + Y(y + l)*Ny + X(x + c)) == 1)) nn++;
				}
			}


			if (*(map + y * Ny + x) == 1) {
				if ((nn == 2) || (nn == 3)) *(buf + y * Ny + x) = 1;
				else *(buf + y * Ny + x) = 0;
			}
			else {
				if (nn == 3) *(buf + y * Ny + x) = 1;
				else *(buf + y * Ny + x) = 0;
			}
		}
	}
	for (i = 0; i < N; i++) *(map + i) = *(buf + i);
	nr++; // zwieksza numer pokolenia o 1
}

int CLife::X(int x) {
	if (x == Nx) x = 0;
	if (x < 0) x = Nx - 1;
	return x;
}

int CLife::Y(int y) {
	if (y == Nx) y = 0;
	if (y < 0) y = Nx - 1;
	return y;
}

void CLife::Set(int x, int y) {
	*(map + y * Ny + x) = 1;
}

CLife::~CLife() {
	delete[] map;
	delete[] buf;
}

main.cpp

int main()
{
	CLife s(20, 12);
	s.Initialize();
	char c;
	cout << "Nacisnij C, by zaczac gre lub dowolny inny klawisz i C, aby zakonczyc gre";

	c = _getch();
	while (c == 'c') {
		s.Show();
		s.Next();
		cout << "Nacisnij C, by zaczac gre lub dowolny inny klawisz i C, aby zakonczyc gre";
		c = _getch();
	}
}
0

Trochę namotane.
Generalnie, jeśli w klasie masz jakąś zmienną to po pierwsze dobrze jej nadać wartość w konstruktorze i po drugie lepiej nie deklarować powtórnie (lokalnie) zmiennych o tych samych nazwach.

U Ciebie masz w klasie np. nr, a potem (w wierszu 19) napisałeś int nr=0;
Czy chciałeś wprowadzić nową zmienną (o tej samej nazwie), czy chciałeś wyzerować zmienną klasową?
Masz w klasie zmienną nr, której nie nadajesz wartości w konstruktorach, a w wierszu 73 robisz nr++.

Ta konstrukcja z this->Nx=Nx w wierszu 20 jest niezgrabna.
Rozumiem, że chciałeś w ten sposób odróżnić Nx klasowe od Nx wchodzącego jako parametr. Może lepiej w nagłówku byłoby dać inne zmienne np. (int _Nx, int _Ny)?

Nanieś poprawki, i może zadziała :-)

1
        if ((i + 1) % 20 == 0) cout << endl;

Magiczna liczba, ignorujesz szerokość planszy.

W ogóle, koniecznie przeczytaj:

0
Stefan_3N napisał(a):

Ta konstrukcja z this->Nx=Nx w wierszu 20 jest niezgrabna.
Rozumiem, że chciałeś w ten sposób odróżnić Nx klasowe od Nx wchodzącego jako parametr. Może lepiej w nagłówku byłoby dać inne zmienne np. (int _Nx, int _Ny)?

A jeszcze lepiej użyć do tego celu listy inicjalizacyjnej konstruktora. Co do nazywania zmiennych przekazanych jako parametr funkcji z podkreśleniem, to trąci coś takiego trochę notacją węgierską, która jest już troszkę jakby nie na czasie. No chyba, że ktoś programuje w notatniku. Wtedy owszem zgodzę się. Jednak po co sobie utrudniać? Sam stosuję taką notację tylko dla elementów GUI. Pozostałe zmienne nie mają takich przedrostków.

0

Postanowiłem przebudować ten dziwny wskaźnikowy wynalazek na zwykłe tablice. Teraz jedyny problem, który mi pozostał, to warunek brzegowy, który ma zapętlać mapę (np. komórka map[13][0] sąsiaduje z komórką map[13,11]). Wymiar mapy to 20x12.
To jest metoda od tego:


void CLife::CountNeighbors() {		//liczenie sąsiadów
	for (int y = 0; y < Ny; y++) {
		for (int x = 0; x < Nx; x++) {
			neighbors = 0;
			for (int ud = -1; ud < 2; ud++) {
				for (int lr = -1; lr < 2; lr++) {
					if (!(ud == 0 && lr == 0)) {
						if (map[x + lr][y + ud] == 1) {
							neighbors++;
						}
					}
				}
			}
			pomocnicza[x][y] = neighbors;	//tablica określająca ilość sąsiadów dla komórki map[x][y]
										//(w innej metodzie zmieniam status komórki w zależności od jej ilości)
		}
	}
	pokolenie++;
}

EDIT
Opracowałem te warunki, ale nie wiem w które miejsce je wstawić. Wyszło mi coś takiego:

	if (y == 0 && map[x][11] == 1)	//góra-dół
		neighbors++;
	if (y == 11 && map[x][0] == 1)	//dół-góra
		neighbors++;
	if (x == 19 && map[0][y] == 1)	//prawo-lewo
		neighbors++;
	if (x == 0 && map[19][y] == 1)	//lewo-prawo
		neighbors++;		

Jakieś pomysły?

1 użytkowników online, w tym zalogowanych: 0, gości: 1