Ĺadny brzuch
Cześć.
Ma ktoś jakiś dobry pomysł, jak najsprawniej (i najoptymalniej) można zrobić siatkę prostokątną/hexagonalną obiektów jakiejś klasy, ale tak, by w każdym obiekcie była dostępna łatwo informacja, z którymi obiektami jest on bezpośrednio połączony na siatce?
Chodzi o to, by odwołując się do jakiegoś elementu siatki mieć od razu informację o jego sąsiadach i nie musieć sprawdzać całej siatki, by poznać, czy jakiś element jest sąsiadem, czy nie.
Na razie mam tak (nie sprawdzałem, czy działa, bo nie mam w tej chwili dostępu do kompilatora):
class obiekt { int x, y; void sasiedzi_ptr[8]; public: void obiekt(int xx, int yy) { x=xx; y=yy; for (i=0; i<8; i++) { sasiedzi_ptr = 0; } } }; list<obiekt> obiekty; list<obiekt>::iterator obj_it, obj_ptr; int grid_dim = 5; //---------- int main(...) { obiekt o; int sasiad = 0; //- utworz elementy siatki for (i=1; i<=grid_dim; i++) for (j=1; j<=grid_dim; j++) obiekty.push_back(obiekt(i,j)); //- przypisz elementom wskazniki do ich sasiadow obj_it = obiekty.begin(); obj_ptr = obj_it; for (; obj_it!=obiekty.end(); obj_it++) { o = *obj_it; if (i>1) { advance(obj_ptr,-grid_dim); o.sasiedzi_ptr[sasiad++] = obj_ptr; // *** if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; } obj_ptr = obj_it; } if (j>1) { advance(obj_ptr,-1); o.sasiedzi_ptr[sasiad++] = obj_ptr; obj_ptr = obj_it; } if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; obj_ptr = obj_it; } if (i<grid_dim) { advance(obj_ptr,grid_dim); o.sasiedzi_ptr[sasiad++] = obj_ptr; if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; } } } }Nie jestem pewien, czy linia oznaczona przez *** zadziała.
Czy jest może jakiś bardziej optymalny sposób?
Uważam, że takie pisanie nie ma sensu. Jeśli nie masz dostępu do kompilatora, to nie bierz się za tworzenie kodu. Zwłaszcza, że brakuje Ci podstaw (np. nie można utworzyć zmiennych o typie void, można ew. void*). Jeśli chcesz stworzyć 2-wymiarową siatkę, to wykorzystaj do tego 2-wymiarową tablicę. Po co bawić się z listami? Oznaczona linia nie zadziała (dowiedziałbyś się, gdybyś skompilował program), bo nie można przekonwertować iteratora do typu void (czy void*).
Siatka prostokątna posiada prostokątne pola, a każde pole ma 4 sąsiadów (ew. 8 jeśli liczyć stykające się narożnikami). Siatka heksagonalna składa się z sześcianów, a każde pole ma 6 sąsiadów. Domyślam się, że chodzi Ci o pierwszy wariant. To powinno Ci pomóc:
#include <iostream> using namespace std; class Field { public: static const int NeighboursCount = 8; int x; int y; Field* neighbours[NeighboursCount]; Field() { for (int i = 0; i < NeighboursCount; ++i) { neighbours[i] = NULL; } } }; const int indices[Field::NeighboursCount][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } }; class Grid { public: static const int sizeX = 5; static const int sizeY = 8; Field fields[sizeX][sizeY]; Grid() { for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { for (int i = 0; i < Field::NeighboursCount; ++i) { fields[x][y].x = x; fields[x][y].y = y; int posX = x + indices[i][0]; int posY = y + indices[i][1]; if (posX >= 0 && posY >= 0 && posX < sizeX && posY < sizeY) { fields[x][y].neighbours[i] = &(fields[posX][posY]); } } } } } void display() { for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { int count = 0; for (int i = 0; i < Field::NeighboursCount; ++i) { if (fields[x][y].neighbours[i]) { ++count; } } cout << count; } cout << endl; } } }; int main() { Grid grid; grid.display(); return 0; }
Użytkownik Kozack edytował ten post 02 listopad 2008, 12:01
Robiłem na liście, bo wymiar siatki nie jest stały. Jednak chyba rzeczywiście przedobrzyłem z tymi listami, bo przecież można wpisać w kodzie, by zarezerowana została pamięć dla maksymalnej siatki, którą będę miał możliwość wykorzystać, a korzystać tylko z części o wymiarze, który potrzebuję. (Choć pomyślałem o liście, gdyż łatwo ją posortować, z czego będę korzystał.)
Dzięki wielkie za pomoc, Kozack!
Jeśli ktoś ma do dodanie jakieś swoje słowo, to zachęcam.
Użytkownik JackK edytował ten post 02 listopad 2008, 12:42
Możesz tworzyć dynamiczne tablice. Możliwości jest wiele.
Field** fields = new Field*[sizeX]; for (int i = 0; i < sizeX; ++i) { fields[i] = new Field[sizeY]; }
std::vector<Field> fields; fields.resize(sizeX * sizeY); for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { fields[x * sizeY + y]; } }
Po rezygnacji z list, program działa o wiele szybciej :)
zanotowane.pl doc.pisz.pl pdf.pisz.pl zsf.htw.pl
Ma ktoś jakiś dobry pomysł, jak najsprawniej (i najoptymalniej) można zrobić siatkę prostokątną/hexagonalną obiektów jakiejś klasy, ale tak, by w każdym obiekcie była dostępna łatwo informacja, z którymi obiektami jest on bezpośrednio połączony na siatce?
Chodzi o to, by odwołując się do jakiegoś elementu siatki mieć od razu informację o jego sąsiadach i nie musieć sprawdzać całej siatki, by poznać, czy jakiś element jest sąsiadem, czy nie.
Na razie mam tak (nie sprawdzałem, czy działa, bo nie mam w tej chwili dostępu do kompilatora):
class obiekt { int x, y; void sasiedzi_ptr[8]; public: void obiekt(int xx, int yy) { x=xx; y=yy; for (i=0; i<8; i++) { sasiedzi_ptr = 0; } } }; list<obiekt> obiekty; list<obiekt>::iterator obj_it, obj_ptr; int grid_dim = 5; //---------- int main(...) { obiekt o; int sasiad = 0; //- utworz elementy siatki for (i=1; i<=grid_dim; i++) for (j=1; j<=grid_dim; j++) obiekty.push_back(obiekt(i,j)); //- przypisz elementom wskazniki do ich sasiadow obj_it = obiekty.begin(); obj_ptr = obj_it; for (; obj_it!=obiekty.end(); obj_it++) { o = *obj_it; if (i>1) { advance(obj_ptr,-grid_dim); o.sasiedzi_ptr[sasiad++] = obj_ptr; // *** if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; } obj_ptr = obj_it; } if (j>1) { advance(obj_ptr,-1); o.sasiedzi_ptr[sasiad++] = obj_ptr; obj_ptr = obj_it; } if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; obj_ptr = obj_it; } if (i<grid_dim) { advance(obj_ptr,grid_dim); o.sasiedzi_ptr[sasiad++] = obj_ptr; if (j<grid_dim) { advance(obj_ptr,1); o.sasiedzi_ptr[sasiad++] = obj_ptr; } } } }Nie jestem pewien, czy linia oznaczona przez *** zadziała.
Czy jest może jakiś bardziej optymalny sposób?
Uważam, że takie pisanie nie ma sensu. Jeśli nie masz dostępu do kompilatora, to nie bierz się za tworzenie kodu. Zwłaszcza, że brakuje Ci podstaw (np. nie można utworzyć zmiennych o typie void, można ew. void*). Jeśli chcesz stworzyć 2-wymiarową siatkę, to wykorzystaj do tego 2-wymiarową tablicę. Po co bawić się z listami? Oznaczona linia nie zadziała (dowiedziałbyś się, gdybyś skompilował program), bo nie można przekonwertować iteratora do typu void (czy void*).
Siatka prostokątna posiada prostokątne pola, a każde pole ma 4 sąsiadów (ew. 8 jeśli liczyć stykające się narożnikami). Siatka heksagonalna składa się z sześcianów, a każde pole ma 6 sąsiadów. Domyślam się, że chodzi Ci o pierwszy wariant. To powinno Ci pomóc:
#include <iostream> using namespace std; class Field { public: static const int NeighboursCount = 8; int x; int y; Field* neighbours[NeighboursCount]; Field() { for (int i = 0; i < NeighboursCount; ++i) { neighbours[i] = NULL; } } }; const int indices[Field::NeighboursCount][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } }; class Grid { public: static const int sizeX = 5; static const int sizeY = 8; Field fields[sizeX][sizeY]; Grid() { for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { for (int i = 0; i < Field::NeighboursCount; ++i) { fields[x][y].x = x; fields[x][y].y = y; int posX = x + indices[i][0]; int posY = y + indices[i][1]; if (posX >= 0 && posY >= 0 && posX < sizeX && posY < sizeY) { fields[x][y].neighbours[i] = &(fields[posX][posY]); } } } } } void display() { for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { int count = 0; for (int i = 0; i < Field::NeighboursCount; ++i) { if (fields[x][y].neighbours[i]) { ++count; } } cout << count; } cout << endl; } } }; int main() { Grid grid; grid.display(); return 0; }
Użytkownik Kozack edytował ten post 02 listopad 2008, 12:01
Robiłem na liście, bo wymiar siatki nie jest stały. Jednak chyba rzeczywiście przedobrzyłem z tymi listami, bo przecież można wpisać w kodzie, by zarezerowana została pamięć dla maksymalnej siatki, którą będę miał możliwość wykorzystać, a korzystać tylko z części o wymiarze, który potrzebuję. (Choć pomyślałem o liście, gdyż łatwo ją posortować, z czego będę korzystał.)
Dzięki wielkie za pomoc, Kozack!
Jeśli ktoś ma do dodanie jakieś swoje słowo, to zachęcam.
Użytkownik JackK edytował ten post 02 listopad 2008, 12:42
Możesz tworzyć dynamiczne tablice. Możliwości jest wiele.
Field** fields = new Field*[sizeX]; for (int i = 0; i < sizeX; ++i) { fields[i] = new Field[sizeY]; }
std::vector<Field> fields; fields.resize(sizeX * sizeY); for (int x = 0; x < sizeX; ++x) { for (int y = 0; y < sizeY; ++y) { fields[x * sizeY + y]; } }
Po rezygnacji z list, program działa o wiele szybciej :)