Truy tìm tia 2 chiều


9

Thách thức là triển khai chương trình dò ​​tia 2 chiều, dựa trên văn bản.

Nguồn của ánh sáng trắng là @biểu tượng. R, GBlà bộ lọc ánh sáng. /\là những tấm gương có độ phản xạ 80%. ?là một cảm biến ánh sáng. >, <, ^Vkết hợp ánh sáng theo hướng thích hợp (ví dụ như nếu một màu đỏ và một màu xanh lá cây được đưa vào một >ánh sáng sẽ được phát ra về phía bên phải và nó sẽ là màu vàng). Các nhân vật không phải khoảng trắng khác hấp thụ tất cả ánh sáng. Ánh sáng được phát ra từ @các biểu tượng theo bốn hướng.

Khi chương trình được chạy, nó sẽ tạo ra đầu ra giống như đầu vào, nhưng với các tia được theo dõi. Bởi vì đây là 2 chiều và tôi đảm bảo trong đầu vào sẽ không có tia nào đi qua, nên sẽ không có vấn đề gì với điều đó. Mỗi tia nên được đại diện bởi một chữ cái; r = đỏ, g = xanh, b = xanh, c = lục lam, m = đỏ tươi, y = vàng, w = trắng. Sẽ không có bất kỳ màu sắc ternary, bao giờ. Vỏ là quan trọng để phân biệt nó với đầu vào. Sau đầu ra đó, các giá trị ánh sáng thu được bằng các dấu hỏi (theo thứ tự xuất hiện của chúng, từ trái sang phải từ trên xuống dưới) phải được xuất ra dưới dạng phần trăm và màu sắc. Ví dụ: đầu vào này:

 /                  @
                    -
 \R>                 ?

 @B/

Nên cho đầu ra:

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

#1: 72% Magenta

Một điểm quan trọng khác cần lưu ý - khi hai màu được kết hợp bằng cách sử dụng "lăng kính" (mũi tên), cường độ của ánh sáng kết hợp sẽ trở thành cường độ trung bình của hai màu. Đầu ra phải chính xác như được chỉ định (ví dụ #x: [x] [x] x% Color ).

Nếu ngôn ngữ của bạn không thể đọc từ STDIN và ghi vào STDOUT, hãy tạo một hàm (ẩn danh hoặc lambda khi khả dụng) chấp nhận đầu vào làm đối số và trả về kết quả.

Chỉ thị cho trình biên dịch, các cấu trúc cần thiết hoặc được khuyến nghị cho tất cả hoặc hầu hết các chương trình được tạo bằng ngôn ngữ, v.v. có thể được bỏ qua. Ví dụ: #includevà các usingchỉ thị (nhưng không #define) có thể bị xóa trong các ngôn ngữ kiểu C, #/usr/bin/perl -optionstrong Perl và

 Module Module1
      Sub Main()
      End Sub
 End Module

trong VB.NET chẳng hạn. Nếu bạn nhập không gian tên hoặc thêm bao gồm các chỉ thị, xin vui lòng lưu ý chúng trong câu trả lời của bạn.

Bây giờ đã đủ khó chưa? :)


Liên quan đến Code Golf: Laser trên Stack Overflow.
dmckee --- ex-moderator mèo con

Hành vi của các gương trong ví dụ của bạn không có ý nghĩa. Bạn có một \ (thoát bị hỏng) ảnh hưởng đến ánh sáng đi thẳng qua nó. Có vẻ hợp lý hơn nhiều khi có ánh sáng chiếu vào cùng một hàng với gương và để lại trên cùng một cột, hoặc ngược lại. Tương tự như vậy >là bắt ánh sáng đi thẳng qua nó. Và nếu wtừ trên xuống đi qua đó R, thì btừ dưới lên. Cuối cùng (tôi nghĩ), bạn đã sai về các tia không giao nhau. Để đưa ra một ví dụ một dòng, đầu ra chính xác sẽ là @R> B@gì?
Peter Taylor

Tại sao bạn thêm một w ngẫu nhiên và phá vỡ tất cả các khoảng cách? Và ánh sáng không chiếu thẳng qua nó, không chắc ý bạn là gì.
Ry-

@minitech, @ở phía dưới bên trái phát ra ánh sáng theo cả bốn hướng, phải không? Vì vậy, đặc biệt, nó phát ra rằng w. Và tôi đã không phá vỡ bất kỳ khoảng cách nào, ít nhất là được hiển thị trong Chromium. Khi đi thẳng qua nó, bản chỉnh sửa của tôi có thể làm rõ điều đó.
Peter Taylor

5
minitech: Là một lời khuyên cho các nhiệm vụ trong tương lai: Trước tiên, hãy hỏi ý kiến ​​trong Sandbox hoặc Puzzle Lab , điều này đủ để giải quyết sự không nhất quán và các vấn đề ban đầu với các nhiệm vụ. Bằng cách đó, một khi bạn đăng nhiệm vụ ở đây, bạn sẽ biết nó đã được kiểm tra (và có thể được thực hiện) bởi một số người khác.
Joey

Câu trả lời:


2

Python, 602 559 614 ký tự

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

Chỉnh sửa: đã sửa nên không cần dấu cách.


Hầu như - nhưng kết quả trường hợp thử nghiệm là không chính xác. Xem: ideone.com/kUTxE . Dù sao đi nữa, thật tuyệt vời !!!
Ry-

@minitech: Tôi nghĩ rằng điều này có liên quan đến việc thiếu không gian dấu. Mã của tôi giả định rằng mỗi hàng có cùng độ dài, được đệm bằng khoảng trắng nếu cần thiết. đây không phải là trường hợp à? Nếu vậy, làm thế nào để bạn biết, ví dụ, nguồn sáng phía trên đi về bên phải bao xa?
Keith Randall

Sử dụng độ dài của dòng dài nhất để đệm nó, bạn có thể tìm ra toàn bộ lưới. Tuy nhiên, ngay cả khi được đệm bằng khoảng trắng, nó vẫn cung cấp điều này (đầu vào số 4): ideone.com/kUTxE
Ry-

@minitech: Bạn đang thiếu một khoảng trống trên dòng thứ 4. Tôi sẽ sửa mã của mình để không yêu cầu dấu cách.
Keith Randall

Oh, wow nó hoạt động !! Làm tốt lắm. Nhưng vâng, nó sẽ tốt nếu nó không yêu cầu đệm.
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 nhưng vẫn tuyệt vời! +1.
Ry-
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.