230,794.38 ในการวิ่ง 20x20, 100k
อัพเดทล่าสุด: ในที่สุดฉันก็สร้างโซลูชัน 2 เส้นทางแบบไดนามิกที่สมบูรณ์แบบ ฉันบอกว่าสมบูรณ์แบบเนื่องจากรุ่นก่อนหน้านี้ไม่ได้สมมาตรจริง ๆ แล้วมันจะง่ายกว่าหากจะใช้เส้นทางที่ยาวกว่าถ้าคนขี้เมาเดินไปอีกทางหนึ่ง ปัจจุบันมีความสมมาตรดังนั้นจึงสามารถมีจำนวนก้าวที่คาดหวังสูงขึ้น หลังจากการทดลองไม่กี่ครั้งดูเหมือนว่าจะอยู่ที่ประมาณ 230k ซึ่งเป็นการปรับปรุงที่ดีกว่ารุ่นก่อนหน้าซึ่งประมาณ 228k แต่สถิติที่พูดตัวเลขเหล่านั้นยังคงอยู่ในส่วนเบี่ยงเบนขนาดใหญ่ของพวกเขาดังนั้นฉันไม่ได้อ้างว่านี่เป็นสิ่งที่ดีกว่าอย่างมีนัยสำคัญ แต่ฉันเชื่อว่านี่ควรจะดีกว่ารุ่นก่อนหน้า
รหัสอยู่ที่ด้านล่างของโพสต์นี้ มีการปรับปรุงเพื่อให้เร็วกว่ารุ่นก่อนหน้ามากถึง 1,000 ครั้งใน 23 วินาที
ด้านล่างเป็นตัวอย่างการใช้งานและตัวอย่างเขาวงกต:
วอล์คเกอร์ที่สมบูรณ์แบบ
ค่าเฉลี่ย: 230794.384
สูงสุด: 1514506
นาที: 25860
สร้างเสร็จใน 2317.374 วินาที
_ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | | | _ _ _ _
| | | | | | | | | | | | | | | _ _ _ _ |
| | | | | | | | | | | | | | _ | | _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | | | | | | | | | _ _ _ _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | | | | | | | | | _ _ _ _ _ _ _
| | | | | | | | | | | | | _ _ _ _ _ _ |
| | | | | | _ | | _ | | _ | | _ | | _ _ _ _ _ _ _
| | | | | _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | | | | | _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ | | _ | | _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
การส่งก่อนหน้า
ในที่สุดฉันสามารถจับคู่ผลลัพธ์ของ Sparr! = D
จากการทดลองก่อนหน้าของฉัน (ดูที่ด้านล่างของโพสต์นี้) กลยุทธ์ที่ดีที่สุดคือการมีสองเส้นทางและปิดหนึ่งเมื่อเมาถึงใด ๆ ของพวกเขาและตัวแปรมาจากวิธีที่ดีที่เราสามารถทำนายแบบไดนามิกที่ขี้เมาจะไป เพิ่มโอกาสของเขาในการเข้าสู่เส้นทางอีกต่อไป
ดังนั้นตามDOUBLE_PATH
กลยุทธ์ของฉันฉันสร้างอีกอันหนึ่งซึ่งเปลี่ยนเขาวงกต ( DOUBLE_PATH
เขาวงกตของฉันสามารถแก้ไขได้อย่างง่ายดาย) ขึ้นอยู่กับการเคลื่อนไหวของขี้เมา ในขณะที่เขาใช้เส้นทางที่มีมากกว่าหนึ่งตัวเลือกที่มีอยู่ฉันจะปิดเส้นทางเพื่อให้เหลือเพียงสองตัวเลือกที่เป็นไปได้
เสียงนี้คล้ายกับสิ่งที่ Sparr ประสบความสำเร็จตามที่แสดง ความแตกต่างของเขาเล็กเกินไปที่จะถือว่าดีกว่า แต่ฉันจะบอกว่าวิธีการของฉันนั้นมีพลังมากกว่าเขาเนื่องจากเขาวงกตของฉันนั้นสามารถปรับเปลี่ยนได้มากกว่า Sparr's =)
ผลลัพธ์ที่ได้จากเขาวงกตสุดท้ายตัวอย่าง:
EXTREME_DOUBLE_PATH
ค่าเฉลี่ย: 228034.89
สูงสุด: 1050816
นาที: 34170
เสร็จสมบูรณ์ใน 396.728 วินาที
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
ส่วนการทดลอง
วิธีที่ดีที่สุดกลายเป็นกลยุทธ์เดียวกับความกระตือรือร้นฉันภูมิใจในการทดลองใช้กลยุทธ์ที่หลากหลายและพิมพ์ผลลัพธ์ที่ดี :)
เขาวงกตที่พิมพ์แต่ละอันด้านล่างนี้เป็นเขาวงกตสุดท้ายหลังจากที่คนเมาถึงบ้านแล้วดังนั้นพวกเขาอาจแตกต่างกันเล็กน้อยจากการวิ่งเพื่อวิ่งเนื่องจากการสุ่มในขบวนการมึนเมาและความผิดปรกติของฝ่ายตรงข้าม
ฉันจะอธิบายแต่ละกลยุทธ์:
เส้นทางเดียว
นี่เป็นวิธีที่ง่ายที่สุดซึ่งจะสร้างเส้นทางเดียวจากรายการไปยังทางออก
SINGLE_PATH
ค่าเฉลี่ย: 162621.612
สูงสุด: 956694
นาที: 14838
สร้างเสร็จใน 149.430 วิ
_ _ _ _ _ _ _ _ _ _ _
| | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
เกาะ (ระดับ 0)
นี่เป็นวิธีการที่พยายามดักจับขี้เมาในเกาะที่อยู่โดดเดี่ยว ใช้งานไม่ได้ดีอย่างที่ฉันคาดไว้ แต่นี่เป็นหนึ่งในแนวคิดแรกของฉันดังนั้นฉันจึงรวมไว้
มีสองเส้นทางที่นำไปสู่ทางออกและเมื่อมึนเมาเข้ามาใกล้หนึ่งในนั้นฝ่ายตรงข้ามก็ปิดมันบังคับให้เขาหาทางออกอื่น (และอาจติดกับดักอีกครั้งในเกาะ)
เกาะ
เฉลี่ย: 74626.070
สูงสุด: 428560
ต่ำสุด: 1528
สร้างเสร็จใน 122.512 วิ
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
เส้นทางคู่
นี่คือกลยุทธ์ที่ถูกกล่าวถึงมากที่สุดซึ่งมีสองเส้นทางที่มีความยาวเท่ากันจนถึงทางออก
DOUBLE_PATH
ค่าเฉลี่ย: 197743.472
สูงสุด: 1443406
นาที: 21516
แล้วเสร็จใน 308.177 วิ
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
_ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
เกาะ (ระดับ 1)
แรงบันดาลใจจากหลายเส้นทางของเกาะและการเดินสูงนับในเส้นทางเดียวเราเชื่อมต่อเกาะกับทางออกและทำให้เขาวงกตเส้นทางเดียวในเกาะสร้างในสามเส้นทางทั้งหมดที่จะออกและคล้ายกับกรณีก่อนหน้าปิดใด ๆ ทางออกเมื่อขี้เมาเข้ามาใกล้
วิธีนี้ใช้งานได้ดีกว่าเส้นทางเดียวที่บริสุทธิ์เล็กน้อย แต่ก็ยังไม่สามารถเอาชนะเส้นทางคู่ได้
เกาะ
เฉลี่ย: 166265.132
สูงสุด: 1162966
นาที: 19544
สร้างเสร็จใน 471.982 วิ
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ | _
| | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ |
เกาะ (ระดับ 2)
พยายามที่จะขยายแนวคิดก่อนหน้านี้ฉันสร้างเกาะซ้อนกันสร้างในเส้นทางทั้งหมดห้าเส้นทาง แต่ดูเหมือนว่าจะไม่ได้ผล
เกาะ
เฉลี่ย: 164222.712
สูงสุด: 927608
นาที: 22024
สร้างเสร็จใน 793.591s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ | _ |
| | | | _ | | _ | | _ | | _ | | _ | | _ | | _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| _ | _ | _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
เกาะ (ระดับ 3)
สังเกตว่าเส้นทางคู่นั้นใช้งานได้ดีกว่าเส้นทางเดียวเรามาทำให้เกาะเป็นสองเท่ากัน!
ผลที่ได้คือการปรับปรุงบนเกาะ (ระดับ 1) แต่ก็ยังไม่ชนะคู่ที่บริสุทธิ์
สำหรับการเปรียบเทียบผลลัพธ์สำหรับเส้นทางคู่ของขนาดของเกาะคือ 131,134.42 เคลื่อนที่โดยเฉลี่ย ดังนั้นนี่เป็นการเพิ่มจำนวนการเคลื่อนไหวที่สำคัญ (ประมาณ 40k) แต่ไม่เพียงพอที่จะเอาชนะสองทาง
เกาะ
ค่าเฉลี่ย: 171730.090
สูงสุด: 769080
นาที: 29760
สร้างเสร็จใน 587.646 วินาที
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ |
เกาะ (ระดับ 4)
อีกครั้งทดลองกับเกาะที่ซ้อนกันและอีกครั้งมันทำงานได้ไม่ดีนัก
เกาะ
ค่าเฉลี่ย: 149723.068
สูงสุด: 622106
นาที: 25752
แล้วเสร็จใน 830.889s
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _ |
| | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _ |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | | _ _ _ _ _ _ _ _ _ _ _ _ _ | | |
| | _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ | |
| | _ | _ _ _ _ _ _ _ _ _ _ _ _ | | |
| _ | _ _ _ _ _ _ _ _ _ _ _ _ _ | |
| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
ข้อสรุป
ทั้งหมดนี้พิสูจน์ได้ว่าการมีเส้นทางยาวเดียวจากตำแหน่งปัจจุบันของเมาเหล้าไปจนถึงทางออกดีที่สุดซึ่งทำได้โดยกลยุทธ์สองทางเนื่องจากหลังจากปิดทางออกแล้วคนเมาจะต้องเดินทางในระยะทางสูงสุดเท่าที่จะเป็นไปได้ ทางออก
นี่เป็นการบอกเป็นนัยเพิ่มเติมว่ากลยุทธ์พื้นฐานควรยังคงเป็นเส้นทางคู่และเราสามารถปรับเปลี่ยนได้เพียงวิธีการสร้างเส้นทางแบบไดนามิกซึ่งทำโดย Sparr ดังนั้นฉันเชื่อว่ากลยุทธ์ของเขาเป็นวิธีที่จะไป!
รหัส
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;
}
}
}