ASCII topolojisi pt 1: Size güvenebilir miyim?


28

Benim ciddi bir problemim var. Çok önemli numaralarımı tuttuğum bazı metin dosyalarım var - tüm önemli olanları! Ve iki, ve üçlü ..

Bu sayılar o kadar önemliydi ki, onları yeni çıkmış ondalık ya da ikili sayı sistemlerine emanet edemedim. Her numarayı aynı şekilde unary olarak kodladım:

            +--+
            |  |
+---+  +----+  |
|   |  |       |
+---+  +-------+
   ~/two.txt

Basit ve güvenilir: İki ASCII 2 sayısı için döngüler. Maalesef, bu şeyler zamanla birbirine karışmaya meyilli ve şimdi her dosyada kaç tane döngü olduğunu bulmakta zorlanıyorum. Elde çalıştığım bazı örnekler:

Bir:

   +---+
   |   |
+--+   |
|      |
+--+   |
   |   |
   |   |
   |   |
+--+   +--+
|         |
+---------+

Üç:

+---------+
| +-----+ |
| | +-+ | |
| | | | | |
| | +-+ | |
| +-----+ |
+---------+

Dört:

  +--------------+
  |  +--+  +--+  |
  |  |  |  |  |  |
+-|-----|-----|----+
| |  |  |  |  |  | |
| +--+  +--+  +--+ |
+------------------+

              +------------+
              |            |
        +-----+  +-----+   |
        |        |     |   |
  +-----|-----------+  |   |
  |     |  +--+  |  |  |   |
  +-+   +--|--|--+  +---------+
    |      |  +-+      |   |  |
    +------+    |      |   |  |
                +-------+  |  |
                       ||  |  |
                       |+-----+
                       |   |
                       +---+

Beş:

+--------+  +--------+  +--------+
|        |  |        |  |        |
|     +--|-----+  +--|-----+     |
|     |  |  |  |  |  |  |  |     |
+-----|--+  +-----|--+  +--------+
      |        |  |        |
      +--------+  +--------+

Döngüleri saymama yardım eder misin?

İşte kurallar:

  • Her şeyi ASCII kodlu ünitede sakladığım için, alan verimliliği benim için çok önemli. Bu nedenle, bu kod golf. Bayt cinsinden en küçük program kazanır.
  • Döngüler +, -, | karakterleriyle çizilir. Döngüdeki her köşe açık bir şekilde çizilir: tam olarak + üstündeki ve altındaki karakterlerden biri |, tam olarak sağa veya sola bir - olacaktır. İki + işareti asla bitişik değildir.
  • Teller üst üste ve altından geçebilir. İplikler geçtiğinde, "üst" şeridin hemen her iki tarafında "alt" şeridi görebileceksiniz.
  • Programınız (stdin'den veya bir işlev parametresinden) döngünün dizgi gösterimini almalı ve bir sayı (stdout'a ya da bir dönüş değeri olarak) üretmelidir.
  • Çizgi uzunlukları, döngü çiziminde aynı olmayabilir ve her bir çizgi üzerinde takip eden boşluklar olabilir.
  • Girişte en az bir döngü olduğunu varsayabilirsiniz.

Sana güveniyorum!


Bir 'iplik altındaki' taraflardan biri bir olabilir +mi?
Feersum

@ feersum: Hayır, + 'ya ekli iki kenar her zaman görünür olacak.
Matt Noonan

1
@ Martin: Korkarım öyle değil. Depolama alanım gerçekten yüksek bir değer olduğu için tüm bu fazladan boşlukları alamam.
Matt Noonan

Ben bir şeyleri özmediğim ve geçerli bir giriş olmadığı sürece bunu ( pastebin ) bir test senaryosu olarak eklemeniz gerektiğini düşünüyorum . 6 döngü vardır; Sadece çevrimiçi olarak SnakeEx çözümü ile test ettim ve 12 çıktı.
blutorange

1
Belki de açıkça kendilerini yasaklayan döngüleri yasaklamanız veya izin vermeniz gerekir (örneğin pastebin.com/5RLZuULG ) Halen, yakut çözümü tarafından algılanır, ancak SnakeEx çözümü tarafından algılanmaz.
blutorange

Yanıtlar:


19

SnakeEx - Javascript ile 98 bayt, 44 olmadan

Bu, dilimi Fortnightly Challenge’dan itibaren denemek için iyi bir sorun gibi görünüyordu :

m:({e<>PE}\-[|\-]*<T>\+|[|\-]*<T>)+`\+
e:\+

Bunu denemek için en iyi yer benim çevrimiçi tercümanımdır .

SnakeEx, metin eşleştirme düzeninin etrafında hareket eden "yılanları" kullanarak metin içindeki kalıpları eşleştirir. Kod dışında bir regex gibi görünüyor:

  • <T>Talimatı. Bu, yılanı mevcut yönünden sola ve sağa yönlendiren bir yön komutudur.
  • {e<>PE}alt rutin bir çağrı gibi. Tanımı eileri doğru hareket eden bir yılan ( <>) ve parametrelerle P(geri tepme - yumurtlama yılanı yeni yılanı izler) ve E(ayrıcalıklı - zaten eşleştirilen hiçbir şeyle eşleşmiyor). Bu özel kontrol, yılanın sonsuz döngü yapmasını engelleyen tek şey.
  • Sondaki önek `, izlenenlerin yalnızca önceden eşleştirildiyse eşleşmesi gerektiğini gösterir; bu, döngüyü kapatmaya zorlamak için kullanabiliriz.

SnakeEx regex gibi olduğundan ve sonuçları kendi istediği gibi teknik olarak göstermediğinden, tercümanı çağıran bazı Javascript’e sarmamız gerekiyor:

function e(s){return snakeEx.run('m:({e<>PE}\\-[|\\-]*<T>\\+|[|\\-]*<T>)+`\\+\ne:\\+',s,1).length}

Düzenleme : blutorange ek test durumları ile çalışmak için düzeltildi


1
+1 Bundan gerçekten hoşlanıyorum, belki de çevrimiçi deneyebilir ve döngüleri vurgulayabiliyorum. Ancak bu iki test
olayını

@blutorange İyi yakala. Kendi kendine geçen döngüler için biraz zorlu bir düzeltme ekledim. Yine de test senaryosu 1'i biraz daha düşünmem gerekecek.
BMac

Düzeltmesi kolay olanı, sadece ;) [^ ]ile değiştirin[|\-]
blutorange

Hah, neden böyle olduğunu anlamam uzun zaman aldı. İyi arama.
BMac

Bu harika!
Ingo Bürk

10

C # - 338 388 433 bayt

1 boyutlu bir diziye geçerek bir grup bayt kaydedildi.

using C=System.Console;using System.Linq;class P{static void Main(){var D=C.In.ReadToEnd().Split('\n');int z,w=D.Max(m=>m.Length)+1,d,c=0;var E=D.SelectMany(l=>l.PadRight(w)).ToList();for(z=E.Count;z-->1;)if(E[z-1]==43)for(d=1,c++;E[z+=d%2<1?w*d-w:d-2]>32;)if(E[z]<44){E[z]=' ';d=d%2>0?z<w||E[z-w]<99?2:0:E[z+1]!=45?1:3;}C.WriteLine(c);}}

Öncelikle girdiyi okur ve onu güzel ve dikdörtgen yapar, "" kenarlığı olur, böylece yatayda herhangi bir sınırlama yapmak zorunda kalmayız (dikeydeki kontrolü yapmak daha fazla sıraya koymaktan daha ucuzdur) . Sonra dikdörtgenin içinden geriye bakar, böylece daima sağ alt köşeye çarpar. Bunlardan birine çarptığında, kendisini yönlendirir, bulduğu her bir + 'ı takip eder ve gittikçe (boşlukla) temizler. Bir boşlukla karşılaştığında takip etmeyi durdurur. Verilen beş örnek üzerinde test edilmiştir.

using C=System.Console;
using System.Linq;

class P
{
    static void Main()
    {
        // read in
        var D=C.In.ReadToEnd().Split('\n');

        int z, // z is position in E
        w=D.Max(m=>m.Length)+1, // w is width
        d, // d is direction of travel (1 == horizontal?, 2 == down/right?)
        c=0; // c is loop count

        // make all the lines the same length
        var E=D.SelectMany(l=>l.PadRight(w)).ToList(); // say no to horizontal bounds checking

        // consume +s
        for(z=E.Count;z-->1;)
            if(E[z-1]==43) // right-most lower-most +
                for(d=1,c++; // go left, increment counter
                    E[z+=d%2<1?w*d-w:d-2]>32 // move z, then check we havn't hit a space (when we do, z is basiclly z - 1)
                    ;)
                    if(E[z]<44) // +
                    {
                        E[z]=' '; // toodles

                        d=
                            d%2>0? // currently horizontal, must go vertical
                                z<w||E[z-w]<99?2 // can't go up, must go down
                                :0 // can go up, go up
                            : // currently vertical, must go horizontal
                                E[z+1]!=45?1 // can't go right, must go left
                                :3 // can go right, go right
                            ;
                    }

        // output result
        C.WriteLine(c);
    }
}

Vay. Etkileyici: o
Metoniem

6

Kayma , 51 41 + 2 = 43 bayt

$a(`+`-[^ +]*`+(<|>)`|[^ +]*`+#(<|>))+?$A

(Şimdi, @ blutorange'nın test çantasıyla çalışmak için büyük bir ücret karşılığında güncellendi)

@BMac bu meydan okuma için SnakeEx'i kullandığından, 2B kalıp eşleştirme dili gönderimi Slip'i kullanmaya çalışacağımı düşündüm . Fakat Slip bu problemi çözmek için gerekli özelliklere sahip olmadığından, son birkaç gündür bunları ekliyorum. Başka bir deyişle, bu başvuru kazanmaya uygun değil .

nÖrneğin, maç sayısı için bayrakla koşun

py -3 slip.py regex.txt input.txt n

Çevrimiçi deneyin .


açıklama

Bu sunumdaki yeni özelliklerin bolluğu nedeniyle, bu onları göstermek için iyi bir fırsat.

$a                Set custom anchor at current position
(
  `+`-            Match '+-'
  [^ +]*          Match any number of '|' or '-'
  `+              Match a '+'
  (<|>)           Either turn left or turn right
  `|              Match a '|'
  [^ +]*          Match any number of '|' or '-'
  `+              Match a '+'
  #               Prevent next match from moving the match pointer (doubling up on '+')
  (<|>)           Either turn left or turn right
)
+?                Do the above at least once, matching lazily
$A                Make sure we're back where we started

Kayma, her pozisyondan başlayarak eşleşmeye çalışır ve yalnızca benzersiz eşleşmeleri döndürür. Kullandığımızı not edin [^ +]- kullanırken [-|]teorik olarak iki byte tasarruf sağlar -, karakter sınıflarının başında / sonunda çıkmadan henüz Slip'te uygulanmadı.


1
@blutorange threeayrıca +bir -, bir |ve 2 boşluk olmayan s'ye sahiptir , bu yüzden bunun bir hata olmadığını varsayıyorum
Sp3000

5

Ruby 295

F=->i{l=i.lines
g={}
l.size.times{|y|i.size.times{|x|l[y][x]==?+&&g[[y,x]]=[[y,x]]}}
c=->a,b{w=g[b]+g[a];w.map{|x|g[x]=w}}
k=g.keys
k.product(k).map{|n,o|
r,p=n
s,q=o
((r==s&&p<q&&l[r][p...q]=~/^\+-[|-]*$/)||(p==q&&r<s&&l[r...s].map{|l|l[p]||c}.join=~/^\+\|[|-]*$/))&&c[n,o]}
g.values.uniq.size}

Çevrimiçi deneyin: http://ideone.com/kIKELi ( İlk hatta bir #to_aarama ekledim , çünkü ideone.com s #sizeiçin desteklemeyen Ruby 1.9.3 kullanıyor Enumerable. Ruby 2.1.5+ sürümünde kod çalışıyor . )

Yaklaşım şöyledir:

  • Girdideki bütün +işaretlerin bir listesini yapın ve her birini ayrı bir şekil olarak kabul edin.
  • iki +işareti birbirine bağlayan ve şekillerini bir araya getiren yatay ve dikey çizgiler bulun
  • sonunda, farklı şekillerin sayısı sonuçla eşleşir

İşte daha okunaklı bir sürüm:

def ascii_topology_count(input)
  lines = input.lines
  max_length = lines.map(&:size).max

  # hash in which the keys are corners ("+"s), represented by their [y, x] coords
  # and the values are arrays of corners, representing all corners in that group
  corner_groups = {}

  lines.size.times { |y|
    max_length.times { |x|
      if lines[y][x] == ?+
        corner_groups[[y, x]] = [[y, x]]
      end
    }
  }

  # function that combines the groups of two different corners
  # into only one group
  combine_groups =-> c1, c2 {
    g1 = corner_groups[c1]
    g2 = corner_groups[c2]

    g2 += g1
    corner_groups[c1] = g2
    g2.map{|x| corner_groups[x] = g2}
  }

  corner_groups.keys.product(corner_groups.keys).map{|c1, c2|
    y1,x1=c1
    y2,x2=c2
    if y1 == y2 && x1 < x2
      # test horizontal edge
      t = lines[y1][x1...x2]
      if t =~ /^\+-[|-]*$/
        # p "#{c1}, #{c2}, [H] #{t}"
        combine_groups[c1, c2]

      end
    end

    if x1 == x2 && y1 < y2
      # test vertical edge
      t=lines[y1...y2].map{|l|l[x1]||' '}.join

      if t =~ /^\+\|[|-]*$/
        # p "#{c1}, #{c2}, [V] #{t}"
        combine_groups[c1, c2]
      end
    end
  }

  corner_groups.values.uniq.count
end

5

JavaScript (ES6) 190 197 202 215 235 289 570

Düzenleme 2 yerine boyutun tek boyutlu dizi, maksimum satır boyutu 999 karakter (ancak maliyetle daha fazla olabilir, örneğin, 1E5 yerine 999)

Düzenle Eklendi animasyonlu kod pasajı, aşağıya bakın

F=s=>[...s.replace(/.+/g,r=>r+Array(e-r.length),e=999)]
  .map((c,x,z,d=1,f='-',g='|')=>{
    if(c=='+')
      for(++n;z[x+=d]!='+'||([f,g,e,d]=[g,f,d,z[x-e]==g?-e:z[x+e]==g&&e],d);)
        z[x]=z[x]==g&&g
  },n=0)|n

Ungolfed ilk denemesi

f=s=>
{
  cnt=0
  s = (1+s+1).split(/[1\n]/)

  for(;x=-1, y=s.findIndex(r=>~(x=r.indexOf('+-'))), x>=0;++cnt)
  {
    //console.log(y+' '+x+' '+s.join('\n'))
    dx = 1
    for(;dx;)
    {
      a=s[y-1],b=s[y+1],
      r=[...s[y]]
      for(r[x]=' ';(c=r[x+=dx])!='+';)
      {
        if (c=='-')
          if((a[x]||b[x])=='|')r[x]='|';
          else r[x]=' ';
      }  

      if(a[x]=='|')dy=-1;
      else if(b[x]=='|')dy=1;
      else dy=0
      r[x]=' '
      s[y]=r.join('')
      if (dy) {
        for(;y+=dy,r=[...s[y]],(c=r[x])!='+'&c!=' ';)
        {
          if (c=='|') 
            if((r[x-1]||r[x+1])=='-')r[x]='-';
            else r[x]=' ';
          s[y]=r.join('')
        }  
        if(r[x-1]=='-')dx=-1;
        else if(r[x+1]=='-')dx=1;
        else dx=0;
      }
    }  
  }
  return cnt
}

Animasyonlu snippet

Firefox / FireBug konsolunda test edin

F('\
  +--------------+\n\
  |  +--+  +--+  |\n\
  |  |  |  |  |  |\n\
+-|-----|-----|----+\n\
| |  |  |  |  |  | |\n\
| +--+  +--+  +--+ |\n\
+------------------+\n\
\n\
              +------------+\n\
              |            |\n\
        +-----+  +-----+   |\n\
        |        |     |   |\n\
  +-----|-----------+  |   |\n\
  |     |  +--+  |  |  |   |\n\
  +-+   +--|--|--+  +---------+\n\
    |      |  +-+      |   |  |\n\
    +------+    |      |   |  |\n\
                +-------+  |  |\n\
                       ||  |  |\n\
                       |+-----+\n\
                       |   |\n\
                       +---+')

4

F('\
+--------+  +--------+  +--------+\n\
|        |  |        |  |        |\n\
|     +--|-----+  +--|-----+     |\n\
|     |  |  |  |  |  |  |  |     |\n\
+-----|--+  +-----|--+  +--------+\n\
      |        |  |        |\n\
      +--------+  +--------+')

5


Elbette golf versiyonunu tek sıraya sokarak bazı baytları kurtarırsınız? Ayrıca anonim bir işlev de oluşturabilirsiniz (sanırım codegolf kuralları dahilinde)
theonlygusti

@theonlygusti golfed versiyonu ... Ben 2 bayt, önemsiz tasarruf tasarruf isimsiz bir işlev .With tek hat (hiçbir yeni satırların ve girinti boşluk sayılır) olarak sayılır
edc65

4

Ruby, 178 187 199 212

Daha iyi yakut versiyonu, F fonksiyonu yaratır. Şimdi daha lezzetli tercüman uyarıları ile sürekli.

b=->n{Q[I]=?~
d=Q[I+n]==(n>1??|:?-)?1:-1
loop{I+=d*n
b[n>1?1:N]if Q[I]==?+
Q[I]<?~?4:break}}
F=->s{N=s.size;Q=s+?\n
Q.gsub!(/^.*$/){$&.ljust N-1}
(0..N).find{!(I=Q=~/\+/)||b[1]}}

Çevrimiçi test edin: ideone

Temelde, fonksiyon bherhangi başlar +, ardışık tüm ayar, döngü geçer +için u. Böylece her seferinde bir döngü kaldırılır b. İşlev Fsadece bherhangi bir döngü kalmamış olana kadar ne sıklıkta aramamız gerektiğini dener .


2

Python 2 - 390

Stdin'den newlines ile bir dize alır. Oldukça basit bir yöntemle oynanan oldukça basit bir yöntem, ancak ne kadar süreceğini düşündüğümden emin değilim.

s=raw_input().split('\n');L=len
def R(x,y):
 b=p,q=x,y;u=v=f=0
 while b!=(p,q)or not f:
    p+=u;q+=v;f=u+v;c=s[q][p]
    if'+'==c:u,v=[(i,j)for i,j in{(-1,0),(1,0),(0,-1),(0,1)}-{(-u,-v)}if 0<=q+j<L(s)and 0<=p+i<L(s[q+j])and s[q+j][p+i]in['-+','|+'][j]][0];s[q]=s[q][:p]+' '+s[q][p+1:]
    if c+s[q+v][p+u]in'-|-':p+=u;q+=v
print L([R(x,y)for y in range(L(s))for x in range(L(s[y]))if'+'==s[y][x]])

1

Python 2 - 346 bayt

cDosya verilerini girdi olarak alan ve döngü sayısını döndüren bir işlev olarak uygulanır.

İlk olarak, işlev, verileri döngü elemanı konumlarının o konumdaki öğe türüne eşlemesine ayrıştırır (örn. {(0,0): '+'}). Ardından, karşılıklı olarak iki özyinelemeli iç işlev kullanır. Birincisi, bir döngü segmentini haritalamadan kaldırır ve sonraki segment için hangi yerleri kontrol edeceğine karar verir. İkincisi, seçili konumlarda ne tür bir döngü elemanı olduğunu kontrol eder ve beklenenlerle uyumluysa, yeni bulunan bölümü ilk kaldırır.

e=enumerate
def c(d):
 D={(i,j):k for i,l in e(d.split('\n'))for j,k in e(l)if k in'+-|'}
 def f(r,c,R,C,t):
  if D.get((r,c),t)!=t:g(r,c)
  elif D.get((R,C),t)!=t:g(R,C)
 def g(r,c):
  t=D.pop((r,c))
  if t!='|':f(r,c-1,r,c-2,'|');f(r,c+1,r,c+2,'|')
  if t!='-':f(r-1,c,r-2,c,'-');f(r+1,c,r+2,c,'-')
 n=0
 while D:g(*D.keys()[0]);n+=1
 return n
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.