20x20, 100k koşularda 230.794,38
Son Güncelleme: Sonunda mükemmel dinamik 2 yollu çözüm geliştirdim. Önceki versiyonun aslında simetrik olmadığı için mükemmel dedim, ayyaş bir yoldan diğerine geçerse daha uzun yol almak daha kolaydı. Mevcut olan simetriktir, bu nedenle beklenen sayıda adım alabilir. Birkaç denemeden sonra, 230k civarında, bir öncekine göre yaklaşık 228k'lık bir gelişme gibi görünüyor. Ancak istatistiksel olarak bu rakamlar hala büyük sapmaları içinde, bu yüzden bunun önemli ölçüde daha iyi olduğunu iddia etmiyorum, ancak bunun önceki versiyondan daha iyi olması gerektiğine inanıyorum.
Kod bu yazının altındadır. Bir önceki versiyondan çok daha hızlı olacak şekilde güncellenir ve 23'lerde 1000 çalışmayı tamamlar.
Aşağıda örnek çalışma ve örnek labirent verilmiştir:
Mükemmel Yürüteç
Ortalama: 230794.384
Maksimum: 1514506
Min: 25860
Tamamlandı 2317.374s
_ _ _ _ _ _ _ _ _ _ _ _ _.
| | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | _ | | _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | | | | | | | | | _ _ _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | | | | | | | | | _ _ _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | _ | | _ | | _ | | _ | | _ _ _ _ _ _
| | | | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | | | | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ | | _ | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Önceki gönderimler
Sonunda Sparr'ın sonucunu eşleştirebilirim! = D
Önceki deneylerime dayanarak (bu yazının altına bakın), en iyi strateji, sarhoş bunlardan herhangi birine ulaştığında çift yollu ve bir tane kapatmaktır ve değişken, sarhoşun nereye gideceğini dinamik olarak tahmin edebileceğimizden gelir. daha uzun bir yola girme şansını arttırır.
Bu yüzden DOUBLE_PATH
stratejime dayanarak DOUBLE_PATH
, sarhoş hareketine bağlı olarak labirenti değiştiren ( labirentim kolayca değiştirilebilir) başka bir tane inşa ettim . Birden fazla mevcut seçeneğe sahip bir yol alırken, sadece iki olası seçeneği (biri geldiği, diğeri izlenmemiş) bırakacak şekilde yolları kapatacağım.
Sonuçta görüldüğü gibi, bu Sparr'ın başardığı şeye benziyor. Onunla olan fark daha iyi düşünülemeyecek kadar küçük, ama labirentim Sparr's = 'den daha değiştirilebilir olduğu için yaklaşımımın ondan daha dinamik olduğunu söyleyebilirim.
Örnek bir son labirent ile sonuç:
EXTREME_DOUBLE_PATH
Ortalama: 228034.89
Maksimum: 1050816
Min: 34170
Tamamlandı 396.728s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Deney Bölümü
En iyisi stokastic ile aynı strateji olduğu ortaya çıkıyor, çeşitli stratejiler kullanarak denemeler yapmak ve güzel çıktılar basmaktan gurur duyuyorum :)
Aşağıdaki basılı labirentlerin her biri, sarhoş eve ulaştıktan sonraki son labirenttir , bu nedenle sarhoş hareketindeki rastgelelik ve rakiplerin dinamizmi nedeniyle koşmaktan biraz farklı olabilirler.
Her stratejiyi açıklayacağım:
Tek Yol
Bu, girişten çıkışa tek bir yol oluşturacak en basit yaklaşımdır.
SINGLE_PATH
Ortalama: 162621.612
Maksimum: 956694
Min: 14838
Tamamlandı 149.430s
_ _ _ _ _ _ _ _ _ _ _
| | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Ada (seviye 0)
Bu, neredeyse izole bir adada sarhoşu yakalamaya çalışan bir yaklaşımdır. Beklediğim kadar iyi çalışmıyor, ancak bu benim ilk fikirlerimden biri, bu yüzden dahil ediyorum.
Çıkışa giden iki yol var ve ayyaş bunlardan birine yaklaştığında, rakip onu kapatıyor ve onu diğer çıkışı bulmaya zorluyor (ve muhtemelen adada tekrar tuzağa düşüyor)
ADASI
Ortalama: 74626.070
Maksimum: 428560
Min: 1528
Tamamlandı 122.512s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Çift Yol
Bu, en çok tartışılan stratejidir, bu da çıkışa iki eşit uzunluktaki yola sahip olmak ve bunlardan birini, sarhoş bunlardan birine yaklaştıkça kapatmaktır.
DOUBLE_PATH
Ortalama: 197743.472
Maksimum: 1443406
Min: 21516
Tamamlandı 308.177s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Ada (seviye 1)
Adanın birden çok yolundan ve tek yoldaki yüksek yürüyüş sayısından esinlenerek, adayı çıkışa bağlarız ve adada tek yol labirenti yaparız, çıkmak için toplam üç yol yaratırız ve önceki duruma benzer şekilde, ayyaş yaklaştıkça çık.
Bu saf tek yoldan biraz daha iyi çalışır, ancak yine de çift yolu yenmez.
ADASI
Ortalama: 166265.132
Maksimum: 1162966
Min: 19544
Tamamlandı 471.982s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ | _
| | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Ada (seviye 2)
Önceki fikri genişletmeye çalışarak, toplam beş yol oluşturarak iç içe bir ada yarattım, ancak bu işe yaramadı.
ADASI
Ortalama: 164222.712
Maksimum: 927608
Min: 22024
Tamamlandı 793.591s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _
| | _ _ _ _ _ _ _ _ | _ |
| | | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| _ | _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Ada (seviye 3)
Çift yolun aslında tek yoldan daha iyi çalıştığını fark ederek, adayı çift yol haline getirelim!
Sonuç Ada üzerinde bir gelişme (seviye 1), ama yine de saf çift yolu yenmez.
Karşılaştırma için, adanın büyüklüğünün çift yolunun sonucu ortalama 131.134,42 harekettir. Bu, oldukça önemli sayıda hareket (yaklaşık 40k) ekler, ancak çift yolu yenmek için yeterli değildir.
ADASI
Ortalama: 171730.090
Maksimum: 769080
Min: 29760
Tamamlandı 587.646s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Ada (seviye 4)
Yine, iç içe ada ile deneyler ve yine o kadar iyi çalışmıyor.
ADASI
Ortalama: 149723.068
Max: 622106
Min: 25752
Tamamlandı 830.889s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _ |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
Sonuç
Sonuçta, bu, sarhoş akım konumundan çıkışa kadar tek bir uzun yolun en iyi şekilde çalıştığını kanıtlıyor, bu da çift yol stratejisi ile elde ediliyor, çünkü bir çıkışı kapattıktan sonra, sarhoşun ulaşmak için mümkün olan maksimum mesafeyi kat etmesi gerekecek. çıkış.
Bu, temel stratejinin hala çift yol olması gerektiğine işaret ediyor ve sadece Sparr tarafından yapılan yolların ne kadar dinamik oluşturulduğunu değiştirebiliyoruz. Bu yüzden stratejisinin ilerlemenin yolu olduğuna inanıyorum!
kod
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.TreeSet;
public class Walker {
enum Strategy{
SINGLE_PATH,
ISLAND,
DOUBLE_PATH,
EXTREME_DOUBLE_PATH,
PERFECT_DOUBLE_PATH,
}
int width,height;
int x,y; //walker's position
int dX,dY; //destination
Point[][] points;
int stepCount = 0;
public static void main(String[]args){
int side = 20;
// runOnce(side, Strategy.EXTREME_DOUBLE_PATH, 0);
runOnce(side, Strategy.PERFECT_DOUBLE_PATH, 0);
// for(Strategy strategy: Strategy.values()){
// runOnce(side, strategy, 0);
// }
// runOnce(side, Strategy.ISLAND, 1);
// runOnce(side, Strategy.ISLAND, 2);
// Scanner scanner = new Scanner(System.in);
// System.out.println("Enter side, strategy (SINGLE_PATH, ISLAND, DOUBLE_PATH, EXTREME_DOUBLE_PATH), and level:");
// while(scanner.hasNext()){
// side = scanner.nextInt();
// Strategy strategy = Strategy.valueOf(scanner.next());
// int level = scanner.nextInt();
// scanner.nextLine();
// runOnce(side, strategy, level);
// System.out.println("Enter side, strategy (SINGLE_PATH, ISLAND, DOUBLE_PATH, EXTREME_DOUBLE_PATH), and level:");
// }
// scanner.close();
}
private static Walker runOnce(int side, Strategy strategy, int level) {
Walker walker = null;
long total = 0;
int max = 0;
int min = Integer.MAX_VALUE;
double count = 1000;
long start = System.currentTimeMillis();
for(int i=0; i<count; i++){
walker = new Walker(0,0,side,side,side-1,side-1, strategy, level, false);
total += walker.stepCount;
max = Math.max(walker.stepCount, max);
min = Math.min(walker.stepCount, min);
// System.out.println("Iteration "+i+": "+walker.stepCount);
}
System.out.printf("%s\nAverage: %.3f\nMax: %d\nMin:%d\n",strategy, total/count, max, min);
System.out.printf("Completed in %.3fs\n", (System.currentTimeMillis()-start)/1000.0);
walker.printPath();
return walker;
}
private void createIsland(int botLeftX, int botLeftY, int topRightX, int topRightY){
for(int i=botLeftY+1; i<topRightY; i++){
if(i>botLeftY+1) deletePath(points[botLeftX][i].right());
if(i<topRightY-1) deletePath(points[topRightX][i].left());
}
for(int i=botLeftX+1; i<topRightX; i++){
if(i>botLeftX+1) deletePath(points[i][botLeftY].up());
if(i<topRightX-1) deletePath(points[i][topRightY].down());
}
}
private void createSinglePath(int botLeftX, int botLeftY, int topRightX, int topRightY){
for(int i=botLeftY; i<topRightY; i++){
if(i==topRightY-1 && (topRightY+1-botLeftY)%2==0){
for(int j=botLeftX; j<topRightX; j++){
if(j==topRightX-1 && (j-botLeftX)%2==0){
deletePath(points[topRightX][topRightY].down());
} else {
deletePath(points[j][topRightY-1+((j-botLeftX)%2)].right());
}
}
} else {
for(int j=botLeftX+(i-botLeftY)%2; j<topRightX+((i-botLeftY)%2); j++){
deletePath(points[j][i].up());
}
}
}
}
private void createDoublePath(int botLeftX, int botLeftY, int topRightX, int topRightY){
for(int i=botLeftY; i<topRightY; i++){
if(i>botLeftY && (width%4!=1 || i<topRightY-1)) deletePath(points[width/2-1][i].right());
if(i==topRightY-1 && (topRightY+1-botLeftY)%2==1){
for(int j=botLeftX; j<topRightX; j++){
if((j-botLeftX)%2==0 || j<topRightX-1){
deletePath(points[j][topRightY-1+((j-botLeftX)%2)].right());
} else {
deletePath(points[topRightX-1][topRightY-1].right());
}
}
} else {
if((i-botLeftY)%2==0){
for(int j=botLeftX+1; j<topRightX; j++){
deletePath(points[j][i].up());
}
} else {
for(int j=botLeftX; j<topRightX+1; j++){
if(j!=width/2 && j!=width/2-1){
deletePath(points[j][i].up());
}
}
}
}
}
}
public Walker(int startingX,int startingY, int Width, int Height, int destinationX, int destinationY, Strategy strategy, int level, boolean animate){
width = Width;
height = Height;
dX = destinationX;
dY = destinationY;
x=startingX;
y=startingY;
points = new Point[width][height];
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
points[x][y] = new Point(x,y);
}
}
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
if(x<width-1) new Edge(points[x][y], points[x+1][y]);
if(y<height-1) new Edge(points[x][y], points[x][y+1]);
}
}
if(strategy == Strategy.SINGLE_PATH) createSinglePath(0,0,width-1,height-1);
if(strategy == Strategy.DOUBLE_PATH) createDoublePath(0,0,width-1,height-1);
List<EdgeList> edgeLists = new ArrayList<EdgeList>();
if(strategy == Strategy.ISLAND){
List<Edge> edges = new ArrayList<Edge>();
if(level==0){
createIsland(0,0,width-1,height-1);
deletePath(points[width-2][height-2].right());
deletePath(points[width-2][height-2].up());
} else {
for(int i=0; i<level; i++){
createIsland(i,i,width-1-i, height-1-i);
}
createDoublePath(level,level,width-1-level,height-1-level);
for(int i=height-1; i>=height-level; i--){
edges.add(points[i-2][i].right());
edges.add(points[i][i-2].up());
edgeLists.add(new EdgeList(points[i-1][i].right(), points[i][i-1].up()));
}
}
edges.add(points[width-1-level][height-1-level].down());
edges.add(points[width-1-level][height-1-level].left());
edgeLists.add(new EdgeList(edges.toArray(new Edge[0])));
}
int[] availableVerticals = new int[height];
if(strategy == Strategy.EXTREME_DOUBLE_PATH){
for(int i=1; i<width-1; i++){
deletePath(points[i][0].up());
}
availableVerticals[0] = 2;
for(int i=1; i<height; i++){
availableVerticals[i] = width;
}
}
boolean[][] available = new boolean[width][height];
if(strategy == Strategy.PERFECT_DOUBLE_PATH){
for(int x=0; x<width; x++){
for(int y=0; y<height; y++){
if(x%2==1 && y%2==1){
available[x][y] = true;
} else {
available[x][y] = false;
}
}
}
}
// printPath();
while(!walk()){
if(animate)try{Thread.sleep(500);}catch(InterruptedException e){}
if(strategy == Strategy.ISLAND){
if(x==y && (x==1 || (x>=2 && x<=level))){
if(!hasBeenWalked(points[x][x].down())){
deletePath(points[x][x].down());
} else if(!hasBeenWalked(points[x][x].left())){
deletePath(points[x][x].left());
}
}
}
if(strategy == Strategy.EXTREME_DOUBLE_PATH){
Point cur = points[x][y];
int untravelled = 0;
for(Edge edge: cur.edges) if(edge!=null && !edge.walked) untravelled++;
if(untravelled>1){
if(cur.up()!=null && availableVerticals[y]>2 && !cur.up().walked){
deletePath(cur.up());
availableVerticals[y]--;
}
if(cur.down()!=null && !cur.down().walked){
deletePath(cur.down());
availableVerticals[y-1]--;
}
if(cur.up()!=null && cur.left()!=null && !cur.left().walked){
deletePath(cur.left());
deletePath(points[x][y+1].left());
}
if(cur.up()!=null && cur.right()!=null && !cur.right().walked){
deletePath(cur.right());
if(y<height-1) deletePath(points[x][y+1].right());
}
}
}
if(strategy == Strategy.PERFECT_DOUBLE_PATH){
Point cur = points[x][y];
int untravelled = 0;
for(Edge edge: cur.edges) if(edge!=null && !edge.walked) untravelled++;
if(x%2!=1 || y%2!=1){
if(untravelled>1){
if(cur.down()==null && hasBeenWalked(cur.right())){
if(canBeDeleted(cur.up())) deletePath(cur.up());
}
if(cur.down()==null && hasBeenWalked(cur.left())){
if(x%2==0 && y%2==1 && canBeDeleted(cur.right())) deletePath(cur.right());
else if(cur.right()!=null && canBeDeleted(cur.up())) deletePath(cur.up());
}
if(cur.left()==null && hasBeenWalked(cur.up())){
if(canBeDeleted(cur.right())) deletePath(cur.right());
}
if(cur.left()==null && hasBeenWalked(cur.down())){
if(x%2==1 && y%2==0 && canBeDeleted(cur.up())) deletePath(cur.up());
else if (cur.up()!=null && canBeDeleted(cur.right())) deletePath(cur.right());
}
}
} else {
if(!hasBeenWalked(cur.left())){
if(x>1 && available[x-2][y]){
if(untravelled>1){
available[x-2][y] = false;
deletePath(cur.up());
}
} else if(cur.up()!=null){
if(canBeDeleted(cur.left())) deletePath(cur.left());
if(canBeDeleted(points[x][y+1].left())) deletePath(points[x][y+1].left());
}
}
if(!hasBeenWalked(cur.down())){
if(y>1 && available[x][y-2]){
if(untravelled>1){
available[x][y-2] = false;
deletePath(cur.right());
}
} else if(cur.right()!=null){
if(canBeDeleted(cur.down())) deletePath(cur.down());
if(canBeDeleted(points[x+1][y].down())) deletePath(points[x+1][y].down());
}
}
}
}
if(strategy == Strategy.DOUBLE_PATH || strategy == Strategy.EXTREME_DOUBLE_PATH
|| strategy == Strategy.PERFECT_DOUBLE_PATH){
if(x==width-2 && y==height-1 && points[width-1][height-1].down()!=null){
deletePath(points[width-1][height-1].left());
}
if(x==width-1 && y==height-2 && points[width-1][height-1].left()!=null){
deletePath(points[width-1][height-1].down());
}
} else if(strategy == Strategy.ISLAND){
for(EdgeList edgeList: edgeLists){
boolean deleted = false;
for(Edge edge: edgeList.edges){
if(edge.start.x == x && edge.start.y == y){
if(!hasBeenWalked(edge)){
deletePath(edge);
edgeList.edges.remove(edge);
if(edgeList.edges.size() == 1){
edgeLists.remove(edgeList);
}
deleted = true;
break;
}
}
}
if(deleted) break;
}
}
if(animate)printPath();
}
}
public boolean hasBeenWalked(Edge edge){
if(edge == null) return false;
return edge.walked;
}
public boolean canBeDeleted(Edge edge){
if(edge == null) return false;
return !edge.walked;
}
public List<Edge> getAdjacentUntravelledEdges(){
List<Edge> result = new ArrayList<Edge>();
for(Edge edge: points[x][y].edges){
if(edge!=null && !hasBeenWalked(edge)) result.add(edge);
}
return result;
}
public void printPath(){
StringBuilder builder = new StringBuilder();
for(int y=height-1; y>=0; y--){
for(int x=0; x<width; x++){
Point point = points[x][y];
if(this.x==x && this.y==y){
if(point.up()!=null) builder.append('?');
else builder.append('.');
} else {
if(point.up()!=null) builder.append('|');
else builder.append(' ');
}
if(point.right()!=null) builder.append('_');
else builder.append(' ');
}
builder.append('\n');
}
System.out.print(builder.toString());
}
public boolean walk(){
ArrayList<Edge> possibleMoves = new ArrayList<Edge>();
Point cur = points[x][y];
for(Edge edge: cur.edges){
if(edge!=null) possibleMoves.add(edge);
}
int random = (int)(Math.random()*possibleMoves.size());
Edge move = possibleMoves.get(random);
move.walked = true;
if(move.start == cur){
x = move.end.x;
y = move.end.y;
} else {
x = move.start.x;
y = move.start.y;
}
stepCount++;
if(x==dX && y == dY){
return true;
} else {
return false;
}
}
public boolean isSolvable(){
TreeSet<Point> reachable = new TreeSet<Point>();
Queue<Point> next = new LinkedList<Point>();
next.offer(points[x][y]);
reachable.add(points[x][y]);
while(next.size()>0){
Point cur = next.poll();
ArrayList<Point> neighbors = new ArrayList<Point>();
if(cur.up()!=null) neighbors.add(cur.up().end);
if(cur.right()!=null) neighbors.add(cur.right().end);
if(cur.down()!=null) neighbors.add(cur.down().start);
if(cur.left()!=null) neighbors.add(cur.left().start);
for(Point neighbor: neighbors){
if(!reachable.contains(neighbor)){
if(neighbor == points[dX][dY]) return true;
reachable.add(neighbor);
next.offer(neighbor);
}
}
}
return false;
}
public boolean deletePath(Edge toDelete){
if(toDelete == null) return true;
// if(toDelete.walked){
// System.err.println("Edge already travelled!");
// return false;
// }
int startIdx = toDelete.getStartIdx();
int endIdx = toDelete.getEndIdx();
toDelete.start.edges[startIdx] = null;
toDelete.end.edges[endIdx] = null;
// if(!isSolvable()){
// toDelete.start.edges[startIdx] = toDelete;
// toDelete.end.edges[endIdx] = toDelete;
// System.err.println("Invalid deletion!");
// return false;
// }
return true;
}
static class EdgeList{
List<Edge> edges;
public EdgeList(Edge... edges){
this.edges = new ArrayList<Edge>();
this.edges.addAll(Arrays.asList(edges));
}
}
static class Edge implements Comparable<Edge>{
Point start, end;
boolean walked;
public Edge(Point start, Point end){
walked = false;
this.start = start;
this.end = end;
this.start.edges[getStartIdx()] = this;
this.end.edges[getEndIdx()] = this;
if(start.compareTo(end)>0){
Point tmp = end;
end = start;
start = tmp;
}
}
public Edge(int x1, int y1, int x2, int y2){
this(new Point(x1,y1), new Point(x2,y2));
}
public boolean exists(){
return start.edges[getStartIdx()] != null || end.edges[getEndIdx()] != null;
}
public int getStartIdx(){
if(start.x == end.x){
if(start.y < end.y) return 0;
else return 2;
} else {
if(start.x < end.x) return 1;
else return 3;
}
}
public int getEndIdx(){
if(start.x == end.x){
if(start.y < end.y) return 2;
else return 0;
} else {
if(start.x < end.x) return 3;
else return 1;
}
}
public boolean isVertical(){
return start.x==end.x;
}
@Override
public int compareTo(Edge o) {
int result = start.compareTo(o.start);
if(result!=0) return result;
return end.compareTo(o.end);
}
}
static class Point implements Comparable<Point>{
int x,y;
Edge[] edges;
public Point(int x, int y){
this.x = x;
this.y = y;
edges = new Edge[4];
}
public Edge up(){ return edges[0]; }
public Edge right(){ return edges[1]; }
public Edge down(){ return edges[2]; }
public Edge left(){ return edges[3]; }
public int compareTo(Point o){
int result = Integer.compare(x, o.x);
if(result!=0) return result;
result = Integer.compare(y, o.y);
if(result!=0) return result;
return 0;
}
}
}