Wyjscia z labiryntu
Janusz Sobieraj - 28 LO

Szukam wyjść z labiryntu

[Twoja przeglądarka nie obsługuje apletów Javy]
Z Wikipedii
Labirynt (gr.labyrinthos) - ciąg korytarzy, w którym trudno znależć wyjście. Używany czasami w matematyce i w logice. Słowo labirynt jest właściwie niegreckiego pochodzenia, często uważa się, że pochodzi od przedgreckiego (pelazgijskiego) słowa labrys, które oznaczało obusieczny topór.

Metod szukania wyjścia/wyjść z labiryntu jest chyba trzy ( nie licząc ich modyfikacji ) np taka:
DOPÓKI (nie trafiłeś na wyjście LUB nie trafiłeś do punktu startowego) na każdym skrzyzowaniu zawsze skręcasz w tę samą stronę (np w prawo).

Nasz aplet proponuje szukanie wyjścia z plataniny korytarzy (czasami) i większych wolnych obszarów (jaskiń), nie jest przeto "klasycznym labiryntem". Mimo wszystko dalej będę go nazywał labiryntem ( ze zwykłej wygody ).

Obserwując poprzedni aplet "wypełnij obszar", nasuwa sie nieodparte wrażenie, że w trakcie wypełniania, widoczne jest niezwykłe dążenie, aby jak najszybciej trafić do brzegu figury. Wykorzystamy to.
Rozwiążę zadanie:
Startując z wewnętrznego punktu "labiryntu" znaleźć wszystkie możliwe wyjścia (tym samym drogi do tych wyjść)

Tym razem zastosuję rozwiązanie rekurencyjne. Wolne pola "labiryntu" nie są w przesadnie wielkiej liczbie i raczej nie grozi nam kłopot : Stack overflow. Gdyby jednak, znamy rozwiązanie alternatywne (patrz wypełnianie).

Przy tym podejściu nie ma potrzeby korzystania z liczb losowych oraz struktur typu lista / stos. W aplecie zastosowalem jednak stos, by zilustrować proces szukania i pokazać nieduże koszty algorytmu w prezentowanej sytuacji.

void losuj_lab( ) 
{ 
  for(int i=1;i<w-1;i++) 
   for(int j=1;j<k-1;j++) 
    { 
      lab[j][i]=mat.losowa_c(5)<3; 
      // zapelniam labirynt bez brzegów 
    } 
  for(int i=0;i<k;i++) 
    { 
      lab[i][0]=(mat.losowa_c(5)==0); 
      lab[i][w-1]=(mat.losowa_c(5)==0); 
      // wypelniam brzegi lewy i prawy 
    } 
  for(int i=0;i<w;i++) 
    { 
      lab[0][i]=(mat.losowa_c(5)==0); 
      lab[k-1][i]=(mat.losowa_c(5)==0); 
      // wypelniam brzeg górny i dolny 
    } 
		
    lab[k/2-1][w/2-1]=true; 
  // zapewniam dostepnym srodek labiryntu 
} 
Teraz zbuduję "labirynt" o wymiarach w x k (w przykładzie w=k, ale to bez znaczenia), jego stan zapamiętam w tablicy boolean lab[k][w], gdzie pole "wolne" oznaczę true zaś element muru false.
Losowo wypełnię elementy tablicy lab z prawdopodobieństwem p→true, i z prawdopodobienstwem 1-p→false.
Odrębne losowanie zapewni "wyjścia" na brzegach.

Algorytm wypisujacy adresy wyjść można ująć w formie funkcji logicznej szukaj (zapewniamy sobe skończenie watku rekurencyjnego !!!)

boolean szukaj(int k_,int w_) 
{boolean czy=true; 
  if(brzeg(k_,w_)) 
  { 
    wypisz(k_,w_); 
    return true; 
  } 
  lab[k_-1][w_-1]=false; 
  if(lab[k_+1][w_])czy=szukaj(k_+1,w_); 
  if(lab[k_-1][w_])czy=szukaj(k_-1,w_); 
  if(lab[k_][w_+1])czy=szukaj(k_,w_+1); 
  if(lab[k_][w_-1])czy=szukaj(k_,w_-1); 
  return czy; 
}

Zdefiniuję funkcje sprawdzającą, czy osiagnąłem
już brzeg labiryntu:
boolean brzeg(int x,int y) 
{ 
  return(x==1 || x==k || y==1 || y==w); 
} 
Funkcja szukaj to tylko zapis idei algorytmu.
Spróbuj samodzielnie wykonać wizualizację.
Nieskromnie sugeruję, by tak jak w widocznym aplecie pokazać caly proces szukania wyjścia, z prezentacją momentów wycofywania się z nietrafnych kierunków. Uwaga:
Funkcja szukaj (w prezentowanej formie) zawsze zwraca wartość true.