Asteroid alanında başarılı bir şekilde gezinme


36

Giriş

Herkes başarılı bir şekilde bir asteroit alanında gezinme olasılığının yaklaşık 3,720 ila 1 olduğunu biliyor. Ancak uyarınıza rağmen, Han Solo hala şansını denemek istiyor.

Yapay hayatınız için endişe duyduğunuzda, geminin kendine özgü lehçesinde ( okuma: tercih ettiğiniz Code Golf dili ), ASCII labirentinde bir asteroid alanında hangi yolu seçeceğinize karar verecek bir asteroid kaçınma programı kodlamaya karar verdiniz .

Giriş

Millenium Falcon'da buna benzer veriler sağlayan bir asteroid alan haritalama programı var:

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

Üst sıralar Falcon'dan ayrılmıştır, alt sıralar Falcon'un sağındadır ve sütunlar geminin önünde olanı temsil eder.

  • Her #biri bir engeldir.
  • Her alan, geminin uçabileceği boş alandır.
  • Giriş her zaman 7 karakter yüksekliğindedir. Bu asteroit haritalama genişliği sınırıdır.
  • Giriş daima 32 karakter uzunluğundadır (alanın kendisi için 30 ve başlangıç ​​ve bitiş sınırları için 2'dir). Bu asteroit haritalama derinliği sınırıdır. Dikey çubuklar |, eşlemenin başlangıcını ve sonunu işaretler.
  • @Şahin. Her zaman orta satırda (4. satır) ve girişteki ilk sütundadır.
  • Son sütundaki dikey çubuklarda kalan boşluk, geminin ulaşması gereken yerdir. Her zaman orta satırda (4. satır) ve girişteki son sütundadır.

Giriş, çok satırlı bir dize, bir dizi dizisi, STDIN'den veya bir işlev parametresinden alınabilir veya bir dosyadan okunabilir.

Muhtemel manevralar

TIE-Fighters tarafından takip ediliyorsunuz, bu yüzden daima ilerlemelisiniz. Bu nedenle, geminin her adımda uçabileceği üç yol vardır:

  • - ileri

  • / İleri ve sola dön

  • \ İleri ve sağa dön

Örneğin, bunlar geçerli yollardır:

@---

  --
 /  \ /
@    -

   -
  / \
 /   \
@     \

Gördüğünüz gibi, sütun başına her zaman tam olarak bir hareket var. Falcon bir hurda parçası, bu yüzden şiddetli dönüş yapamaz. Gibi hangi araçlar hamle /\veya \/edilir izin . -İki zıt dönüş arasında en az bir tane saf ileri olmalı . Öte yandan, yukarıda görüldüğü gibi, art arda birden fazla adım için bir yol açmak mümkündür.

Bir hamle gemiyi engelin olduğu bir noktada olmaya yönlendirirse Falcon çöker. Örneğin, bu hareketler çökmelere yol açar:

@-#

@
 \
  #

  #
 /
@

Bunun bir çökme olmadığını unutmayın:

@-#
  \
   -

Çıktı

Aynı asteroid alanını ASCII olarak, sonuna kadar geçerli bir yolla çıkarmalısınız. Falcon, başlangıç ​​noktası yerine bitiş noktasına yazdırılmalıdır.

Örneğin, daha önce verilen giriş örneği için geçerli bir çıktı şöyle olacaktır:

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

Yolunun sadece şahinle çarpışmaması gerekiyor. Mümkün olan en kısa yol olması gerekmez.

Sonuna kadar en az bir olası yol olacağını varsayabilirsiniz.

STDOUT'a, bir dosyada veya asteroid alanı bu yazıdaki gibi yazdırıldığı sürece herhangi bir eşdeğerinde çıktı alabilirsiniz (örneğin, yol için koordinatların listesini çıkarmak geçerli değildir).

Test durumları

  • Normal bir asteroid alanı

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

    Olası çıkış

    |   #####           #########  |
    | ######  #--------  ###   #   |
    |   # #  #/ #  ####\  #        |
     ---------      ##  \ #### ----@
    |#   #   #       ### \ ## /    |
    |##      ##      #### \ #/ #   |
    |####           ##### #-- ##   |
    
  • Hiper-regüler asteroid alanı

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

    Olası çıkış

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
     -# #-# #-# #-# #-# #-# #-# #--@
    |#\#/#\#/#\#/#\#/#\#/#\#/#\#/# |
    | #-# #-# #-# #-# #-# #-# #-# #|
    |# # # # # # # # # # # # # # # |
    
  • Ölüm yıldızının çekirdeği

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

    Olası çıkış

    |    #    #    #   --    #     |
    |  ---    #    #  / #\   -     |
    | /  #\   #    # /  # \ /#\    |
     -   # \  #    #/   #  - # ----@
    |    #  \ # ----    #    #     |
    |    #   \#/   #    #    #     |
    |    #    -    #    #    #     |
    
  • Ölüm yıldızı açması

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

    Çıktı

    |##############################|
    |##############################|
    |##############################|
     ------------------------------@
    |##############################|
    |##############################|
    |##############################|
    
  • Asteroit mağarası

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

    Olası çıkış

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

puanlama

R2D2 bataklıkta yüzmekle meşgul, bu yüzden Falcon'un kontrol ünitesini kendiniz programlamak zorunda kalacaksınız, bu çok sıkıcı. Bu nedenle en kısa kod kazanır .


@DJMcMayhem: Teknik olarak ilk satır "Giriş";)
Alex A.

2
Örneklere göre nasıl görünmesi gerektiğini anladım, ancak hamle kodlaması hala biraz kafa karıştırıcı. Örneğin, "hiper-regüler" örneğe bakarsanız, ilk / son hamle hariç, her zaman köşegen hareket edersiniz. Oysa -her turda “ileri” hareketi olarak tanımlanan yolda bulunuyor. Ancak asıl hareketler her zaman iki çapraz-sol ve onu takip eden iki çapraz-sağdır.
Reto Koradi,

@RetoKoradi Açıkça anlaşılan bir şey olmadığını anlayabiliyorum ama temel fikir, tüm hareketlerin bir karakterin genişliğini sağa doğru ilerletmek. Yolun sürekli görünmesi gerekir, bu nedenle sağ ve sol dönüşlerden sonraki / sonraki hareket önceki çizginin üstünde / altında bir çizgidir.
15'te

@ apsillers Her ikisi de geçerlidir, eğer sizi doğru
anlarsam

Yanıtlar:


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)

Çalıştırılabilir pasajı:

<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

Bu işlev yeni satırlı tek bir dize kabul eder. İşlev, dizgiyi ...işleci kullanarak bir diziye böler ve (x,y)koordinatlar için dizini alır (33 * y) + x.

İşlev, her alan için farklı olası hareketleri test ederek yinelemeli olarak çalışır. Bir engelle karşılaştığında, sahte bir değer döndürür ve hedefin son alanına ulaştığında geri döner true. (Golf kodunda, bu truetarafından yaratılmıştır !console.log(...).)

Bu kodun uzun süreli sağa dönüş hareketleri kullanmadığını, ancak bunları düz hareketlerle noktaladığına dikkat edin. Başka bir deyişle, birinci seçeneği değil, aşağıdaki ikinci seçeneği kullanır:

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

Bu yasal görünüyor, çünkü -yasal olarak bir dönüşten önce veya sonra gelebilir, öyleyse neden ikisi birden değil? Nihai harekettir o zaman, sonunda özellikle tuhaf görünüyor \ama olarak görüntülenir @:

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

En sevdiğim kötü golf hack burada varsayılan argüman kötüye ile c=k=" ". Argümanlar (i,l,c=" ")"dizesini kullanmak söyleyebilirim " "için ceğer füçüncü bir argüman sağlanmazsa". Ancak bunu yaparak c=k=" ", " csağlanmazsa, " "global değişkende ksakla ve sonra da bu değeri sakla " deriz c. Özyineleme yalnızca tek bir argümanla başladığından k, ilk fonksiyon çağrısında her zaman başlatılır.

Hafif 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]=" ");

}

@ vihan1086 Doğru, golf-ifying yaparken bu alanları tamamen özledim. D: Bir diziden bir dizgeye geçmek de güzel bir değişiklik. Teşekkürler. :) Ayrıca, " "puanımı daha da düşüren başka bir değişiklik daha yaptım (mevcut hareket karakterini işlev içinde belirlenen yerine üçüncü bir argüman haline getirip değişkende sakladım).
apsillers

7

C (tam program), 249 247 235 bayt

Bu, girdiyi bir dosyadan okuyan ve sonucu stdout'a çıkaran eksiksiz bir programdır. Dosyanın adı programa bir parametre olarak iletilir.

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);}

Ungolfed:

/* 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);
}

Çıktı:

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

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

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

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

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

İlk testte bitiş noktasını kaçırmış gibisin.
Reto Koradi

@RetoKoradi Bunu bir -takip eder \, ancak bu gizlice \kaplıdır @. (Programım aynı şeyi yapıyor.)
apsillers

1
@RetoKoradi Daha önceki yinelemeleri bu davayı daha iyi ele almıştı. +4 bayt. Avcıların çözümlerinin de benzer şekilde davrandığını fark ettim, bu yüzden yerden tasarruf etmeyi seçtim.
Cole Cameron

Anlıyorum. Bana doğru görünmüyor, ancak neye izin verildiğine karar vermek OP'ye bağlı. Hareketlerin nasıl temsil edildiğine dair bir miktar özgürlük verdiklerini gördüm. Baştan beri net ve benzersiz bir tanım görmek isterdim. Eğlenceli bir problem gibi görünüyordu, ancak belirsizlikle neredeyse hiç de ilginç değildi.
Reto Koradi

3

Ortak Lisp, 303 bayt

Bu zorlukla çok eğlendik, yaptığım ilk codegolf görevi. Temel olarak, geçerli olan her hareketi son konuma ulaşana kadar deneyen basit bir özyinelemeli işlev vardır.

Golfed / minified

(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)))

Çalışma dizindeki i dosyasındaki girişi okur . İyileştirme için hala yer olduğundan eminim.

Düz kod

(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)))

Örnek çıktı

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

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

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

2

ActionScript 3, 364 bayt

Bunu ikiye böldüm; biri diziyi bir dizi dizisine dönüştürmek için diğeri de uçuş yolunu hesaplamak için özyinelemeli olanı.

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;}

Bir programda tanımlanmamış bir asteroid alanı bulunan programsız sürüm:

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);
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.