二维射线追踪


9

挑战是要实现基于文本的二维射线跟踪程序。

白光的来源是@符号。RGB是光的过滤器。/\与80%的反射率的反射镜。?是一个光传感器。><^V在适当的方向相结合的光(例如,如果一个红色和一个绿色来到一个>的光将朝向右侧被发射,这将是黄色)。其他非空白字符会吸收所有光。@符号从四个方向发射光。

运行该程序时,它应产生与输入相同的输出,但带有光线。因为这是二维的,并且我保证输入中不会有任何光线交叉,所以不会有任何问题。每条射线应以字母表示;r =红色,g =绿色,b =蓝色,c =青色,m =品红色,y =黄色,w =白色。永远不会有任何三元颜色。套管对于区分输入和输入很重要。在输出之后,应将问号捕获的光的值(从出现的顺序,从左到右,从上到下)输出为百分比和颜色。例如,此输入:

 /                  @
                    -
 \R>                 ?

 @B/

应该给出输出:

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

#1: 72% Magenta

还要注意的另一个重要点-当使用“棱镜”(箭头)组合两种颜色时,组合后的光的强度变为两种颜色的平均强度。输出必须完全符合规定(例如#x:[x] [x] x%Color)。

如果您的语言无法从STDIN读取并向STDOUT写入,请创建一个函数(将匿名或lambda可用)接受该输入作为参数并返回结果。

可以省略针对编译器的指令,使用该语言创建的所有或大多数程序所需或推荐的结构等。例如,#includeusing指令(但不是#define)可以在C语言风格的语言被除去,#/usr/bin/perl -options在Perl和

 Module Module1
      Sub Main()
      End Sub
 End Module

例如在VB.NET中。如果您导入名称空间或添加包含指令,请在您的答案中注意它们。

现在够难了吗?:)


Code Golf相关堆栈溢出时的激光
dmckee ---前主持人小猫,

在您的示例中,镜像的行为没有任何意义。您有一个\(转义符被打断了)会影响光线,光线会直接越过它。光线与镜子排在同一行,并留在同一列,反之亦然,这似乎更为明智。同样,>正在捕获的光线会直接越过它。如果w从顶部开始通过,则底部也R应该通过b。最后(我认为),您对光线不交叉是错误的。举一个单行示例,正确的输出是@R> B@什么?
彼得·泰勒

为什么要添加随机w并破坏所有间距?光线并没有直射过去,不确定您的意思。
Ry- 2011年

@minitech,它@的左下角在所有四个方向发光,不是吗?因此,特别是它发出了w。而且我没有打破任何间距,至少在Chromium中是如此。至于直截了当,我的编辑可能会清除它。
彼得·泰勒

5
minitech:作为对未来任务的建议:首先在SandboxPuzzle Lab中征求意见,这足以消除工作中的矛盾和早期问题。这样,将任务发布到此处后,您将知道其他任务已经对其进行了检查(并可能已实施)。
乔伊,

Answers:


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- 2011年

@minitech:我认为这与缺少尾随空格有关。我的代码假定每一行的长度相同,并在必要时用空格填充。不是吗?如果是这样,那么您如何知道例如上部光源向右走多远?
基思·兰德尔

使用最长的线的长度来填充它,您可以找出整个网格。但是,即使用空格填充,它也会显示以下内容(输入#4):ideone.com/kUTxE
Ry- 2011年

@minitech:您在第4行上缺少空格。我将修复代码,以免尾随空格。
基思·兰德尔

哦,它确实有效!!做得好。但是,是的,如果它不需要填充,那就太好了。
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
)

空洞的,但仍然很棒!+1。
Ry-
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.