Código (Mini) Golfe

50

Dada a vista lateral de um campo de minigolfe e a força do balanço, determine se a bola entrará no buraco.


Um curso será neste formato:

      ____       ____ _   
   __/    \     /    U \  
__/        \   /        \_
            \_/           

A bola começa diretamente antes do primeiro pedaço de solo à esquerda e segue o contorno do percurso até atingir o buraco (uma maiúscula Uabaixo do nível atual do solo). Se atingir o furo, produza um valor de verdade. A força do swing será a velocidade inicial da bola. A bola se move para o próximo personagem à direita a cada iteração, e a velocidade é alterada dependendo do personagem em que está agora. Se a velocidade atingir 0ou menos antes do furo, produza um valor de falsey.

  • _ diminui a velocidade em 1
  • / diminui a velocidade em 5
  • \ aumenta a velocidade em 4

Os cursos podem opcionalmente ser preenchidos com espaços. A potência do balanço será sempre um número inteiro positivo.

Você não precisa se preocupar com a bola indo muito rápido para entrar no buraco, rolando para trás ou pulando / saltando de colinas.

Casos de teste

Input: 27
      ____       ____ _   
   __/    \     /    U \  
__/        \   /        \_
            \_/           
Output: true

----------

Input: 26
      ____       ____ _   
   __/    \     /    U \  
__/        \   /        \_
            \_/           
Output: false

----------

Input: 1

U
Output: true

----------

Input: 1
_ 
 U
Output: false

----------

Input: 22

     /U
    /  
   /   
  /    
\/     
Output: true

----------

Input: 999
_       _
 \     / 
  \   /  
   \ /   
    U    
Output: true

----------

Input: 5
  /
/U 
Output: false

----------

Input: 9

/\/\/\/\/U
Output: false

----------

Input: 16

_/\                                         _
   \      __       /\/\/\                  / 
    \    /  \     /      \                /  
     \__/    \   /        \____________ _/   
              \_/                      U     

Output: true

Este é o código mini-golfe, a resposta mais curta em bytes ganha!

user81655
fonte
1
Se o seu idioma tiver bons recursos de matriz, você poderá transformar a entrada em um fluxo de operações ( \_/) com as seguintes etapas: divida em matriz de linhas, gire, aplane, aplique espaços.
Cyoce 20/01
1
Este é realmente mais de um mecanismo de controle fixo de um campo de golfe: P
Zach Gates,
24
Eu gosto que \/\/\/\/\/é um curso mais eficiente do que __________.
ezrast
2
Era isso que eu pensava, 4 abaixo, 5 acima, então 0,5 deve ser mediano. Oh, apartamento é 1?
precisa saber é o seguinte
Cada linha de um percurso sempre terá o mesmo comprimento (com espaços à direita preenchendo o final de linhas mais curtas)?
precisa saber é o seguinte

Respostas:

17

Pitão, 27 bytes

.Am<sXsd"_\ /"[1_4Z5)Q._C.z

Demonstração

Esse código faz algo muito inteligente e nem um pouco seguro para o tipo X. Confira abaixo.

Explicação:

.Am<sXsd"_\ /"[1_4Z5)Q._C.z
                               Implicit: Z = 0, Q = eval(input())
                               Q is the initial power.
                         .z    Take all input, as a list of lines.
                        C      Transpose, giving all columns.
                      ._       Form all prefixes.
  m                            Map over the prefixes.
      sd                       Concatenate the prefix.
     X  "_\ /"[1_4Z5)          Change '_' to 1, '\' to -4, ' ' to 0, and '/' to 5.
                               In particular, 'U' is left unchanged.
    s                          Reduce on addition.
                               If all elements were numbers,
                               this results in the total change in power.
                               If there was a 'U', it results in a string.
   <                 Q         If the previous result was a number, this compares
                               it with the initial input to see if the ball is
                               still rolling.
                               If the previous result was a string, this slices off
                               the first Q characters, which always has a truthy
                               result.
.A                             Test whether all of the prefixes mapped to a thruthy
                               result.
isaacg
fonte
Eu posso estar perdendo alguma coisa, mas para Q? Ou seja, o último exemplo pode causar alguns problemas?
flindeberg
@flindeberg Não é assim que funciona. O < ... Qfunciona como uma comparação numérica até o buraco, não uma fatia. Depois do buraco, o que importa é que o resultado seja verdadeiro.
Isaacg
14

Haskell, 111 109 bytes

import Data.List
g"_"=1
g"/"=5
g _= -4 
f n=all(>0).scanl(-)n.map g.fst.span(/="U").(>>=words).transpose.lines

Exemplo de uso:

*Main> f 27 "      ____       ____ _   \n   __/    \\     /    U \\  \n__/        \\   /        \\_\n            \\_/           "
True
*Main> f 26 "      ____       ____ _   \n   __/    \\     /    U \\  \n__/        \\   /        \\_\n            \\_/           "
False

Como funciona:

                            lines  -- split into list of lines at nl
                       transpose   -- transpose
                  (>>=words)       -- turn each line into words (i.e. remove spaces)  
            fst.span(/="U")        -- take all words up to but excluding "U"
         map g                     -- turn each word into the speed modifier
    scanl(-)n                      -- build list of partial sums starting with n
                                   --   note: speed modifiers are negative so we
                                   --   use (-) with scanl to build sums 
all(>0)                            -- return true if all sums are greater than 0                                 

Edit: @ user81655 encontrado 2 bytes para salvar. Obrigado!

nimi
fonte
7

Ruby, 104 87 caracteres

->s,t{t.lines.map(&:bytes).transpose.map{|o|(c=o.max)==85||s<0?break: s+=c*3%14-6}
s>0}

Exemplo de execução:

2.1.5 :001 > track = '      ____       ____ _   
2.1.5 :002'>    __/    \     /    U \  
2.1.5 :003'> __/        \   /        \_
2.1.5 :004'>             \_/           
2.1.5 :005'> '
 => "      ____       ____ _   \n   __/    \\     /    U \\  \n__/        \\   /        \\_\n            \\_/           \n" 

2.1.5 :006 > ->s,t{t.lines.map(&:bytes).transpose.map{|o|(c=o.max)==85||s<0?break: s+=c*3%14-6};s>0}[27, track]
 => true 

2.1.5 :007 > ->s,t{t.lines.map(&:bytes).transpose.map{|o|(c=o.max)==85||s<0?break: s+=c*3%14-6};s>0}[26, track]
 => false 
homem a trabalhar
fonte
6

Japt, 38 bytes

Vz r"%s|U[^]*" ¬e@UµX¥'_?1:X¥'/?5:-4 ¬

Try it here!

Batendo CJam!

Explicação

Basicamente, pega a entrada da string, gira 90 graus no sentido horário, retira espaços e novas linhas, remove o orifício e tudo o que se segue e se divide ao longo de caracteres. Em seguida, verifica se a bola chega a zero ou abaixo usando a everyfunção

Mama Fun Roll
fonte
Eu acho que `` deve ser positivo (descrição parece errado)
isaacg
Eu não acho que isso funcione. Imagine isto: uma série de pistas aumenta a velocidade da bola para -2, mas depois há uma rede +4 mais tarde. A soma refletiria +2, então a bola chegou. Na realidade, nunca chegaria à seção positiva depois de alcançar os negativos.
precisa saber é
Eu acho que resolvi o problema.
Mama Fun Roll
Isso é um botão fresco;)
J Atkin
Agradável! Então, jogando golfe ... A barra invertida dupla é substituível por %e >0pode ser substituída por ¬, uma vez que o sqrt de um número não positivo é sempre falso ( 0 -> 0, -1 -> NaN).
ETHproductions
6

CJam, 40 39 bytes

liqN/:.e>'U/0="\_/"[4W-5]er{1$+}/]:e<0>

A entrada tem o poder na primeira linha e o curso começa na segunda linha. A saída é 0ou 1.

Teste aqui.

Explicação

li    e# Read power and convert to integer.
qN/   e# Read course and split into lines.
:.e>  e# Flatten course by folding maximum over columns.
'U/   e# Split around the hole.
0=    e# Keep the first chunk.
"\_/"[4W-5]er
      e# Replace \, _, / with 4, -1, 5, respectively.
{     e# For each of those costs...
  1$+ e#   Copy the previous power and add the cost.
}/    e# This leaves all partial sums on the stack.
]     e# Wrap them in an array.
:e<   e# Find the minimum.
0>    e# Check whether it's positive.
Martin Ender
fonte
5

Retina, 82 81 77 74 68 67 68 bytes

+`(?<=(.)*) (?=.*¶(?<-1>.)*(.))
$2
\\
>>>>
+`>_|>{5}/|>¶

^>*U

Experimente online

  • A entrada é representada em uma base unária , como n >s - por exemplo, 4 é >>>>\n. (isso é legal?)
  • +`(?<=(.)*) (?=.*¶(?<-1>.)*(.)) $2 - achatar o percurso - substituir espaços pelo caractere abaixo deles.

    Após esta etapa, os dados ficarão assim:

    >>>>>>>>>>>>>>>>>>>>>>>>>>
    __/__/____\\\_///____U_\\_
    __/__/    \\\_///    U \\_
    __/        \\_//        \_
                \_/           
    

    Nós podemos simplesmente ignorar tudo depois do primeiro U, não chegaremos lá de qualquer maneira.

  • > representam um passo que estamos autorizados a dar, ou a energia restante.
  • Substitua cada um \por quatro >- uma inclinação nos dá energia adicional.
  • Loop: remova contenciosamente >_ou >>>>>/até não sobrar mais nada. _s e /s consomem energia.
  • Finalmente, tente combinar ^>*U- verifique se podemos alcançar Ucom energia positiva (ou sem energia).
    Isso produzirá 0ou 1.

Outra opção de fechamento com 91 79 bytes é:

+`(?<=¶(.)*) (?=.*¶(?<-1>.)*(.))
$2
^(>)+\n(?<-1>_|/(?<-1>){4}|\\(?<1>){5})+U

Experimente online

Essa é a mesma abordagem, mas com um grupo de equilíbrio em vez de uma substituição controversa.

Tenho certeza de que ambos podem ser jogados ainda mais, então qualquer um deles pode acabar mais curto.

Kobi
fonte
1
Sim, a entrada unária é legítima (a menos que o desafio especifique "decimal"), embora eu provavelmente usasse 0ou 1como o dígito se isso não gerar bytes adicionais.
Martin Ender
1
Bem-vindo ao PPCG, estou muito feliz em vê-lo aqui! :) (E usando Retina também.)
Martin Ender
Certo! Estava na lista de perguntas mais quentes e parecia divertido. Eu pensei que eu iria dar-lhe uma tentativa :-)
Kobi
3

ES6, 117 bytes

(c,p)=>c.split`
`.map(s=>[...s.slice(0,c.match(/^.*U/m)[0].length-1)].map(c=>p+=c=='/'?-5:'    \\'.indexOf(c)))&&p>0

Ungolfed:

function hole(course, power) {
    width = course.match(/^.*U/m)[0].length - 1; // calculate width to hole
    lines = course.split("\n");
    for (i = 0; i < lines.length; i++) {
        line = lines[i].slice(0, width); // ignore extraneous parts of the course
        for (j = 0; j < line.length; j++) {
            switch (line[j]) { // accumulate remaining power
            case '/': power -= 5; break;
            case '\\': power += 4; break;
            case ' ': break;
            default: power--; break;
            }
        }
    }
    return power > 0;
}

Editar: salvou 4 bytes graças a ՊՓԼՃՐՊՃՈԲՍԼ.

Neil
fonte
@ ՊՓԼՃՐՊՃՈԲՍԼ Obrigado, eu continuo tentando otimizar a velocidade ...
Neil
3

JavaScript (ES6), 108 107 106 bytes

Essa é a solução que surgiu quando criei o desafio.

(p,c)=>[...(l=c.split`
`)[w=0]].map((_,i)=>l.map(t=>(g=t[i])-1|p<=0?0:p-=g>"]"?1:g>"U"?-4:g>"/"?w=1:5))&&w

Explicação

Toma o poder como um número e o curso como uma corda. Retorna 1para trueou 0para false. O percurso deve ser preenchido com espaços.

(p,c)=>
  [...(l=c.split`
`)                          // l = array of lines
  [w=0]]                    // w = true if the ball has entered the hole
.map((_,i)=>                // for each index i
  l.map(t=>                 // for each line t
    (g=t[i])                // g = the character at the current index
    -1|p<=0?0:              // do nothing if g is a space or the ball has no speed left
    p-=
      g>"]"?1               // case _: subtract 1 from p
      :g>"U"?-4             // case \: add 4 to p
      :g>"/"?w=1            // case U: set w to true (it doesn't matter what happens to p)
      :5                    // case /: subtract 5 from p
  )
)
&&w                         // return w

Teste

var solution = (p,c)=>[...(l=c.split`
`)[w=0]].map((_,i)=>l.map(t=>(g=t[i])-1|p<=0?0:p-=g>"]"?1:g>"U"?-4:g>"/"?w=1:5))&&w
Power = <input type="number" id="power" value="16" /><br />
<textarea id="course" rows="6" cols="50">_/\                                         _
   \      __       /\/\/\                  / 
    \    /  \     /      \                /  
     \__/    \   /        \____________ _/   
              \_/                      U     </textarea><br />
<button onclick="result.textContent=solution(+power.value,course.value)">Go</button>
<pre id="result"></pre>

user81655
fonte
3

Python (3.5) 169 160 bytes

Uma solução recursiva sem a função de transposição (zip)

def f(c,p):c=c.splitlines();l=len(c);f=lambda x,h,v:v if'U'==c[h][x]or v<1 else f(x+(h==l-1),(h+1)%l,v+{"_":-1,"\\":4,"/":-5," ":0}[c[h][x]]);return f(0,0,p)>0

Ungolfed

c para curso, p para potência, v para velocidade, h para altura

def f(c,p):
    c=c.splitlines()
    l=len(c)
    tmp = {"_":-1,"\\":4,"/":-5," ":0}
    f=lambda x,h,v:v if'U'==c[h][x]or v<1 else f(x+(h==l-1),(h+1)%l,v+tmp[c[h][x]])
    return f(0,0,p)>0

Uso

f(16,"_/\                                         _\n   \      __       /\/\/\                  / \n    \    /  \     /      \                /  \n     \__/    \   /        \____________ _/   \n              \_/                      U     ")
f(9,"/\/\/\/\/U")
Erwan
fonte
2

Pitão, 35 bytes

VC.z=-Q@(1_4 5)x"_\\/"JrN6IqJ\U>Q_5

Explicação

                                    - Autoassign Q = eval(input())
                                    - Autoassign .z = rest of input
VC.z                                - For N in zip(*.z)
    =-Q                             - Q -= ...
                      JrN6          - Autoassign J to N.strip() (get rid of spaces)
       @(1_4 5)x"_\\/"              - {"_":1, "\\": -4, "/": 5, "U":5}[J] ("U" isn't defined but that's what it is according to how str.index works)
                          IqJ\U     - If J == "U"
                               >Q_5 - print Q > -5 ()
Azul
fonte
1

Ruby, 85 caracteres

->i,s{s.lines.map(&:bytes).transpose.any?{|o|(c=o.max)==85||i<0||!(i+=c*3%14-6)};i>0}

Resposta adaptada do @ manatwork

Connor Clark
fonte
1

JavaScript, 266 263 244 bytes

(s,a)=>{var f=(e,x)=>{for(var i=1;D=e[i][x],i<e.length;i++)if(D!=" ")return D},o=a.split(`
`),l=o.reduce((a,b)=>Math.max(a.length||a,b.length)),b="";for(i=0;i<l;i)b+=f(o,i++);for(i=0;b[i]!="U"&&s>0;i++)s-=b[i]=="_"?1:b[i]=="/"?5:-4;return s>0}

Ungolfed

(s,a)=>{
    var f=(e,x)=>{
        for(var i=1;D=e[i][x],i<e.length;i++)
            if(D!=" ")
                return D
    },
    o=a.split(`
`),
    l=o.reduce((a,b)=>Math.max(a.length||a,b.length)),
    b="";
    for(i=0;i<l;)
        b+=f(o,i++);
    for(i=0;b[i]!="U"&&s>0;i++)
        s-=b[i]=="_"?1:b[i]=="/"?5:-4;
    return s>0
}

Uso

var o = (s,a)=>{var f=(e,x)=>{for(var i=1;D=e[i][x],i<e.length;i++)if(D!=" ")return D},o=a.split(`
`),l=o.reduce((a,b)=>Math.max(a.length||a,b.length)),b="";for(i=0;i<l;)b+=f(o,i++);for(i=0;b[i]!="U"&&s>0;i++)s-=b[i]=="_"?1:b[i]=="/"?5:-4;return s>0}


o(27, `
      ____       ____ _   
   __/    \\     /    U \\  
__/        \\   /        \\_
            \\_/           `); // will return true
user49328
fonte
Meu erro; Eu pensei que tinha copiado no primeiro exemplo com "27" como o primeiro argumento. Eu corrigi isso. Obrigado.
user49328
1

Java, 219 bytes

boolean p(int v,String c){int z=c.length(),f[]=new int[z],e,i,k;for(String r:c.split("\n"))for(i=-1;++i<r.length();)if((e=r.charAt(i))>32)f[i]=e;for(i=-1,e=0;++i<z&v>0;)v-=(k=f[i])>94?1:k>91?-4:k>84?(e=1):5;return 0<e;}
  • Achate o curso, porque a coordenada y não importa, infelizmente o Java não tem um ajuste vertical. Também não possui uma string de transposição.

  • Itere sobre o percurso achatado e acompanhe a velocidade da bola.

ECS
fonte
1

Oitava, 111 110 bytes

function g(v,s) A([95,47,92])=[1,5,-4];all(v>cumsum(A(m=max(cat(1,strsplit(s,'\n'){:}),[],1)))(1:find(m==85)))

Explicação:

  • Divida a entrada em novas linhas e converta essa matriz de células irritante em uma matriz
  • Achate a matriz localizando o maxpara cada coluna
  • Mapeie os caracteres '_/\'para [1, 5, -4](todos os outros caracteres menores que '_'os mapeados 0)
  • Calcular a soma cumulativa de todos os elementos da matriz mapeada
  • Saída Truese todas as somas acumuladas do início do percurso até o copo forem menores que a velocidade inicial ( Falsecaso contrário).

Aqui está um caso de teste que eu já desenvolvi semelhante ao segundo proposto por @Erwan e alguns resultados:

s9 =
   /\
  /  \
_/    \
       \
        \
         U

g(11,s9) %False
ans = 0
g(17,s9) %True
ans =  1

E aqui está o primeiro caso de teste:

s10 = 
  _
 / U\
/    \
      \
       \
        \
         \
          \_

>> g(11,s10)
ans = 0
>> g(12,s10)
ans =  1
taça
fonte
Eu acho que se o curso é como "//_U\\\\\\\_o resultado está incorreto, uma vez que você não remove o caractere após as Umesmas coisas, se você tiver um curso com o máximo local como_//\\\\\U
Erwan
@Erwan Mas eu não remover os caracteres após o U. Isso é o que (1:find(m==85))faz; leva a sub-matriz do primeiro índice para o local da U. Vou verificar o seu caso de teste com algumas velocidades iniciais e voltar para você.
copo
Não consegui executar sua solução (não tenho Octave), é por isso que simplesmente pergunto ... e porque encontro o issu com o máximo local na outra solução python :) finalmente sua solução funciona com o máximo local desde que você use cumsum e não apenas a soma (não ver que na primeira leitura)
Erwan
@ Erwan Adicionei os dois casos de teste que você sugeriu. Por favor, dê uma olhada e veja se os resultados são o que você espera. Se você estiver tentando isso no MATLAB, não poderá executá-lo porque ele usa alguma indexação que só funciona no Octave. Você teria que atribuir o resultado cumsuma uma variável intermediária e depois usá-lo para a comparação final all(v>tmp(1:find(m==85))).
beaker
Sua solução trabalho finos lotes da falta de coisas na primeira leitura (apenas teste em Matlab tantas variáveis intermediárias para adicionar)
Erwan
0

C, 629 bytes

#include <string.h>
#include <stdlib.h>
#include <string.h>

bool swing(char *c, unsigned int p)
{
    char *olc = calloc(strlen(c), 1);
    int x = 0;
    char *n = c;

    while(1) {
        if(*n == '\0')  break;
        else if(*n == ' ') x += 1;
        else if(*n == '\n') x = 0;
        else {
            olc[x] = *n;
            x += 1;
        }
        n++;
    }

    int hd = 0;
    for(char *i = olc; i != strchr(olc, 'U'); i++) {
        if(*i == '_') hd += 1;
        else if(*i == '/') hd += 5;
        else hd -= 4;
    }

    free(olc);
    if(hd < p) return 1;
    return 0;
}

Ungolfed:

bool swing(char *course, unsigned int power)
{
    const size_t course_len = strlen(course);
    char *one_line_course = calloc(course_len, sizeof(char));
    assert(one_line_course);
    int x_pos = 0;
    char *next = course;

    //Convert to one line representation
    while(1) {
        if(*next == '\0') {
            break;
        }
        else if(*next == ' ') {
            x_pos += 1;
        }
        else if((*next == '\n') || (*next == '\r')) {
            x_pos = 0;
        }
        else {
            one_line_course[x_pos] = *next;
            x_pos += 1;
        }
        next++;
    }

    //Calculate power vs distance
    const char *hole_location = strchr(one_line_course, 'U');
    int hole_distance = 0;
    for(char *i = one_line_course; i != hole_location; i++) {
        if(*i == '_') {
            hole_distance += 1;
        }
        else if(*i == '/') {
            hole_distance += 5;
        }
        else {
            hole_distance -= 4;
        }
    }

    free(one_line_course);
    if(hole_distance < power) {
        return true;
    }
    else {
        return false;
    }
}

Basicamente, eu apenas faço uma passagem para converter a string de entrada para caber tudo em uma linha, depois

samt1903
fonte
Bem-vindo à programação de quebra-cabeças e código de golfe! Você pode (e deve) ser capaz de reduzir substancialmente o tamanho, eliminando a maioria dos espaços em branco; você pode reduzir alguns dos seus if/ elseeg x+=*n==' ')?1:*n=='\n'?-x:(olc[x]=*n,1. Outra dica: em C, unsigned intpode ser escrito unsigned, economizando 4 bytes imediatamente.
Toby Speight
0

Python, 212 201 188 143 bytes

Grande parte do crédito por essa iteração desse script vai para @Erwan, que me deu uma abordagem totalmente diferente para tentar e algumas dicas que me salvaram 55 bytes no final.

Não é recursivo; portanto, deve ser substancialmente diferente da outra solução python.

def g(c,p):
 o=[''.join(x).split()[0] for x in zip(*c.split('\n'))]
 t={"_":1,"/":5,"\\":-4}
 for v in o:
    if v=="U" or p<1:return p>0
    p-=t[v]

Ungolfed um pouco:

def g(course,power):
  course=course.split('\n') # split into lines
  course=zip(*course) 

  #transpose and flatten course, then remove spaces
  one_line_course=[''.join(x).split[0] for x in zip(*course)] 

  terrain_values={"_":1,"/":5,"\\":-4}
  for char in one_line_course:
    if char=="U" or power<1: 
      return power>0 # true when power remains, false otherwise
    power-=terrain_values[char]
SnoringFrog
fonte
se você quiser uma solução mais curta, use o Cyoce tip e use a função interna de transposição. o=[''.join(x).split()[0] for x in zip(*c.split('\n'))]
Erwan
você também pode substituir breakpor return p>0e removerif p...
Erwan
você precisa adicionar uma condição if"U"==v or p<1 se houver um máximo local como_//\\\\\U
Erwan
@ Erwan Sua primeira dica não funcionará se as linhas não tiverem o mesmo comprimento (as linhas curtas têm espaços à direita para coincidir com as longas). Como o post dizia "Os cursos podem opcionalmente ser preenchidos com espaços", não tenho certeza de que podemos assumir que isso é verdade. Eu perguntei sobre isso em um comentário.
SnoringFrog
sim eu assumo toda a linha têm o mesmo comprimento (egalized com espaço em branco) Talvez eu esteja errado, neste caso, eu acho que a minha solução é ruim
Erwan