การติดตามรังสี 2 มิติ


9

ความท้าทายคือการใช้โปรแกรมติดตามเรย์แบบ 2 มิติซึ่งเป็นข้อความ

แหล่งกำเนิดแสงสีขาวเป็น@สัญลักษณ์ R, GและBตัวกรองแสง /และ\เป็นกระจกที่มีการสะท้อนแสง 80% ?เป็นเซ็นเซอร์วัดแสง >, <, ^และVรวมแสงในทิศทางที่เหมาะสม (เช่นถ้าสีแดงและสีเขียวมาเป็น>แสงจะถูกปล่อยออกไปทางขวาและมันจะเป็นสีเหลือง) ตัวละครที่ไม่ใช่ช่องว่างอื่น ๆ ดูดซับแสงทั้งหมด แสงถูกปล่อยออกมาจาก@สัญลักษณ์ในสี่ทิศทาง

เมื่อโปรแกรมทำงานก็ควรสร้างผลลัพธ์เช่นเดียวกับอินพุต แต่มีรังสีติดตาม เพราะนี่คือ 2 มิติและฉันรับประกันในการป้อนข้อมูลที่รังสีจะไม่เคยข้ามจะไม่มีปัญหากับสิ่งนั้น แต่ละเรย์ควรแสดงด้วยตัวอักษร r = แดง, g = เขียว, b = น้ำเงิน, c = cyan, m = ม่วงแดง, y = เหลือง, w = ขาว จะไม่มีสีประกอบไปด้วยเลย ปลอกเป็นสิ่งสำคัญที่แตกต่างจากอินพุต หลังจากเอาต์พุตนั้นค่าของแสงที่จับด้วยเครื่องหมายคำถาม (เรียงตามลำดับจากซ้ายไปขวาบนลงล่าง) ควรแสดงผลลัพธ์เป็นเปอร์เซ็นต์และสี ตัวอย่างเช่นอินพุตนี้:

 /                  @
                    -
 \R>                 ?

 @B/

ควรให้ผลลัพธ์:

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

#1: 72% Magenta

อีกจุดสำคัญที่ควรทราบ - เมื่อรวมสองสีเข้าด้วยกันโดยใช้ "ปริซึม" (ลูกศร) ความแข็งแรงของแสงที่รวมกันจะกลายเป็นความแข็งแรงเฉลี่ยของทั้งสอง ผลลัพธ์จะต้องตรงตามที่ระบุไว้ (เช่น #x: [x] [x] x% Color )

หากภาษาของคุณไม่สามารถอ่านจาก STDIN และเขียนไปยัง STDOUT ให้สร้างฟังก์ชั่น (ไม่ระบุชื่อหรือแลมบ์ดาเมื่อมี) ที่รับอินพุตเป็นอาร์กิวเมนต์และส่งกลับผลลัพธ์

คำสั่งสำหรับคอมไพเลอร์โครงสร้างที่จำเป็นหรือแนะนำสำหรับโปรแกรมทั้งหมดหรือส่วนใหญ่ที่สร้างขึ้นในภาษา ฯลฯ สามารถละเว้นได้ ตัวอย่างเช่น#includeและusingคำสั่ง (แต่ไม่ใช่#define) อาจถูกลบในภาษา C-style #/usr/bin/perl -optionsใน Perl และ

 Module Module1
      Sub Main()
      End Sub
 End Module

ใน VB.NET เช่น หากคุณนำเข้าเนมสเปซหรือเพิ่มคำสั่งรวมถึงโปรดทราบพวกเขาในคำตอบของคุณ

มันยากพอไหมตอนนี้? :)


เกี่ยวข้องกับCode Golf: เลเซอร์บน Stack Overflow
dmckee --- ผู้ดูแลอดีตลูกแมว

พฤติกรรมของกระจกเงาในตัวอย่างของคุณไม่สมเหตุสมผล คุณมี \ (การหลบหนีถูกทำลาย) ส่งผลกระทบต่อแสงซึ่งผ่านตรงมา ดูเหมือนจะเหมาะสมกว่าที่จะมีแสงเข้ามาในแถวเดียวกับกระจกและทิ้งไว้ในคอลัมน์เดียวกันหรือกลับกัน ในทำนองเดียวกัน>แสงคือการจับภาพซึ่งจะผ่านตรงมา และถ้าwจากด้านบนผ่านสิ่งRนั้นbมาจากด้านล่าง ในที่สุด (ฉันคิดว่า) คุณผิดเกี่ยวกับรังสีที่ไม่ผ่าน เพื่อให้ตัวอย่างหนึ่งบรรทัดผลลัพธ์ที่ถูกต้องจะเป็น@R> B@อย่างไร
Peter Taylor

ทำไมคุณถึงเพิ่ม w แบบสุ่มและทำลายระยะห่างทั้งหมด? และแสงจะไม่ผ่านไปทางตรงไม่แน่ใจว่าคุณหมายถึงอะไร
Ry-

@minitech นั้นที่@มุมซ้ายล่างเปล่งแสงทั้งสี่ทิศทางใช่ไหม? wดังนั้นโดยเฉพาะอย่างยิ่งมันปล่อยออกมาว่า และฉันไม่ได้เว้นระยะห่างอย่างน้อยก็อย่างน้อยก็แสดงผลใน Chromium เมื่อผ่านไปจริง ๆ การแก้ไขของฉันอาจชัดเจนขึ้น
Peter Taylor

5
minitech: เป็นคำแนะนำสำหรับงานในอนาคต: ขอความคิดเห็นในSandboxหรือPuzzle Labก่อนซึ่งน่าจะเพียงพอสำหรับการแก้ไขปัญหาความไม่สอดคล้องและปัญหาเบื้องต้นของงาน ด้วยวิธีนี้เมื่อคุณโพสต์งานที่นี่คุณจะรู้ว่ามีการตรวจสอบแล้ว (และอาจนำไปใช้) โดยบางคนแล้ว
Joey

คำตอบ:


2

Python, 602 559 614 ตัวอักษร

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]]

แก้ไข: แก้ไขแล้วดังนั้นจึงไม่ต้องการช่องว่างต่อท้าย


เกือบ - แต่ผลการทดสอบไม่ถูกต้อง ดู: ideone.com/kUTxE +1 อย่างไรก็ตามยังดีมาก !!!
Ry-

@minitech: ฉันคิดว่ามันเกี่ยวข้องกับการขาดช่องว่างต่อท้าย รหัสของฉันสมมติว่าแต่ละแถวมีความยาวเท่ากันเบาะมีช่องว่างหากจำเป็น นั่นไม่ใช่กรณีหรือไม่ ถ้าเป็นเช่นนั้นคุณจะรู้ได้อย่างไรเช่นไกลแค่ไหนที่แหล่งกำเนิดแสงด้านบนไปทางขวา?
Keith Randall

การใช้ความยาวของบรรทัดที่ยาวที่สุดในการวางคุณสามารถคำนวณกริดทั้งหมดได้ อย่างไรก็ตามแม้ว่าจะมีช่องว่าง แต่ก็ให้สิ่งนี้ (อินพุต # 4): ideone.com/kUTxE
Ry-

@minitech: คุณไม่มีที่ว่างในบรรทัดที่ 4 ฉันจะแก้ไขรหัสของฉันไม่ต้องใช้ช่องว่างต่อท้าย
Keith Randall

โอ้วววววมันใช้งานได้ !! ทำได้ดีมาก แต่ใช่มันจะดีถ้ามันไม่ต้องใช้ช่องว่างภายใน
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
)

Ungolfed แต่ก็ยังยอดเยี่ยม! +1
Ry-
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.