Berhasil menavigasi bidang asteroid

36

pengantar

Semua orang tahu bahwa kemungkinan berhasil menavigasi bidang asteroid adalah sekitar 3.720 hingga 1. Tetapi meskipun Anda memperingatkan, Han Solo masih bersedia untuk mencoba peruntungannya.

Takut untuk kehidupan buatan Anda, Anda memutuskan untuk membuat kode, dalam dialek khusus kapal ( baca: bahasa Golf Kode pilihan Anda ), program penghindaran asteroid yang akan memutuskan jalur mana yang akan diambil dalam labirin ASCII bidang asteroid.

Memasukkan

Millenium Falcon memiliki program pemetaan lapangan asteroid, yang memberikan data serupa dengan ini:

|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #        |
@              ##    ####       
|#   #   #       ###   ##      |
|##      ##      ####   #  #   |
|####           ##### #   ##   |

Baris atas adalah kiri dari Falcon, baris bawah adalah kanan dari Falcon, dan kolom mewakili apa yang ada di depan kapal.

  • Masing #- masing adalah hambatan.
  • Setiap ruang adalah ruang kosong tempat kapal dapat terbang.
  • Input selalu tinggi 7 karakter. Ini adalah batas lebar pemetaan asteroid.
  • Input selalu panjang 32 karakter (30 untuk bidang itu sendiri dan 2 untuk batas awal dan akhir). Ini adalah batas kedalaman pemetaan asteroid. Bilah vertikal |menandai awal dan akhir pemetaan.
  • @adalah Falcon. Itu selalu di baris tengah (baris 4) dan kolom pertama di input.
  • Ruang yang tersisa di bilah vertikal pada kolom terakhir adalah tempat kapal harus tiba. Itu selalu di baris tengah (baris ke-4) dan kolom terakhir di input.

Input dapat diambil sebagai string multi-line, array string, dari STDIN atau parameter fungsi, atau dibaca dari file.

Kemungkinan manuver

Anda dikejar oleh TIE-Fighters, oleh karena itu Anda harus selalu maju. Dengan demikian ada tiga cara kapal dapat terbang di setiap langkah:

  • - Meneruskan

  • / Maju dan belok kiri

  • \ Maju dan belok kanan

Misalnya, ini adalah jalur yang valid:

@---

  --
 /  \ /
@    -

   -
  / \
 /   \
@     \

Seperti yang Anda lihat, selalu ada tepat satu gerakan per kolom. Falcon adalah sepotong sampah, oleh karena itu ia tidak dapat melakukan pergantian yang keras. Yang berarti bergerak seperti /\atau \/tidak diizinkan . Harus ada minimal satu penyerang murni di -antara dua belokan yang berlawanan. Di sisi lain, memutar satu cara untuk beberapa langkah berturut-turut dimungkinkan, seperti yang terlihat di atas.

Falcon terhempas jika satu gerakan menuntun kapal berada di tempat di mana hambatan terjadi. Misalnya, gerakan ini menyebabkan crash:

@-#

@
 \
  #

  #
 /
@

Perhatikan bahwa ini bukan kerusakan:

@-#
  \
   -

Keluaran

Anda harus menampilkan bidang asteroid yang sama ASCII, dengan jalur yang valid hingga akhir. Falcon harus dicetak di titik akhir dan bukan di titik awal.

Misalnya, output yang valid untuk contoh input yang diberikan sebelumnya adalah:

|   #####           #########  |
| ######  #--------  ###   #   |
|   # #  #/ #  ####\  #        |
 ---------      ##  \ #### ----@
|#   #   #       ### \ ## /    |
|##      ##      #### \ #/ #   |
|####           ##### #-- ##   |

Jalur Anda hanya perlu tidak menabrak elang. Itu tidak perlu menjadi jalan terpendek yang mungkin.

Anda dapat mengasumsikan bahwa akan selalu ada setidaknya satu jalan yang mungkin sampai akhir.

Anda dapat menampilkan ke STDOUT, dalam file atau apa pun yang setara asalkan bidang asteroid dicetak persis seperti yang ada di pos ini (mis., Mengeluarkan daftar koordinat untuk jalur tidak valid).

Uji kasus

  • Bidang asteroid normal

    |   #####           #########  |
    | ######  #          ###   #   |
    |   # #  #  #  ####   #        |
    @              ##    ####       
    |#   #   #       ###   ##      |
    |##      ##      ####   #  #   |
    |####           ##### #   ##   |
    

    Output yang mungkin

    |   #####           #########  |
    | ######  #--------  ###   #   |
    |   # #  #/ #  ####\  #        |
     ---------      ##  \ #### ----@
    |#   #   #       ### \ ## /    |
    |##      ##      #### \ #/ #   |
    |####           ##### #-- ##   |
    
  • Bidang asteroid yang tidak teratur

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    @ # # # # # # # # # # # # # #   
    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    

    Output yang mungkin

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
     -# #-# #-# #-# #-# #-# #-# #--@
    |#\#/#\#/#\#/#\#/#\#/#\#/#\#/# |
    | #-# #-# #-# #-# #-# #-# #-# #|
    |# # # # # # # # # # # # # # # |
    
  • Inti bintang kematian

    |    #    #    #         #     |
    |         #    #    #          |
    |    #    #    #    #    #     |
    @    #    #    #    #    #      
    |    #    #         #    #     |
    |    #    #    #    #    #     |
    |    #         #    #    #     |
    

    Output yang mungkin

    |    #    #    #   --    #     |
    |  ---    #    #  / #\   -     |
    | /  #\   #    # /  # \ /#\    |
     -   # \  #    #/   #  - # ----@
    |    #  \ # ----    #    #     |
    |    #   \#/   #    #    #     |
    |    #    -    #    #    #     |
    
  • Parit bintang kematian

    |##############################|
    |##############################|
    |##############################|
    @                               
    |##############################|
    |##############################|
    |##############################|
    

    Keluaran

    |##############################|
    |##############################|
    |##############################|
     ------------------------------@
    |##############################|
    |##############################|
    |##############################|
    
  • Gua asteroid

    |### ##########################|
    |## # ############### ## ######|
    |# ###  ######## ### ## # #####|
    @ ###### ###### ### ## ###      
    |########  ### ### ## #########|
    |########## # ### ## ##########|
    |###########              #####|
    

    Output yang mungkin

    |###-##########################|
    |##/#\############### ##-######|
    |#/###--######## ### ##/#\#####|
     -######\###### ### ##/###-----@
    |########--### ### ##/#########|
    |##########\# ### ##/##########|
    |###########--------      #####|
    

Mencetak gol

R2D2 sibuk berenang di rawa-rawa, jadi Anda harus memprogram pengontrol Falcon sendiri, yang membosankan. Karenanya kode terpendek menang .

Fatalisasi
sumber
@DJMcMayhem: Secara teknis baris pertama adalah "Pendahuluan";)
Alex A.
2
Saya semacam mendapatkan bagaimana seharusnya terlihat berdasarkan contoh, tetapi pengkodean langkah masih agak membingungkan bagi saya. Jika Anda melihat misalnya pada contoh "hyperregular", kecuali untuk langkah pertama / terakhir, Anda selalu bergerak diagonal. Namun ia ada -di jalur di setiap belokan, yang didefinisikan sebagai gerakan "maju". Tapi gerakan sebenarnya selalu dua diagonal-kiri diikuti oleh dua diagonal-kanan.
Reto Koradi
@RetoKoradi Saya bisa mengerti bahwa itu tidak terlalu jelas tetapi ide dasarnya adalah bahwa semua gerakan membuat Anda melakukan perjalanan lebar karakter ke kanan. Path harus terlihat kontinu, itulah mengapa gerakan sebelumnya / berikutnya setelah belokan kanan dan kiri adalah satu baris di atas / di bawah yang sebelumnya.
Fatalkan
@apsillers Keduanya valid, jika saya mengerti Anda dengan benar, jawaban Anda pasti bagus
Fatalize

Jawaban:

11

JavaScript (ES6), 186 201

f=([...s])=>(g=(i,l,c=k=" ")=>s[i]!=k&&s[i]!="@"?0:(i-130)?(s[i]=c,([..."/-\\"].some((c,j)=>!((--j&l&&j!=l)||!g(i+33*(l||j)+1,j,c)))||!(s[i]=k))):(s[i]="@",!console.log(s.join(""))))(99)

Cuplikan yang dapat dijalankan:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><textarea cols="33" rows="7" id="t"></textarea><br><button><b>Solve &gt;&gt;&gt;</b></button><hr><button id="1">Normal</button> <button id="2">Hyperregular</button> <button id="3">Death Star core</button> <button id="4">Death Star trench</button> <button id="5">Asteroid cave</button><script>f=(function($__0){var $__2,$__3,$__4,$__5;s = $__4 = $__0.split("");return (g = (function(i, l) {var c = arguments[2] !== (void 0) ? arguments[2] : k = " ";return s[i] != k && s[i] != "@" ? 0 : (i - 130) ? (s[i] = c, ("/-\\".split("").some((function(c, j) {return !((--j & l && j != l) || !g(i + 33 * (l || j) + 1, j, c));})) || !(s[i] = k))) : (s[i] = "@",$("#t").val(s.join("")));}))(99);});$("button").click(function() {this.id?$("#t").val(inputs[this.id]):f($("#t").val());});inputs = [,`|   #####           #########  |\n| ######  #          ###   #   |\n|   # #  #  #  ####   #        |\n@              ##    ####       \n|#   #   #       ###   ##      |\n|##      ##      ####   #  #   |\n|####           ##### #   ##   |`,`|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |\n@ # # # # # # # # # # # # # #   \n|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |`,`|    #    #    #         #     |\n|         #    #    #          |\n|    #    #    #    #    #     |\n@    #    #    #    #    #      \n|    #    #         #    #     |\n|    #    #    #    #    #     |\n|    #         #    #    #     |`,`|##############################|\n|##############################|\n|##############################|\n@                               \n|##############################|\n|##############################|\n|##############################|`,`|### ##########################|\n|## # ############### ## ######|\n|# ###  ######## ### ## # #####|\n@ ###### ###### ### ## ###      \n|########  ### ### ## #########|\n|########## # ### ## ##########|\n|###########              #####|`];$("#t").val(inputs[1]);</script

Fungsi ini menerima string tunggal dengan baris baru. Fungsi ini membagi string menjadi array menggunakan ...operator dan mendapatkan indeks untuk (x,y)koordinat dengan (33 * y) + x.

Fungsi ini berjalan secara rekursif, menguji kemungkinan gerakan yang berbeda untuk setiap ruang. Ketika menemui kendala, ia mengembalikan nilai palsu, dan ketika mencapai ruang tujuan akhir, ia kembali true. (Dalam kode golf, ini truedibuat oleh !console.log(...).)

Perhatikan bahwa kode ini tidak menggunakan jangka panjang dari gerakan belok kanan, tetapi belokkan dengan gerakan lurus. Artinya, ia melakukan opsi kedua di bawah, bukan yang pertama:

\                       \
 \   (<= not this!)      -   (<= yes this!)
  \                       \

Ini tampaknya legal, karena -bisa secara hukum datang sebelum atau setelah belokan, jadi mengapa tidak keduanya sekaligus? Itu terlihat sangat aneh di akhir, ketika langkah terakhir \tetapi ditampilkan sebagai @:

|  --#    #    #   ------#  -  |
| /  \    #    #  / #    \ / \ |
|/   #-   #    # /  #    #-   -|
     # \  #    #/   #    #     @
|    #  - # ----    #    #     |
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

Retas golf nasty favorit saya di sini adalah penyalahgunaan argumen default c=k=" ". Argumen (i,l,c=" ")akan mengatakan "gunakan string " "untuk cjika ftidak disediakan argumen ketiga". Namun, dengan melakukan c=k=" ", kita mengatakan "jika ctidak disediakan, simpan " "dalam variabel global kdan kemudian simpan nilai itu cjuga". Karena rekursi dimulai dengan hanya satu argumen, kselalu diinisialisasi pada pemanggilan fungsi pertama.

Tanpa ungolfed:

// `i` - index in the string we're working on
// `l` - move character for this space (`/`, `\`, or `-`)
search = (i,l,c)=>{

  // not an open space; nip this recursive branch
  if(s[i]!=" "&&s[i]!="@") { return 0; }

  // we made it! the 130th space is (31,3)
  if(i==130) {
      s[i]="@";
      console.log(s.join(""));
      return true;
  }

  // fill in space with move character or a blank
  // (the space is only to blank out the initial `@`)
  s[i] = c || " ";

  // iterate through the 3 options and recursively explore the map
  return ['/','-','\\'].some((c,j)=>{
    --j;
    // if last move was sideways, and this is the opposite move, skip it
    if(l && j && j!=l) { return 0; }

    // recursively call search function on space pointed to by this move or the last move
    return search(i+33*(l||j)+1, j, c);
  })

  // if the `some` call is false (i.e. all options fail for this space)
  // then blank out this space and return false
  || !(s[i]=" ");

}
apsillers
sumber
@ vihan1086 Benar, saya benar-benar merindukan ruang-ruang itu ketika bermain golf. D: Dan beralih dari array ke string split adalah perubahan yang menyenangkan juga. Terima kasih. :) Saya juga telah membuat beberapa perubahan lain (menjadikan karakter gerakan saat ini sebagai argumen ketiga alih-alih ditentukan dalam fungsi, dan menyimpan " "dalam variabel) yang membuat skor saya turun lebih rendah.
apsillers
7

C (program lengkap), 249 247 235 byte

Ini adalah program lengkap yang membaca input dari file dan mengeluarkan hasilnya ke stdout. Nama file dilewatkan sebagai parameter ke program.

char f[7][33];g(i,j,c){return(i<0|i>6|f[i][j]%32?0:j<31?c%45-2?g(i,j+1,c)||g(i+1,j+1,92)||g(i-1,j+1,47):g(i+c/30-2,j+1,c)||g(i+c/30-2,j+1,45):1)?f[i][j]=j?j-31?c:64:32:0;}main(int p,char**v){read(open(v[1],0),f,231);g(3,0,45);puts(f);}

Tidak Disatukan:

/* the field */
char f[7][33];

/* i - row
 * j - col
 * c - movement
 */
g(i,j,c)
{
    return
            /* if we're in bounds and not on an obstacle */
            (i >= 0 & i<7 & f[i][j] % 32 == 0 ?
                    /* if we haven't reached the end */
                    j < 31 ?
                            /* are we going straight ahead? */
                            c%45-2 ?
                                    /* try to go straight */
                                    g(i,j+1,c)
                                    /* try to turn right */
                                    || g(i+1,j+1,92)
                                    /* try to turn left */
                                    || g(i-1,j+1,47)
                            /* turning */
                            :
                                    /* try to keep turning */
                                    g(i+c/30-2,j+1,c)
                                    /* try to go straight */
                                    || g(i+c/30-2,j+1,45)
                    /* done */
                    :1 /* replace this with c==45 to better represent the last move being a turn */
            /* invalid move, fail */
            :0)
            /* add the correct movement to the field */
            ? f[i][j] = j ? j - 31 ? c : 64 : 32
            /* no path, much sads :( */
            :0;
}

main(int p,char*v[])
{
    /* read input file */
    read(open(v[1],0),f,231);

    /* calculate the path */
    g(3,0,45);

    /* print it out */
    puts(f);
}

Keluaran:

$ ./a.out test.inp
|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #      --|
 ------------- ##----####   /  @
|#   #   #    \ /### \ ##  /   |
|##      ##    - #### \ # /#   |
|####           ##### #---##   |

$ ./a.out test2.inp
|# # # # #-# # # # # #-# # # # |
| # # # #/#\# # # # #/#\# # # #|
|# # # #/# #\# # # #/# #\# # # |
 -# # #/# # #\# # #/# # #\# #  @
|#\# #/# # # #\# #/# # # #\# #/|
| #\#/# # # # #\#/# # # # #\#/#|
|# #-# # # # # #-# # # # # #-# |

$ ./a.out test3.inp
|    #    #    #   ------#     |
|    -    #    #  / #    \     |
|   /#\   #    # /  #    #\    |
 --- # \  #    #/   #    # \   @
|    #  \ #    /    #    #  \ /|
|    #   \#   /#    #    #   - |
|    #    ---- #    #    #     |

$ ./a.out test4.inp
|##############################|
|##############################|
|##############################|
 ------------------------------@
|##############################|
|##############################|
|##############################|

$ ./a.out test5.inp
|###-##########################|
|##/#\############### ##-######|
|#/###--######## ### ##/#\#####|
 -######\###### ### ##/###-----@
|########--### ### ##/#########|
|##########\# ### ##/##########|
|###########--------      #####|
Cole Cameron
sumber
Sepertinya Anda melewatkan titik akhir pada tes pertama.
Reto Koradi
@RetoKoradi Ini -diikuti oleh \, tetapi \ditutup oleh @. (Program saya melakukan hal yang sama.)
apsillers
1
@RetoKoradi Iterasi sebelumnya menangani kasus ini dengan lebih baik. Ini +4 byte. Saya perhatikan solusi apsillers berperilaku sama sehingga saya memilih untuk menghemat tempat.
Cole Cameron
Saya melihat. Itu tidak terlihat benar bagi saya, tetapi terserah OP untuk memutuskan apa yang diizinkan. Saya melihat bahwa mereka memberikan kebebasan tentang bagaimana gerakan diwakili. Saya ingin melihat definisi yang jelas dan unik dari awal. Itu tampak seperti masalah yang menyenangkan, tapi itu tidak menarik dengan ambiguitas.
Reto Koradi
3

Common Lisp, 303 byte

Bersenang-senang dengan tantangan ini, ini adalah tugas codegolf pertama yang saya lakukan. Pada dasarnya ada fungsi rekursif sederhana yang mencoba setiap gerakan yang layak sampai posisi akhir tercapai.

Golf / Diminimalkan

(let((s(open "i"))(n nil)(f(make-string 231)))(read-sequence f s)(labels((r(p s u d)(and(< 0 p 224)(find(aref f p)" @")(setf(aref f p)(cond((= 130 p)#\@)((or(unless d(r(- p 32)#\/ t n))(unless u(r(+ p 34)#\\ n t))(r(+ p(cond(u -32)(d 34)(t 1)))#\- n n))s)((return-from r)))))))(r 99 #\- n n)(princ f)))

Membaca input dari file i di direktori kerja. Saya cukup yakin masih ada ruang untuk perbaikan.

Kode polos

(defun run-test (file)
  (let ((stream (open file)) ;;should use with-open-file for autoclose..
        (no nil) ;; alias for brevity
        (field (make-string 231)))
    (read-sequence field stream)
    (labels ((doit (pos sym going-up going-down)
               (and
                 (< 0 pos 224)
                 (find (aref field pos) " @")
                 (setf (aref field pos)
                       (cond
                         ((= 130 pos) #\@)
                         ((or
                            (unless going-down (doit (- pos 32) #\/ t no))
                            (unless going-up (doit (+ pos 34) #\\ no t))
                            (doit (+ pos (cond (going-up -32)
                                               (going-down 34)
                                               (t 1)))
                                  #\- no no))
                          sym)
                         ((return-from doit)))))))
      (doit 99 #\- no no)
      (princ field)
      nil)))

Output sampel

|   #####       --  #########  |
| ######  #    /  \  ###   # - |
|   # #  #  # /####\  #     / \|
--   -       / ##   \####  /   @
|#\ /#\  #  /    ### \ ## /    |
|##-   \ ##/     #### \ #/ #   |
|####   ---     ##### #-- ##   |

|  --#    #    #   --    #-    |
| /  \    #    #  / #\   / \   |
|/   #\   #    # /  # \ /#  \  |
-    # \  #    #/   #  - #   \ @
|    #  \ # ----    #    #    -|
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

|# #-# # # # # #-# # # # # #-# |
| #/#\# # # # #/#\# # # # #/#\#|
|#/# #\# # # #/# #\# # # #/# #\|
--# # #\# # #/# # #\# # #/# #  @
|# # # #\# #/# # # #\# #/# # # |
| # # # #\#/# # # # #\#/# # # #|
|# # # # #-# # # # # #-# # # # |
Florian Patzl
sumber
2

ActionScript 3, 364 byte

Saya membagi ini menjadi dua fungsi; satu untuk mengubah array menjadi array array, dan satu array rekursif untuk menghitung jalur penerbangan.

function m(f){for(var i=0;i<f.length;i++){f[i]=f[i].split("");}n(f,0,3,0);return f;}function n(f,x,y,m){var P=f[y][x],X=x+1,A=y-1,B=y,C=y+1,T=true,F=false,E='-';if (y<0||y>6||P=='#'||P=='|')return F;if (x==31){f[y][x]='@';return T;}if(m<0&&y>0){B=A;C=9;E='/';}else if(m>0&&y<6){A=9;B=C;E='\\';}if (n(f,X,B,0)||n(f,X,A,-1)||n(f,X,C,1)){f[y][x]=E;return T;return F;}

Versi ungolfed dalam suatu program dengan satu bidang sampel asteroid ditentukan:

package
{
    import flash.display.Sprite;

    public class AsteroidNavigator extends Sprite
    {
        var field:Array;
        public function AsteroidNavigator()
        {
            field = [
"|   #####           #########  |",
"| ######  #          ###   #   |",
"|   # #  #  #  ####   #        |",
"@              ##    ####       ",
"|#   #   #       ###   ##      |",
"|##      ##      ####   #  #   |",
"|####           ##### #   ##   |"];
            m(field);
            printField();
        }

        function m(f){
            for(var i=0;i<f.length;i++){
                f[i]=f[i].split("");\
            }
            n(f,0,3,0);
            return f;
        }

        private function n(field,x,y,m) {
            var C = field[y][x];
            if (x > 31 || C == '#' || C == '|') {
                return false;
            }
            if (x == 31 && y == 3) {
                field[y][x] = '@';
                return true;
            }
            if (m == 0) {
                if (n(x+1, y, 0) || ((y>0) && n(x+1, y-1, -1)) || ((y<6) && n(x+1, y+1, 1))) {
                field[y][x] = '-';
                return true;
                }
            } else if ((m<0) && (y>0)) {
                if ((n(x+1, y-1, -1) || n(x+1, y-1, 0))) {
                    field[y][x] = '/';
                    return true;
                }
            } else if ((m>0) && (y<6)) {
                if ((n(x+1, y+1, 1) || n(x+1, y+1, 0))) {
                    field[y][x] = '\\';
                    return true;
                }
            }
            return false;
        }

        private function printField() {
            var sb = "";
            for each (var row:Array in field) {
                sb += row.join("") + "\n";
            }
            trace(sb);
        }
    }
}
Brian
sumber