Kegilaan cermin ajaib

22

pengantar

Saya punya kamar yang penuh cermin ajaib . Mereka adalah artefak misterius yang dapat menduplikasi item apa pun, kecuali cermin ajaib lainnya. Secara lebih eksplisit, versi duplikat item akan muncul di sisi lain dari cermin, pada jarak yang sama. Namun, jika ada cermin ajaib lain di jalan di kedua sisi, antara cermin duplikat dan item (asli atau duplikat), duplikat tidak terbentuk. Item asli dapat berupa kiri atau kanan cermin, dan duplikat akan muncul di sisi lain. Juga, item duplikat itu sendiri dapat diduplikasi oleh mirror lain. Item tidak pernah memblokir duplikasi item lain (kecuali dengan langsung pada posisi calon duplikat).

Memasukkan

Input Anda adalah string yang terdiri dari karakter .#|, yang mewakili ruang kosong, item, dan cermin ajaib. Akan selalu ada setidaknya satu cermin ajaib di input.

Keluaran

Output Anda akan menjadi string lain di mana setiap cermin ajaib telah menggandakan setiap item yang bisa, sesuai dengan aturan di atas. Anda dapat mengasumsikan bahwa akan selalu ada ruang kosong di tempat di mana item duplikat muncul (sehingga mereka tidak akan keluar batas).

Contohnya

Pertimbangkan string input

.#.|.....|......#
 A B     C      D

di mana kami telah menandai beberapa posisi untuk kejelasan. Cermin Bduplikat item A, yang berakhir di sebelah kanan:

.#.|.#...|......#
 A B     C      D

Mirror Clalu menggandakan item baru:

.#.|.#...|...#..#
 A B     C      D

Mirror Ctidak dapat menduplikasi item A, karena mirror Bmenghalangi. Itu juga tidak dapat menduplikasi item D, karena mirror Bada di sisi lain. Demikian juga, mirror Btidak dapat menduplikasi item Datau duplikat di sebelahnya, karena mirror Cmenghalangi, jadi ini adalah output yang benar.

Sebagai contoh lain, pertimbangkan inputnya

.##..#...|#..##...|..##....#.
 AB  C   DE  FG   H  IJ    K

Cermin Ddapat menggandakan Adan Bke kanan, dan Edan Gke kiri. Cdan Fsudah merupakan duplikat satu sama lain. Tali itu menjadi

.##.##..#|#..##.##|..##....#.
 AB  C   DE  FG   H  IJ    K

Cermin Hdapat menggandakan E,, Fdan duplikat dari Adan Bke kanan, dan Ike kiri. Gdan Jsudah duplikat satu sama lain, dan mirror Ddi jalan K. Sekarang kita punya

.##.##..#|#..#####|#####..##.
 AB  C   DE  FG   H  IJ    K

Akhirnya, mirror Ddapat menggandakan duplikat dari Ike kiri. Kita berakhir dengan

.#####..#|#..#####|#####..##.
 AB  C   DE  FG   H  IJ    K

Aturan dan penilaian

Anda dapat menulis program lengkap atau fungsi. Hitungan byte terendah menang. Kiriman yang tidak menggunakan mesin regex bersaing secara terpisah dari yang melakukannya, dan dapat ditandai dengan (tidak ada regex) .

Uji kasus

"|" -> "|"
"..|.." -> "..|.."
".#.|..." -> ".#.|.#."
"..#|.#." -> ".##|##."
".#..|....|.." -> ".#..|..#.|.#"
".|..|.#....." -> "#|#.|.#....."
"...|.#...|....#" -> ".##|##...|...##"
"......#|......." -> "......#|#......"
".#.|.....|......#" -> ".#.|.#...|...#..#"
".......|...#.##|...." -> "##.#...|...#.##|##.#"
"...#..||.......#..#...#" -> "...#..||.......#..#...#"
".##|.#....||#||......#|.#" -> ".##|##....||#||.....##|##"
".##..#...|#..##...|..##....#." -> ".#####..#|#..#####|#####..##."
".#|...||...|#...|..##...|#...." -> ".#|#..||.##|##..|..##..#|#..##"
"....#.|...#.|..|.|.....|..#......" -> "..#.#.|.#.#.|.#|#|#.#..|..#.#...."
"..|....|.....#.|.....|...|.#.|..|.|...#......" -> ".#|#...|...#.#.|.#.#.|.#.|.#.|.#|#|#..#......"
Zgarb
sumber
Bisakah kita mengambil array karakter sebagai input dan / atau output?
Conor O'Brien
@ ConorO'Brien Tidak, kecuali itu adalah representasi alami dari string dalam bahasa Anda.
Zgarb

Jawaban:

10

Retina , 50 byte

+`([#.])(([#.])*\|(?>(?<-3>[#.])*))(?!\1)[#.]
#$2#

Cobalah online! (Baris pertama memungkinkan suite tes yang dipisahkan dengan linefeed.)

Saya kira ini adalah kebalikan dari pengiriman (tanpa regex).

Penjelasan

Ini hanyalah pengganti regex, yang diterapkan berulang kali ( +) hingga string berhenti berubah. Saya menggunakan kelompok penyeimbang untuk memastikan bahwa dua posisi cermin adalah jarak yang sama dari cermin yang diberikan (backreferences tidak akan berlaku, karena string yang tepat di kedua sisi |mungkin berbeda).

([#.])            # Match and capture a non-mirror cell.
(                 # This will match and capture everything up to its corresponding
                  # cell so that we can write it back in the substitution.
  ([#.])*         #   Match zero or more non-mirror cells and push each one onto
                  #   group 3. This counts the distance from our first match to
                  #   the mirror.
  \|              #   Match the mirror.
  (?>             #   Atomic group to prevent backtracking.
    (?<-3>[#.])*  #     Match non-mirror while popping from group 3.
  )               #   There are three reasons why the previous repetition
                  #   might stop:
                  #   - Group 3 was exhausted. That's good, the next position
                  #     corresponds to the first character we matched.
                  #   - We've reached the end of the string. That's fine,
                  #     the last part of the regex will cause the match to fail.
                  #   - We've hit another mirror. That's also fine, because
                  #     the last part of the regex will still fail.
)
(?!\1)            # Make sure that the next character isn't the same as the first
                  # one. We're looking for .|# or #|., not for #|# or .|.
[#.]              # Match the last non-mirror character.

Ini diganti dengan #$2#yang menggantikan karakter pertama dan terakhir dari pertandingan dengan a #.

Martin Ender
sumber
9

Perl, 49 byte

Kredit penuh untuk @Martin Ender untuk yang ini menyarankan regex ini 15 byte lebih pendek dari saya.

47 byte kode + -plbendera

s/([.#])(\||[^|](?2)[^|])(?!\1)[^|]/#$2#/&&redo

Untuk menjalankannya:

perl -plE 's/([.#])(\||[^|](?2)[^|])(?!\1)[^|]/#$2#/&&redo' <<< ".##..#...|#..##...|..##....#."

Bagian pertama ( ([.#])) dan terakhir ( (?!\1)[^|]) sama dengan jawaban Retina (lihat penjelasan di sana).
Bagian tengah ( (\||[^|](?2)[^|])) menggunakan rekursi perl ( (?2)) untuk mencocokkan mirror ( \|) atau ( |) dua karakter bukan-mirror-( [^|]) dipisahkan oleh pola yang sama ( (?2)).


Versi saya yang lebih lama (dan lebih jelek): s/([.#])(([^|]*)\|(??{$3=~s%.%[^|]%gr}))(?!\1)[^|]/#$2#/&&redo

Dada
sumber
4

Haskell (tanpa regex), 117 byte

r=reverse
s=span(<'|')
m=zipWith min
g a|(b,l:c)<-s a,(d,e)<-s c=b++l:g(m(r b++[l,l..])d++e)|0<1=a
f x=m(g x)$r.g.r$x
dianne
sumber
2

PHP, 123 117 100 byte

for($t=$argv[1];$t!=$s;)$t=preg_replace("%([.#])(\||[.#](?2)[.#])(?!\g1)[.#]%","#$2#",$s=$t);echo$t;

program mengambil argumen command line, regex diambil dari @Martin Ender / Dada. Jalankan dengan -r.

Titus
sumber
@ Zgarb diperbaiki, terima kasih
Titus
2

C, 176 byte

void t(char*a){int x=0;for(int i=0;a[i];i++)if(a[i]=='|'){for(int j=x;a[j]&&j<=i*2-x;j++){if((a[j]==35)&&(a[2*i-j]==46)){a[2*i-j]=35;i=-1;}if((i-j)&&(a[j]=='|'))break;}x=i+1;}}

Tidak disatukan

void t(char*a)
{
    int x=0;
    for(int i=0;a[i];i++)
        if(a[i]=='|')
        {
            for(int j=x;a[j]&&j<=i*2-x;j++)
            {
                if((a[j]=='#')&&(a[2*i-j]=='.'))
                {
                    a[2*i-j]='#';
                    i=-1;
                    break;
                }
                if((i!=j)&&(a[j]=='|'))
                    break;
            }
            x=i+1;
        }
}
Eyal Lev
sumber
1
Saya pikir Anda dapat menyimpan beberapa byte dengan mengganti '#'dan '.'dengan 35dan 46masing - masing.
artificialnull
Kode ini dapat di mainkan..banyak.
Mukul Kumar
Terima kasih artificialNull, yang menyelamatkan 3 bye. '|' adalah 124, jadi itu tidak menyimpan apa-apa (tapi mungkin saya harus mengubahnya, jadi itu akan konsisten; belum yakin). dan @Mukul, saya tidak benar-benar mengerti caranya, tanpa banyak mengubah alur logikanya.
Eyal Lev
periksa apakah kode ini berfungsi dengan baik x,i,j;void t(char*a){while(a[i]++)if(a[i]=='|'){for(j=x;a[j++]&&j<=i*2-x;j++){if((a[j]==35)&&(a[2*i-j]==46)){a[2*i-j]=35;i=-1;break;}if((i-j)&&(a[j]=='|'))break;}x=i+1;}}- 170 byte
Mukul Kumar
1
Ganti 1 byte lebih (i! = J) dengan (ij) dan jika Anda akan tetap menggunakan c ++ maka atleast mendefinisikan semua int di satu tempat ...
Mukul Kumar
1

JavaScript (ES6), 170 byte

s=>s.replace(/#/g,(c,i)=>(g(i,-1),g(i,1)),g=(i,d,j=h(i,d))=>j-h(j=j+j-i,-d)|s[j]!='.'||(s=s.slice(0,j)+'#'+s.slice(j+1),g(j,d)),h=(i,d)=>s[i+=d]=='|'?i:s[i]?h(i,d):-1)&&s

Tidak Disatukan:

function mirror(s) {
    for (var i = 0; i < s.length; i++) {
        // Reflect each # in both directions
        if (s[i] == '#') s = reflect(reflect(s, i, true), i, false);
    }
    return s;
}
function reflect(s, i, d) {
    // Find a mirror
    var j = d ? s.indexOf('|', i) : s.lastIndexOf('|', i);
    if (j < 0) return s;
    // Check that the destination is empty
    var k = j + (j - i);
    if (s[k] != '.') return s;
    // Check for an intervening mirror
    var l = d ? s.lastIndexOf('|', k) : s.indexOf('|', k);
    if (l != j) return s;
    // Magically duplicate the #
    s = s.slice(0, k) + '#' + s.slice(k + 1);
    // Recursively apply to the new #
    return reflect(s, k, d);
}
Neil
sumber