Göreceli - Mutlak


17

Bu ızgaradaki A noktasında kuzeye bakan biri, B noktasına giden yeşil yolu (yalnızca ızgara çizgilerini takip edebilecekleri gibi) takip etmek için yol tarifleri isterse, onlara şunu söyleyebilirsiniz:

Git North, North, West, East, East, South, East, East.

Veya eşdeğer olarak

Git Forward, Forward, Left, Back, Forward, Right, Left, Forward.
( Sağ , Sol veya Geri komutunun dolaylı olarak bu yönde dönmesi, sonra ileri gitmesi anlamına gelir.)

A'dan B'ye yolu

Yalnızca bir noktaya değil , aynı yol boyunca bu mutlak ve göreli yönler arasında çeviri yapan bir bağımsız değişkeni olan bir işlev yazın . Yönlendirilen kişinin her zaman kuzeye bakmaya başladığını varsayın.

Argüman harflerden oluşan bir dizeyse NSEW, eşdeğer bağıl yönleri döndürün.
örneğin f("NNWEESEE"), dizeyi döndürür FFLBFRLF.

Bağımsız değişken harflerden oluşan bir dizeyse FBLR, eşdeğer mutlak yönleri döndürün.
örneğin f("FFLBFRLF"), dizeyi döndürür NNWEESEE.

Boş dize kendini verir. Başka girdi vakası olmadığını varsayalım.

Dilinizde işlevler veya dizeler yoksa en uygun olanı kullanın.

Bayt cinsinden en kısa kod kazanır.


Bir insanın her zaman başı Kuzeye bakacak şekilde başladığını düşünüyor muyuz? Bu şekilde, göreli olarak Doğu'ya gitmek için, sadece İleri'yi söylemekten ziyade Sağa
Optimizer

@Optimizer Evet, kuzey. Ve evet diğer noktaya. başlangıçta Reşittir E.
Calvin'in Hobileri

1
Yaşasın! Her zaman ne düşündüğümü doğrulamak için resmini değiştirdin!
Justin

4
Yine PPCG'ye mi takıldınız? ;)
Martin Ender

4
@ MartinBüttner Öyle ya da ödev problemlerimi gizlemekte çok iyiyim. ;)
Calvin'in Hobileri

Yanıtlar:


6

CJam, 57 53 49

{"NESW""FRBL"_3$&!!:Q$:R^^f#0\{{+0\}Q*_@-R=\}%);}

Önceki versiyon

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}

Misal:

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}:T;
"NNWEESEE"T
N
"FFLBFRLF"T

Çıktı:

FFLBFRLF
NNWEESEE

Nasıl çalışır

{
  "NESW""FRBL"             " Push the two strings. ";
  _3$0=#W>                 " Check if the first character is in FRBL. ";
  :Q                       " Assign the result to Q. ";
  {\}*                     " Swap the two strings if true. ";
  :R;                      " Assign the top string to R and discard it. ";
  f#                       " Find each character of the input in the string. ";
  0\                       " Push a 0 under the top of the stack. ";
  {                        " For each item (index of character): ";
    {                      " If Q: ";
      +0\                  " A B -> 0 (A+B) ";
    }Q*
    _@-                    " C D -> D (D-C) ";
    R=                     " E -> E-th character in R ";
    \                      " Swap the top two items. ";
  }%
  );                       " Discard the last item in the list. ";
}

6

C ++, 99 97

Aşağıdakiler lambda ifadesi olarak biçimlendirilir. Bir char*argüman alır ve üzerine yazar.

[](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];}

Bu özelliğe aşina olmayanlar için (1 saat önce kendim gibi), aşağıdaki gibi kullanın:

#include <iostream>

int main()
{
    char s[] = "NNWEESEE";
    auto x = [](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];};

    x(s); // transform from absolute to relative
    std::cout << s << '\n';

    x(s); // transform from relative to absolute
    std::cout << s << '\n';
}

Bazı açıklamalar:

  • Gibi kod kullanırken flag ? (x = y) : (x += z) , C'de ikinci parantez çifti gereklidir. Bunun yerine C ++ kullandım!
  • C ++, bir işlev için bir dönüş türü belirtmeyi gerektirir. Bir lambda ifadesi kullanmadığım sürece, bu! Ek olarak, fonksiyonun adına 1 karakter harcamak zorunda kalmam.
  • Kod *s*9%37&4ilk baytı test eder; sonuçlardan biri 4 ise NESW; 0 aksi takdirde
  • Kod *s%11/3baytları NESW0, 1, 2, 3'e dönüştürür
  • Kod *s%73%10baytları FRBL0, 9, 6, 3'e (0, 1, 2, 3 modulo 4) dönüştürür
  • Göreli yönleri mutlak olarak dönüştürürken, ddeğişkene ihtiyacım yok . Kodu tamamen ortadan kaldırmak için yeniden düzenlemeyi denedim, ama imkansız görünüyor ...

1
Harfleri sayılara dönüştürme şeklinizi çok seviyorum. :)
Emil

6

JavaScript (E6) 84 86 88 92104

Düzenleme: & yerine%, farklı işleç önceliği (daha az köşeli ayraç) kullanarak ve negatif sayılarla daha iyi çalışır
Edit2: | + yerine op önceliği, -2. Teşekkürler DocMax
Edit3: dizi anlama dizelerden, haritadan () 2 karakter daha kısadır

F=p=>[o+=c[d=n,n=c.search(i),n<4?4|n-d&3:n=n+d&3]for(i of n=o='',c='NESWFRBL',p)]&&o

FireFox / FireBug konsolunda test et

console.log(F('NNWEESEE'),F('FFLBFRLF'))

Çıktı

FFLBFRLF NNWEESEE

@Optimizer artık yok. Ve daha da küçülmeyi umuyorum.
edc65

&& oSonunda ne anlama geliyor?
bebe

2
@bebe harita fonksiyonu içinde bir dizi döndürür, bir yan etkisi olarak, ben geri dönmek için gereken o dize doldurun. array && valueiçin değerlendirebilecek valueherhangi dizi için değerlendirirkentruthy
edc65

1
En sonunda! O bir şey eksik sürece, yerine 88. isabet beri bu bir bakan edilmiş 4+(n-d&3)olan 4|n-d&3ve 2 karakter kurtarmak.
DocMax

4

APL, 72

{^/⍵∊A←'NESW':'FRBL'[1+4|-2-/4,3+A⍳⍵]⋄A[1+4|+\'RBLF'⍳⍵]}

Tercüman yapılandırmaları ceza olmadan değiştirilebilir, sonra puanıdır 66 değiştirerek, ⎕IOiçin 0:

{^/⍵∊A←'NESW':'FRBL'[4|-2-/0,A⍳⍵]⋄A[4|+\'FRBL'⍳⍵]}

3

Python, 171 139

Diğer çözümler kadar kısa bir yol yok, ama sanırım Python ile neler yapılabileceği için nispeten iyi olmalı:

def f(i):a,b='NWSE','FLBR';I=map(a.find,'N'+i);return''.join((b[I[k+1]-I[k]],a[sum(map(b.find,i)[:k+1])%4])[-1in I]for k in range(len(i)))

Biraz daha iyi okunabilirlik için genişletilmiş sürüm:

def f(i):
    a, b = 'NWSE', 'FLBR'
    I = map(a.find,'N'+i)     # translate to numbers assuming abs. directions
    J = map(b.index,i)        # translate to numbers assuming rel. directions
    if not -1 in I:
        o = [b[I[k+1]-I[k]] for k in range(len(i))]    # rel. dir. is differences of abs. dir.
    else:
        o = [a[sum(J[:k+1])%4] for k in range(len(i))] # abs. dir. is sum of all rel. dir. so far
    return ''.join(o)

1

Git 201

type q string;func F(s q)q{d,z:=byte(0),make([]byte,len(s));for i,c:=range[]byte(s){if(c^4)*167%3<2{c=c*156%5;z[i],d="LBRF"[(d-c)%4],c-1;}else{c=(c^43)*3%7-1;d=(d+c)%4;z[i]="NESW"[d];};};return q(z);}

Okunabilir sürüm:

func F(s string) string {
    d, z, R, A := 0, make([]byte, len(s)), "LBRFLBR", "NESW"
    for i, c := range []byte(s) {
        switch c {
        case 'N': c = R[d+3]; d = 0
        case 'E': c = R[d+2]; d = 1
        case 'S': c = R[d+1]; d = 2
        case 'W': c = R[d]; d = 3
        case 'F': c = A[d]
        case 'R': d = (d + 1) % 4; c = A[d]
        case 'B': d = (d + 2) % 4; c = A[d]
        case 'L': d = (d + 3) % 4; c = A[d]
        }
        z[i] = c
    }
    return string(z)
}


1

GNU sed, 356 bayt

Zorluk, bir karakter akışında basit bir dönüşüm gerektiriyor. sed, yayın editörü dilin belirgin seçimidir ;-)

/[FRBL]/bx                                     # Jump to label x if relative
:y                                             # label y (start of abs->rel loop)
/[FRBL]$/q                                     # quit if string ends in rel char
s/(^|[FRBL])N/\1F/;ty                          # Substitute next abs char with
s/(^|[FRBL])E/\1R/;tr                          #     rel char, then jump to
s/(^|[FRBL])S/\1B/;tb                          #     relevant rotation label if
s/(^|[FRBL])W/\1L/;tl                          #     a match was found
by                                             # loop back to y
:r;y/NESW/WNES/;by                             # Rotation labels: transform then
:b;y/NESW/SWNE/;by                             #     loop back to y
:l;y/NESW/ESWN/;by
:x                                             # label x (start of rel->abs loop)
/^[NESW]/q                                     # quit if string starts w/ abs char
/F([NESW]|$)/s/F([NESW]|$)/N\1/                # Matches for each direction:
/R([NESW]|$)/y/NESW/ESWN/;s/R([NESW]|$)/E\1/   #     rotate, then substitute
/B([NESW]|$)/y/NESW/SWNE/;s/B([NESW]|$)/S\1/
/L([NESW]|$)/y/NESW/WNES/;s/L([NESW]|$)/W\1/
bx                                             # loop back to x

(Golf skoru hesaplaması için yorumlar ve alanlar çıkarılmıştır)

Çıktı:

$ sed -rf absrel.sed <<< NNWEESEE
FFLBFRLF
$ sed -rf absrel.sed <<< FFLBFRLF
NNWEESEE
$ 

Açıklama:

Buradaki fikir şudur ki, referans çerçevesini değiştirdiğimizde, {N, E, S, W}ve arasında daima doğrudan bir eşleme vardır {F, R, B, L}.

Akrabadan mutlak olana doğru, ip üzerinden uçurumlar çalışırız. Biz map Her karakter için {N, E, S, W}için {F, R, B, L}, daha sonra kalan döndürmek[NESW]Eşlediğimiz eşlediğimiz karaktere göre karakterleri , ardından bir sonraki karaktere geçin.

Mutlaktan göreceli olana doğru tersini yaparız. Dizede geriye doğru çalışarak, sonraki tüm [NESW]karakterleri hemen öndeki karaktere göre döndürüyoruz . Sonra bu karakteri harita {N, E, S, W}için {F, R, B, L}biz dize başlangıcına elde edene kadar.


0

Haskell, 224

import Data.Function
i=flip(\x->length.takeWhile(/=x))
r=['F','R','B','L']
a=['N','E','S','W']
f s@(x:_)|elem x a=map((r!!).(`mod`4).(4-))$zipWith((-)`on`(i a))('N':s)(s)|True=tail$map((a!!).(`mod`4)).scanl(+)(0)$map(i r) s

Bu, bağıl yönlere dönüş sayılarını ve mutlak yönlere yönlendirme sayılarını atar, ardından ardışık yönelimler veya ardışık dönüşlerden sonraki yönelimler arasındaki dönüşleri bulur. iFonksiyon iki efsane içinde endeksi bulur.

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.