este post eh continuação de

http://www.athanazio.com/2009/01/11/c-criando-um-labirinto-v1/

Fazer as conexões entre os elementos do labirinto foi uma coisa interessante, porque eu preciso de uma representação onde cada posição, seja parede ou celula vazia tenha a mesma largura para representar isto para cada item do labirinto criei uma matriz 3×3 onde a posição do centro representa a celula em si e as posições ao redor são as possiveis conexões com as proximas células, veja o desenho abaixo

o centro do quadro eh a celula atual sendo processada, e as caixa ao redor sao os possiveis vizinhos, note que para cara vizinho existe uma combinacao de modificadores para x e y, por exemplo o vizinho ao norte é 0 e -1 o do leste 1 e 0 e assim por diante.

alem disto para conectar ao vizinho armazenei tambem que coordenada na matriz de conexões é necessário atualizar para realizar a conexão, por exemplo para o norte a conexão é feita em 1,2 da matriz de conexões.

a matriz com estas definições está na classe de geração do maze

int[,] SearchNeighBorNumbers = { { 0, -1, 1, 2 }, { 1, 0, 0, 1 }, { 0, 1, 1, 0 }, { -1, 0, 2, 1 } };

desta forma preciso sortear somente que linha desta matriz vou usar para manipular o vizinho, e assim realizo as conexões. Antes que eu me esqueça ! além de mudar a matriz de conexões do vizinho é necessário fazer o mesmo na célula corrente e para encontrar a célula correta basta usar o mesmo deslocamento usado para encontrar o vizinho, dentro da matriz de conexões da celula atual, a partir da posicao 1,1 conforme este treco abaixo

current.conections[
1 + SearchNeighBorNumbers[neighborRow, NEIGHBOR_X],
1 + SearchNeighBorNumbers[neighborRow, NEIGHBOR_Y]] = OPEN;

algumas referencias para labirintos

tutorial sobre a geração do labirinto
http://www.mazeworks.com/mazegen/mazetut/index.htm

mais comentarios sobre o algoritmo
http://en.wikipedia.org/wiki/Maze#Generating_mazes

uma visao mais detalhada do Deep-first
http://en.wikipedia.org/wiki/Depth-first_search

Tagged with:
 

c# criando um labirinto v1

On January 11, 2009, in games, programacao, by athanazio
1

Para o jogo que estou criando preciso de uns labirintos e como não achei algo que pudesse gerar para um arquivo texto, estou implementando o meu mesmo, com algumas leituras vi que o algoritmo mais fácil para este caso seria a através de uma pilha assim eu garanto que percorri todos os elementos do labirinto.

o algortimo consiste em escolher uma posicao aleatoria, e buscar os vizinhos nao visitados ao redor, encontrando um abre caminho ateh ele e empilha o mesmo, e vai fazendo isto até que não existam vizinhos não visitados, assim vai desempilhando para voltar no caminho e tentando achar vizinhos não visitados no caminho de volta.
Assim percorremos todo o mapa mas ainda ficam uns becos sem saída, como pode ver marcado neste desenho que fiz quando estava testando manualmente o algoritmo

o teste foi de 5×5 e marquei com bolinhas abobora os becos sem saída, na próxima versão do algoritmo vou guardar os becos sem saída e conectar com algum vizinho =) eh melhor fazzer andar em círculos do que encontrar um beco em saída, hehehe

Seguem os códigos fonte, do gerador e do programa que esta gravando num arquivo texto o maze gerado, que por sinal esta com algum problema ainda …

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MazeGenerator
{
class Program
{
static void Main(string[] args)
{
MazeGen mazeGen = new MazeGen();
MazeGen.MazeCell[,] maze = mazeGen.generateMaze(5,5);

string fileName = “c:/work/maze” + DateTime.Now.ToBinary() + “.txt”;
FileStream stream = File.Open(fileName, FileMode.OpenOrCreate);
StreamWriter writer = new StreamWriter(stream);

for (int n = 0; n < maze.GetLength(0); n++)
{
for (int conn = 0; conn < 3; conn++)
{
for (int m = 0; m < maze.GetLength(1); m++)
{
writer.Write(maze[n, m].conections[conn, 0] == MazeGen.OPEN ? "_" : "*");
writer.Write(maze[n, m].conections[conn, 1] == MazeGen.OPEN ? "_" : "*");
writer.Write(maze[n, m].conections[conn, 2] == MazeGen.OPEN ? "_" : "*");
}
writer.WriteLine();
}
}
writer.Close();
}
}
}

MazeGen,cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MazeGenerator
{
public class MazeGen
{
public const Boolean DEBUG = true;
public const int CLOSED = 0;
public const int OPEN = 1;

public const int NEIGHBOR_X = 0;
public const int NEIGHBOR_Y = 1;
public const int NEIGHBOR_CONNECTION_2OPEN_X = 2;
public const int NEIGHBOR_CONNECTION_2OPEN_Y = 3;
public const int POSSIBLE_NEIGHBORS = 4;

public static Random random = new Random();

public class MazeCell
{
public MazeCell(int X, int Y)
{
this.X = X;
this.Y = Y;
this.Visited = false;
}

public Boolean Visited = false;
public int X;
public int Y;
// north, east, south, west
public byte[,] conections = { { CLOSED, CLOSED, CLOSED },
{ CLOSED, OPEN, CLOSED },
{ CLOSED, CLOSED, CLOSED } };

public override string ToString()
{
string buffer = "";
foreach( byte one in conections){
buffer += one.ToString();
}

return X + "," + Y + " [" + buffer +"] ";
}
}

// used to random the neighbor cell
// { increment of X, increment of Y, connection to open in the neighbor }
int[,] SearchNeighBorNumbers = { { 0, -1, 1, 2 }, { 1, 0, 0, 1 }, { 0, 1, 1, 0 }, { -1, 0, 2, 1 } };

public MazeCell[,] generateMaze(int rows, int cols)
{

// fill the matrix
MazeCell[,] result = new MazeCell[rows, cols];
for (int n = 0; n < result.GetLength(0); n++)
{
for (int m = 0; m < result.GetLength(1); m++)
{
result[n, m] = new MazeCell(n, m);
}
}

int visited = 1;
int total = rows * cols;

Stack path = new Stack();

int x = random.Next(1, rows - 1);
int y = random.Next(1, cols - 1);

result[x, y].Visited = true;

path.Push(result[x, y]);
MazeCell current = result[x, y];

while (visited < total)
{
// try the unvisited neighbors
int neighborRow = random.Next(0, 3);
MazeCell neighbor = nextRandomUnvisited(result, current, neighborRow);

int tries = 1;
while (tries < POSSIBLE_NEIGHBORS && neighbor == null)
{
neighborRow ++;
if( neighborRow >= POSSIBLE_NEIGHBORS ){
neighborRow = 0;
}
neighbor = nextRandomUnvisited(result, current, neighborRow);
tries ++;
}

if (neighbor == null)
{
current = (MazeCell)path.Pop();
}
else
{
current.conections[
1 + SearchNeighBorNumbers[neighborRow, NEIGHBOR_X],
1 + SearchNeighBorNumbers[neighborRow, NEIGHBOR_Y]] = OPEN;

neighbor.Visited = true;
neighbor.conections[
SearchNeighBorNumbers[neighborRow, NEIGHBOR_CONNECTION_2OPEN_X],
SearchNeighBorNumbers[neighborRow, NEIGHBOR_CONNECTION_2OPEN_Y]] = OPEN;

if (DEBUG){Console.WriteLine(“from {0} to {1}”, current, neighbor);}

path.Push(neighbor);
current = neighbor;
visited++;
}
}

return result;
}

public MazeCell nextRandomUnvisited(MazeCell[,] result, MazeCell current, int neighborRow)
{

int testX = current.X + SearchNeighBorNumbers[neighborRow, NEIGHBOR_X];
int testY = current.Y + SearchNeighBorNumbers[neighborRow, NEIGHBOR_Y];

// check if neighbor exists
// if not will try again
if (testX >= 0 && testX < result.GetLength(0) && testY >= 0 && testY < result.GetLength(1))
{

if (!result[testX, testY].Visited)
{
return result[testX, testY];
}
}

return null;
}

}
}

Tagged with:
 

codigo para gerar maze

On January 11, 2009, in games, by athanazio
1
Tagged with:
 

eu quero fazer um braid

On January 7, 2009, in trecos, by athanazio
1

eu quero fazer um braid !! http://www.astrolog.org/labyrnth/algrithm.htm

Tagged with: