Rayonnement tridimensionnel

9

Le défi consiste à mettre en œuvre un programme de traçage de rayons bidimensionnel, basé sur du texte.

Les sources de lumière blanche sont des @symboles. R, GEt Bsont des filtres de lumière. /et \sont des miroirs avec une réflectivité de 80%. ?est un capteur de lumière. >, <, ^Et Vcombiner la lumière dans la direction appropriée (par exemple , si un rouge et un vert est venu en >la lumière serait émise vers la droite et il serait jaune). D'autres caractères non blancs absorbent toute la lumière. La lumière est émise par les @symboles dans quatre directions.

Lorsque le programme est exécuté, il doit produire une sortie identique à l'entrée, mais avec des rayons tracés. Parce que c'est bidimensionnel et que je garantis dans l'entrée qu'aucun rayon ne traversera jamais, cela ne posera aucun problème. Chaque rayon doit être représenté par une lettre; r = rouge, g = vert, b = bleu, c = cyan, m = magenta, y = jaune, w = blanc. Il n'y aura jamais de couleurs ternaires. Le boîtier est important pour le différencier de l'entrée. Après cette sortie, les valeurs de lumière capturées par les points d'interrogation (dans l'ordre de leur apparence, de gauche à droite de haut en bas) doivent être sorties sous forme de pourcentages et de couleurs. Par exemple, cette entrée:

 /                  @
                    -
 \R>                 ?

 @B/

Devrait donner la sortie:

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

#1: 72% Magenta

Un autre point important à noter - lorsque deux couleurs sont combinées à l'aide d'un "prisme" (les flèches), la force de la lumière combinée devient la force moyenne des deux. La sortie doit être exactement telle que spécifiée (par exemple #x: [x] [x] x% Color ).

Si votre langue ne peut pas lire à partir de STDIN et écrire dans STDOUT, créez une fonction (anonyme ou lambda si disponible) qui accepte l'entrée comme argument et renvoie le résultat.

Les directives vers le compilateur, les structures requises ou recommandées pour tous ou la plupart des programmes créés dans le langage, etc. peuvent être omises. Par exemple, #includeet les usingdirectives (mais pas #define) peuvent être supprimées dans les langages de style C, #/usr/bin/perl -optionsen Perl et

 Module Module1
      Sub Main()
      End Sub
 End Module

dans VB.NET, par exemple. Si vous importez des espaces de noms ou ajoutez des directives include, veuillez les noter dans votre réponse.

Est-ce déjà assez difficile? :)

Ry-
la source
Lié à Code Golf: Lasers on Stack Overflow.
dmckee --- chaton ex-modérateur
Le comportement des miroirs dans votre exemple n'a pas de sens. Vous avez un \ (l'échappement est cassé) affectant la lumière qui passe directement devant lui. Il semblerait beaucoup plus sensé que la lumière entre dans la même rangée que le miroir et la laisse sur la même colonne, ou vice versa. De même, la >capture la lumière qui passe devant elle. Et si le whaut passe par là R, il en va de même pour ble bas. Enfin (je pense), vous avez tort de ne pas traverser les rayons. Pour donner un exemple sur une ligne, quelle serait la sortie correcte @R> B@?
Peter Taylor
Pourquoi avez-vous ajouté un w aléatoire et brisé tout l'espacement? Et la lumière ne passe pas directement devant elle, je ne sais pas ce que tu veux dire.
Ry-
@minitech, qui @en bas à gauche émet de la lumière dans les quatre directions, n'est-ce pas? Donc, en particulier, cela émet cela w. Et je n'ai rompu aucun espacement, du moins tel que rendu en chrome. En ce qui concerne le passage direct, mon montage peut clarifier cela.
Peter Taylor
5
minitech: Comme conseil pour les tâches futures: demandez d'abord des commentaires dans le bac à sable ou le laboratoire de puzzle qui devraient suffire à aplanir les incohérences et les premiers problèmes avec les tâches. De cette façon, une fois que vous aurez publié la tâche ici, vous saurez qu'elle a déjà été vérifiée (et peut-être implémentée) par d'autres.
Joey

Réponses:

2

Python, 602 559 614 caractères

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

Edit: corrigé pour qu'il ne nécessite pas d'espaces de fin

Keith Randall
la source
Presque - mais le résultat du scénario de test est incorrect. Voir: ideone.com/kUTxE . +1 quand même, c'est super !!!
Ry-
@minitech: Je pense que cela a à voir avec le manque d'espaces de fuite. Mon code suppose que chaque ligne a la même longueur, complétée avec des espaces si nécessaire. N'est-ce pas le cas? Si oui, comment savez-vous, par exemple, jusqu'où la source de lumière supérieure va vers la droite?
Keith Randall
En utilisant la longueur de la ligne la plus longue pour la remplir, vous pouvez déterminer la grille entière. Cependant, même lorsqu'il est rempli d'espaces, il donne ceci (entrée n ° 4): ideone.com/kUTxE
Ry-
@minitech: il vous manque un espace sur la 4ème ligne. Je vais corriger mon code pour ne pas exiger d'espaces de fin.
Keith Randall
Oh, wow ça marche !! Bon travail. Mais oui, ce serait bien si cela ne nécessitait pas de rembourrage.
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
)
Ming-Tang
la source
Non golfé mais toujours génial! +1.
Ry-