Код (Мини) Гольф


50

Учитывая вид сбоку на поле для мини-гольфа и силу удара, определите, попадет ли мяч в лунку.


Курс будет в следующем формате:

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

Мяч начинается непосредственно перед первым участком земли слева и следует по контуру поля, пока не достигнет отверстия (верхний регистр Uниже текущего уровня земли). Если оно достигает дыры, выведите истинное значение. Сила размаха будет начальной скоростью мяча. Мяч перемещается к следующему символу справа на каждой итерации, затем скорость изменяется в зависимости от символа, на котором он сейчас находится. Если скорость достигает 0или меньше перед отверстием, выведите значение фальси.

  • _ уменьшает скорость на 1
  • / уменьшает скорость на 5
  • \ увеличивает скорость на 4

Курсы могут быть дополнены пробелами. Сила свинга всегда будет положительным целым числом.

Вам не нужно беспокоиться о том, что мяч будет слишком быстрым, чтобы попасть в лунку, катиться назад или прыгать / отскакивать от холмов.

Тестовые случаи

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

Это код мини-гольфа, самый короткий ответ в байтах выигрывает!


1
Если ваш язык имеет хорошие встроенные массивы, то вы можете превратить ввод в поток операций ( \_/), выполнив следующие шаги: разбить на массив строк, повернуть, сгладить, разделить пробелами.
Cyoce

1
Это действительно больше механизм с фиксированной гусеницей, чем поле для гольфа: P
Зак Гейтс

24
Мне нравится, что \/\/\/\/\/это более эффективный курс, чем __________.
езраст

2
Это то, о чем я думал: 4 вниз, 5 вверх, затем .5 должно быть средним. О, квартира это 1?
Лейф Виллертс

Будет ли каждая строка в курсе всегда иметь одинаковую длину (с завершающими пробелами в конце более коротких строк)?
SnoringFrog

Ответы:


17

Pyth, 27 байт

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

демонстрация

Этот код делает что-то очень умное и совсем не безопасное для типов X. Проверьте это ниже.

Объяснение:

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

Я могу что-то упустить, но останавливается ли на этом Q? Т.е. последний пример может вызвать некоторые проблемы?
Флиндеберг

@flindeberg Это не так. < ... QРаботает как числовое сравнение вверх до отверстия, а не срез. После дыры важно только то, что результат правдив.
Исаак

14

Haskell, 111 109 байт

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

Пример использования:

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

Как это устроено:

                            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                                 

Редактировать: @ user81655 нашел 2 байта для сохранения. Спасибо!


7

Ruby, 104 87 символов

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

Образец прогона:

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 

6

Japt, 38 байт

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

Try it here!

Бить CJam!

объяснение

В основном принимает строковый ввод, вращает его на 90 градусов по часовой стрелке, удаляет пробелы и символы новой строки, удаляет отверстие и все, что за ним, и разделяется по символам. Затем проверяет, достигает ли шарик нуля или ниже, используя everyфункцию.


Я думаю, что `` должно быть положительным (описание выглядит неправильно)
isaacg

Я не думаю, что это работает. Представьте себе, что ряд уклонов увеличивает скорость мяча до -2, но затем есть чистая +4. Сумма будет отражать +2, чтобы мяч сделал это. На самом деле, он никогда не попадет в положительную часть после достижения отрицательных.
Сайос

Я думаю, что я решил проблему.
Mama Fun Roll

Это крутая кнопка;)
J Atkin

Приятно! Итак, игра в гольф ... Двойная обратная косая черта может быть заменена %и >0может быть заменена ¬, так как sqrt неположительного числа всегда ложно ( 0 -> 0, -1 -> NaN).
ETHproductions

6

CJam, 40 39 байт

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

Вход имеет мощность в первой строке, а курс начинается со второй строки. Вывод 0или 1.

Проверьте это здесь.

объяснение

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.

5

Retina, 82 81 77 74 68 67 68 байт

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

^>*U

Попробуйте онлайн

  • Вход представлен в унарной базе , как n >s - например, 4 есть >>>>\n. (это законно?)
  • +`(?<=(.)*) (?=.*¶(?<-1>.)*(.)) $2 - Выровняйте курс - замените пробелы на символы под ними.

    После этого этапа данные будут выглядеть так:

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

    Мы можем просто игнорировать все после первого U, мы все равно не достигнем этого.

  • > представляют собой шаг, который нам позволено сделать, или оставшуюся энергию.
  • Замените каждый \на четыре >- уклон дает нам дополнительную энергию.
  • Петля: постоянно снимать >_или >>>>>/пока не останется ни одного. _s и /s потребляют энергию.
  • Наконец, попытайтесь соответствовать ^>*U- проверьте, можем ли мы достичь Uс положительной энергией (или без энергии).
    Это выведет 0или 1.

Другой закрытый вариант с 91 79 байтами:

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

Попробуйте онлайн

Это тот же подход, но с балансирующей группой вместо спорного заменить.

Я уверен, что оба они могут быть в гольфе дальше, поэтому любой из них может оказаться короче.


1
Да, унарный ввод допустим (если в задаче не указано «десятичное число»), хотя я бы, вероятно, использовал 0или 1в качестве цифры, если это не повлечет за собой никаких дополнительных байтов.
Мартин Эндер

1
Также добро пожаловать в PPCG, я очень рад видеть вас здесь! :) (И с использованием Retina также.)
Мартин Эндер

Конечно! Это было в списке горячих вопросов и выглядело весело. Я думал, что попробую :-)
Коби

3

ES6, 117 байт

(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;
}

Изменить: Сохранено 4 байта благодаря ՊՓԼՃՐՊՃՈԲՍԼ.


@ ՊՓԼՃՐՊՃՈԲՍԼ Спасибо, я продолжаю пытаться оптимизировать скорость ...
Нил

3

JavaScript (ES6), 108 107 106 байт

Это решение, которое я придумал, когда создал задачу.

(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

объяснение

Принимает силу как число, а курс как строку. Возвращает 1для trueили 0для false. Курс должен быть дополнен пробелами.

(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

Контрольная работа

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>


3

Python (3,5) 169 160 байт

Рекурсивное решение без функции транспонирования (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 для курса, p для мощности, v для скорости, h для высоты

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

использование

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

2

Pyth, 35 байтов

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

объяснение

                                    - 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 ()

1

Рубин, 85 знаков

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

Адаптированный ответ @ manatwork


1

JavaScript, 266 263 244 байта

(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
}

использование

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

Виноват; Я думал, что я скопировал в первом примере с «27» в качестве первого аргумента. Я исправил это. Спасибо.
user49328

1

Java, 219 байт

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;}
  • Выровняйте курс, потому что координата y не имеет значения, к сожалению, в Java нет вертикальной обрезки. Он также не имеет транспонирования строк.

  • Итерируйте по сплющенному курсу и следите за скоростью мяча.


1

Октава, 111 110 байт

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

Объяснение:

  • Разделите ввод на новые строки и преобразуйте этот раздражающий массив ячеек в матрицу
  • Свести матрицу, найдя maxдля каждого столбца
  • Сопоставить символы '_/\'с [1, 5, -4](все другие символы меньше, чем '_'сопоставлены 0)
  • Рассчитать совокупную сумму всех элементов сопоставленного массива
  • Выведите, Trueесли все кумулятивные суммы от начала курса до кубка меньше начальной скорости (в Falseпротивном случае).

Вот тестовый пример, который я уже разработал, похожий на второй, предложенный @Erwan, и несколько результатов:

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

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

И вот первый тестовый пример:

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

>> g(11,s10)
ans = 0
>> g(12,s10)
ans =  1

Я думаю, что если курс похож "//_U\\\\\\\_на результат неправильный, так как вы не удаляете персонажа после тех Uже вещей, если у вас есть курс с локальным максимумом, как_//\\\\\U
Erwan

@Erwan Но я бы удалить символы после U. Это то, что (1:find(m==85))делает; это берет подрешетку от первого индекса до местоположения U. Я проверю ваш тестовый пример с парой начальных скоростей и вернусь к вам.
стакан

Я не смог запустить ваше решение (у меня нет Octave), поэтому я просто спрашиваю ... и потому что я нахожу проблему с локальными максимумами в другом решении Python :), наконец, ваше решение работает с локальными максимумами, так как вы используете cumsum а не просто сумма (не вижу этого при первом прочтении)
Erwan

@ Erwan Я добавил два тестовых примера, которые вы предложили. Пожалуйста, посмотрите и убедитесь, что результаты соответствуют вашим ожиданиям. Если вы попробуете это в MATLAB, вы не сможете запустить его, потому что он использует некоторую индексацию, которая работает только в Octave. Вы должны будете присвоить результат cumsumпромежуточной переменной, а затем использовать его для окончательного сравнения all(v>tmp(1:find(m==85))).
стакан

Ваше решение отлично работает, пропустите много вещей при первом чтении (просто протестируйте в Matlab так много промежуточных переменных, которые нужно добавить)
Erwan

0

C 629 байт

#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;
    }
}

По сути, я просто делаю один проход для преобразования входной строки, чтобы уместить все в одну строку, затем


Добро пожаловать в Программирование Пазлов и Code Golf! Вы можете (и должны) иметь возможность существенно уменьшить размер, устраняя большую часть пробелов; Вы можете уменьшить некоторые из ваших if/ elseнапример x+=*n==' ')?1:*n=='\n'?-x:(olc[x]=*n,1. Другой совет: в C unsigned intможно записать unsigned, сохраняя сразу 4 байта.
Тоби Спейт

0

Python, 212 201 188 143 байта

Большая часть заслуг в этой итерации этого сценария принадлежит @Erwan, который дал мне совершенно другой подход и несколько советов, которые в итоге сэкономили мне 55 байт.

Не рекурсивный, поэтому должен существенно отличаться от другого решения на 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]

Немного разгулялся:

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]

если вы хотите более короткое решение, вы можете использовать Cyoce tip и использовать встроенную функцию транспонирования. что-то подобное o=[''.join(x).split()[0] for x in zip(*c.split('\n'))]выигрывает 40 байтов, я думаю
Erwan

Вы можете также заменить breakна return p>0и удалитьif p...
Эрвана

вам нужно добавить условие, if"U"==v or p<1 если есть локальный максимум, например_//\\\\\U
Erwan

@Erwan Ваш первый совет не работает, если строки не имеют одинаковую длину (короткие строки имеют завершающие пробелы для соответствия длинным). Поскольку в сообщении говорилось, что «курсы могут быть дополнены пробелами», я не уверен, что мы можем предположить, что это правда. Я спросил об этом в комментарии.
SnoringFrog

да, я предполагаю, что все строки имеют одинаковую длину (выровнены с пробелами), возможно, я ошибаюсь в этом случае, я думаю, что мое решение плохое
Erwan
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.