2 boyutlu ışın izleme


9

Zor olan, metin tabanlı 2 boyutlu bir ışın izleme programı uygulamaktır.

Beyaz ışık kaynakları @sembollerdir. R, GVe Bhafif filtrelerdir. /ve \% 80 yansıtma özellikli aynalardır. ?bir ışık sensörüdür. >, <, ^Ve Vuygun yönde ışık birleştirmek (örneğin bir kırmızı ve bir yeşil bir haline geldiyse >sağa doğru yayılan olacağını ışık ve sarı olacaktır). Diğer boşluk olmayan karakterler tüm ışığı emer. Işık dört yöndeki @sembollerden yayılır .

Program çalıştırıldığında, girişle aynı, ancak izlenen ışınlarla çıktı üretmelidir. Bu 2 boyutlu olduğundan ve girişte hiçbir ışının geçmeyeceğini garanti ediyorum, bununla ilgili bir sorun olmayacak. Her ışın bir harfle temsil edilmelidir; r = kırmızı, g = yeşil, b = mavi, c = camgöbeği, m = macenta, y = sarı, w = beyaz. Hiç üçlü renkler olmayacak. Muhafaza, onu girişten ayırmak için önemlidir. Bu çıktıdan sonra, soru işaretleri tarafından yakalanan ışığın değerleri (görünüş sırasına göre, soldan sağa yukarıdan aşağıya) yüzde ve renk olarak verilmelidir. Örneğin, bu girdi:

 /                  @
                    -
 \R>                 ?

 @B/

Çıktı vermelidir:

 /wwwwwwwwwwwwwwwwww@w
 w                  -
w\R>mmmmmmmmmmmmmmmmm?
 w b
 @B/

#1: 72% Magenta

Dikkat edilmesi gereken bir başka önemli nokta - iki renk bir "prizma" (oklar) kullanılarak birleştirildiğinde, birleştirilen ışığın gücü ikisinin ortalama gücü olur. Çıktı tam olarak belirtildiği gibi olmalıdır (örneğin #x: [x] [x] x% Renk ).

Diliniz STDIN'den okuyamıyor ve STDOUT'a yazamıyorsa, girdiyi bağımsız değişken olarak kabul eden ve sonucu döndüren bir işlev (varsa anonim veya lambda) oluşturun.

Derleyicinin yönergeleri, dilde oluşturulan programların tümü veya çoğu için gerekli veya önerilen yapılar, vb. Atlanabilir. Örneğin, #includeve usingdirektifler (ancak değil #define) C tarzı dillerde, #/usr/bin/perl -optionsPerl ve

 Module Module1
      Sub Main()
      End Sub
 End Module

örneğin VB.NET'te. Ad alanlarını içe aktarırsanız veya içerme yönergeleri eklerseniz, lütfen yanıtınıza not edin.

Şimdi bu yeterince zor mu? :)


Code Golf: Lasers on Stack Overflow. İle ilgili olarak
dmckee --- eski moderatör yavru kedi

Aynanın örneğinizdeki davranışı bir anlam ifade etmiyor. Doğrudan geçmekte olan ışığı etkileyen bir \ (kaçma bozuk) var. Ayna ile aynı sıraya ışık girmesi ve aynı sütunda kalması ya da tam tersi çok daha mantıklı görünüyor. Benzer şekilde, >doğrudan geçip giden ışığı yakalamaktır. Ve eğer wüst kısımdan geçerse , alttan da Rgeçmelidir b. Sonunda (sanırım), ışınların geçmemesi konusunda yanılıyorsunuz. Tek satırlık bir örnek vermek gerekirse, doğru çıktı ne için olurdu @R> B@?
Peter Taylor

Neden rastgele bir w eklediniz ve tüm aralıkları kırdınız? Ve ışık düz geçmiyor, ne demek istediğinden emin değilim.
Ry-

@minitech, @sol altta dört yönde de ışık yayıyor değil mi? Özellikle, bunu yayar w. Ve en azından Chromium'da olduğu gibi boşluk bırakmadım. Düz bir şekilde geçmeye gelince, düzenlemem bunu temizleyebilir.
Peter Taylor

5
minitech: Gelecekteki görevler için bir tavsiye olarak: İlk önce Sandbox veya Puzzle Lab'da tutarsızlıkları ve görevlerle ilgili erken problemleri gidermeye yetecek yorumları isteyin . Bu şekilde, görevi buraya gönderdikten sonra, başkaları tarafından zaten kontrol edildiğini (ve belki de uygulandığını) bilirsiniz.
Joey

Yanıtlar:


2

Python, 602 559 614 karakter

import sys
S=sys.stdin.readlines()
X=max(len(s)for s in S)
I='#'*X+''.join(t[:-1]+' '*(X-len(t))+'\n'for t in S)+'#'*X
L=len(I)
R=range(L)
B=[0]*L
C=[0]*L
for p in R:
 if'@'!=I[p]:continue
 for d in(1,-1,X,-X):
  q=p;c=7;b=100.
  while 1:
   q+=d;a=I[q];B[q]+=b;C[q]|=c
   if a in'\/':d=(ord(a)/30-2)*X/d;b*=.8
   elif a in'RGB':c&=ord(a)/5-12
   elif a in'><^V':d={'>':1,'<':-1,'^':-X,'V':X}[a];b/=2
   elif' '!=a:break
print''.join(I[p]if' '!=I[p]else' bgcrmyw'[C[p]]for p in R[X:-X])
i=0
for p in R:
 if'?'==I[p]:i+=1;print'#%d:'%i,'%.0f%%'%B[p],[0,'Blue','Green','Cyan','Red','Magenta','Yellow','White'][C[p]]

Düzenleme: Sondaki boşluklara gerek kalmaması için düzeltildi.


Neredeyse - ancak test senaryosu sonucu yanlış. Bakınız: ideone.com/kUTxE . Yine de +1, yine de, harika !!!
Ry-

@minitech: Bunun sondaki boşlukların olmamasıyla ilgili olduğunu düşünüyorum. Kodum, her satırın aynı uzunlukta olduğunu varsayar ve gerekirse boşluklarla doldurulur. Durum böyle değil mi? Eğer öyleyse, o zaman nereden biliyorsunuz, örneğin, üst ışık kaynağı sağa ne kadar gidiyor?
Keith Randall

Dolgu için en uzun çizginin uzunluğunu kullanarak, tüm ızgarayı anlayabilirsiniz. Bununla birlikte, boşluklarla doldurulduğunda bile, bu (giriş # 4) verir: ideone.com/kUTxE
Ry-

@minitech: 4. satırda bir boşluk eksik. Sondaki boşlukları gerektirmeyen kodumu düzeltirim.
Keith Randall

Oh, wow işe yarıyor !! Aferin. Ama evet, dolgu gerektirmezse iyi olurdu.
Ry-

2

F #

#nowarn "0025"

open System

type MirrorDirection = bool
type LightDirection = bool * bool
type Sq =
  | Air // [ ]
  | Mirror of MirrorDirection // [/] [\]
  | FilterR
  | FilterG
  | FilterB
  | Sensor // [?]
  | Combine of LightDirection // [^] [v] [<] [>]
  | Emitter // [@]
  | Wall of Char // non-whitespace

let [ mL; mR ] : MirrorDirection list = [ true; false ]
(* true T^/
       F</>F
        /vT   false
 *)
let [ dN; dS; dW; dE ] : LightDirection list = [ true, true; false, true; true, false; false, false ]
let bounce (m : MirrorDirection) ((a, b) : LightDirection) =
  m <> a, not b

let dv (a : LightDirection) =
  if a = dN then 0, -1
  elif a = dS then 0, 1
  elif a = dW then -1, 0
  else 1, 0

let fo<'a> : (('a option)[,] -> 'a seq) =
  Seq.cast
  >> Seq.filter Option.isSome
  >> Seq.map Option.get

let input = Console.In.ReadToEnd().Replace("\r\n", "\n")
let sqs =
  input.Split('\n')
  |> Array.map (fun x ->
    x.ToCharArray()
    |> Array.map (
      function
      | ' ' | '\t' | '\v' -> Air
      | '/' -> Mirror mL
      | '\\' -> Mirror mR
      | 'R' -> FilterR
      | 'G' -> FilterG
      | 'B' -> FilterB
      | '?' -> Sensor
      | '^' -> Combine dN
      | 'v' -> Combine dS
      | '<' -> Combine dW
      | '>' -> Combine dE
      | '@' -> Emitter
      | x -> Wall x
    )
  )

let w =
  Array.map Array.length sqs
  |> Set.ofArray
  |> Set.maxElement
let h = sqs.Length

let ib x y = -1 < x && x < w && -1 < y && y < h

let arr = Array2D.init w h (fun x y ->
  if x < sqs.[y].Length then
    sqs.[y].[x]
  else
    Air
)

let board =
  Array2D.map (
    function
    | _ -> 0.0, 0.0, 0.0
  ) arr

let mutable rays =
  Array2D.mapi (fun x y a ->
    match a with
    | Emitter -> Some(x, y)
    | _ -> None
  ) arr
  |> fo
  |> Seq.map (fun (x, y) ->
    [|
      dN, x, y, 1., 1., 1.
      dS, x, y, 1., 1., 1.
      dW, x, y, 1., 1., 1.
      dE, x, y, 1., 1., 1.
    |]
  )
  |> Seq.reduce Array.append

for i = 0 to w * h * 2 do
  rays <-
    rays
    |> Array.map (
      (fun (dir, x, y, r, g, b) ->
        let dx, dy = dv dir
        dir, x + dx, y + dy, r, g, b
      )
      >> (fun (dir, x, y, r, g, b) ->
        if ib x y then
          match arr.[x, y] with
          | Wall _ -> Array.empty
          | Sensor -> [| dir, x, y, r, g, b |]
          | FilterR -> [| dir, x, y, r, 0., 0. |]
          | FilterG -> [| dir, x, y, 0., g, 0. |]
          | FilterB -> [| dir, x, y, 0., 0., b |]
          | Mirror d -> [| bounce d dir, x, y, r * 0.8, g * 0.8, b * 0.8 |]
          | _ -> [| dir, x, y, r, g, b |]
        else
          Array.empty
      ))
    |> Array.concat
  Array2D.mapi (fun x y a ->
    match a with
    | Combine d -> Some(x, y, d)
    | _ -> None
  ) arr
  |> fo
  |> Seq.iter (fun (x, y, d) ->
    for i = 0 to rays.Length - 1 do
      let (d', x', y', r, g, b) = rays.[i]
      if x' = x && y' = y then
        rays.[i] <- (d, x, y, r, g, b)
  )
  for d, x, y, r, g, b in rays do
    if ib x y then
      match board.[x, y] with
      | r', g', b' -> board.[x, y] <- r + r', g + g', b + b'

printfn "%s" (
  let mutable s = ""
  for y = 0 to h - 1 do
    for x = 0 to w - 1 do
      s <- s + (match arr.[x, y] with
                | Air ->
                  match board.[x, y] with
                  | r, g, b ->
                    if r + g + b = 0.0 then ' '
                    else
                      if g = 0.0 && b = 0.0 then 'r'
                      elif r = 0.0 && b = 0.0 then 'g'
                      elif r = 0.0 && g = 0.0 then 'b'
                      elif r = 0.0 then 'c'
                      elif g = 0.0 then 'm'
                      elif b = 0.0 then 'y'
                      else 'w'
                | Wall z -> z
                | Mirror z -> if z = mL then '/' else '\\'
                | FilterR -> 'R'
                | FilterG -> 'G'
                | FilterB -> 'B'
                | Sensor -> '?'
                | Combine z -> if z = dN then '^' elif z = dS then 'v' elif z = dW then '<' else '>'
                | Emitter -> '@'
                |> sprintf "%c")
    s <- s + "\n"
  s
)

Array2D.mapi (fun x y a ->
  match a with
  | Sensor -> Some(x, y)
  | _ -> None
) arr
|> fo
|> Seq.iteri (fun i (x, y) ->
  let (r, g, b) = board.[x, y]
  let desc =
    if r + g + b = 0.0 then "None"
    elif g = 0.0 && b = 0.0 then "Red"
    elif r = 0.0 && b = 0.0 then "Green"
    elif r = 0.0 && g = 0.0 then "Blue"
    elif r = 0.0 then "Cyan"
    elif g = 0.0 then "Magenta"
    elif b = 0.0 then "Yellow"
    else "White"
  let avg = int((r + g + b) * 100.0 / (match desc with
                                       | "White" | "None" -> 3.0
                                       | "Red" | "Green" | "Blue" -> 1.0
                                       | _ -> 2.0))
  printfn "#%d: %d%% %s" (i + 1) avg desc
)

Kurtulmamış ama yine de harika! +1.
Ry-
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.