2015-11-21 3 views
4

Итак, я создаю приложение для лабиринта (я читаю из массива строк в лабиринте, а после этого с сенсорными событиями направляет мяч через него). Удалось создать все до сих пор, приложение работает отлично. Но я хочу включить опцию для ее решения автоматически.Автоматическое решение лабиринта

Я использую этот рекурсивный алгоритм найден здесь: https://en.wikipedia.org/wiki/Maze_solving_algorithm

В основном я получаю путь в булевом многомерном массиве (то есть размер лабиринта).

Пытался достичь MWC, как дизайн, так что у меня есть следующие классы:

LabyrinthView - ручки все, что связанно с рисованием лабиринта, и рисования мяча LabyrinthModel - инициализировать лабиринт, ручки движения мяча, и я проверьте здесь конец лабиринта и реализовали рекурсивную серию здесь, чтобы LabyrinthActivity - вот где я собираю все вместе

Как я уже говорил, решение лабиринта вручную работает как шарм. Не знаю, как анимировать автоматическое решение. Итак, позвольте мне дать вам лабиринте пример:

<string-array name="labyrinthEasy"> 
    <item>0000000001</item> 
    <item>0111110110</item> 
    <item>0100000110</item> 
    <item>0101111000</item> 
    <item>0101000010</item> 
    <item>0101011010</item> 
    <item>0101011110</item> 
    <item>0101000010</item> 
    <item>0101111010</item> 
    <item>0100000010</item> 
    <item>0111111110</item> 
    <item>1000000000</item> 
</string-array> 

Это будет выглядеть примерно так (E-Entry, F-финиш):

enter image description here

И решение:

enter image description here

Вот как далеко я добрался:

private void selectControlMode() { 
    final CharSequence[] items = {"Human","Machine"}; 
    final AlertDialog.Builder alertDialog = new AlertDialog.Builder(this); 
    alertDialog.setItems(items, new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      switch (which) { 
       case 0: 
        dialog.dismiss(); 
        break; 
       case 1: 
        dialog.dismiss(); 
        boolean temp; 
        temp = labyrinthModel.solveMaze(); 
        if(temp){ 
         new MazeSolver().execute(); 
        }else{ 
         AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext()); 
         builder.setMessage("The maze is unsolvable!"); 
         builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { 
          @Override 
          public void onClick(DialogInterface dialog, int which) { 
           switch (which) { 
            case 0: 
             dialog.dismiss(); 
             Intent intent1 = new Intent(LabyrinthActivity.this, MainActivity.class); 
             intent1.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
             startActivity(intent1); 
             break; 
           } 
          } 
         }); 
         AlertDialog alert = builder.create(); 
         alert.show(); 
        } 
        break; 
      } 
     } 
    }); 

} 

В основном я выбираю между человеческим и машинным решением из диалога. Если выбран человек, выберите диалог и ничего (приложение продолжает и ждет ручного решения). Если машина выбрана, я получаю путь, и если она может быть решена, я думаю, что я должен начать новую тему здесь, где я могу анимировать автоматическое решение, иначе, если ее не решить, я вернусь в главное меню приложения. Теперь здесь возникает моя проблема, так как я действительно не знаю, как реализовать это в моем классе AsyncTask.

Я делаю логику в методе doInBackgroung, но не могу понять логику, как следовать правильному пути. Потому что, если я повторяю по массиву по строкам, шарик перескакивает из строки в строку и не будет следовать текучести пути. Также я думаю, что после каждой итерации я должен перерисовать свой прогресс, используя метод onProgressUpdate.

Это как моя ручная логика работы (движение и рисунок):

labyrinthView.setOnTouchListener(new View.OnTouchListener() { 
     float x1 = 0, x2 = 0, y1 = 0, y2 = 0; 
     float dx, dy; 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      float MIN_DIST = 5; 
      switch (event.getAction()){ 
       case (MotionEvent.ACTION_DOWN): 
        x1 = event.getX(); 
        y1 = event.getY(); 
        break; 
       case (MotionEvent.ACTION_UP): 
        x2 = event.getX(); 
        y2 = event.getY(); 
        dx = x2-x1; 
        dy = y2-y1; 
        Log.v("log", dx + " " + dy); 
        if(Math.abs(dx) > MIN_DIST || Math.abs(dy) > MIN_DIST){ 
         if (Math.abs(dx) > Math.abs(dy)){ 
          if(dx > 0) { 
           labyrinthModel.right(); 
           finishMessage(); 
          } 
          else { 
           labyrinthModel.left(); 
           finishMessage(); 
          } 
         }else{ 
          if(dy > 0) { 
           labyrinthModel.down(); 
           finishMessage(); 
          } 
          else { 
           labyrinthModel.up(); 
           finishMessage(); 
          } 
         } 
        } 
        break; 
      } 
      labyrinthView.invalidate(); 
      return true; 
     } 


    }); 

И это то, что я сделал до сих пор в моей assync задачи:

private class MazeSolver extends AsyncTask<Void,Void,Void>{ 
    @Override 
    protected Void doInBackground(Void... params) { 
     for (int row = 0; row < labyrinthModel.correctPath.length; row ++) 
      for (int col = 0; col < labyrinthModel.correctPath[0].length; col++){ 
       if(labyrinthModel.correctPath[row][col + 1]){ 
        labyrinthModel.moveRight(); 
       } 
//here to do the implementaion of the path following logic??? 

      } 
     return null; 
    } 

    @Override 
    protected void onProgressUpdate(Void... values) { 
// here to redraw the progress ???? 
     super.onProgressUpdate(values); 
    } 

    @Override 
    protected void onPostExecute(Void aVoid) { 
     super.onPostExecute(aVoid); 
    } 
} 

Если вы можете указать мне в правильном направлении я был бы очень благодарен.

ответ

3

Учитывая, что вам разрешено перезаписывать путь сигнализации двухмерного массива вы просто должны следовать корень от начала до конца:

travel(correctPath, 0, 0, 11, 8); 

void travel(bool a[][], int row, int col, int finalRow, int finalCol) { 
    // if we are already there stop 
    if(finalRow == row && col == finalCol) return; 

    // avoid comming back 
    a[row][col]=false; 

    // if the input is correct only on of this moves will be valid 
    // try each of them and see which move we can make 
    if(col - 1 >= 0 && a[row][col-1]) { left(); travel(a, row, col-1, finalRow, finalCol)}; 
    if(col + 1 < 8 && a[row][col+1]) { right(); travel(a, row,col+1, finalRow, finalCol)}; 
    if(row - 1 >= 0 && a[row-1][col]) { up(); travel(a, row-1, col, finalRow, finalCol)}; 
    if(row + 1 < 11 && a[row+1][col]) { down(); travel(a, row+1,col, finalRow, finalCol)}; 
} 
Смежные вопросы