# Code (Mini) Golf

Given a side-view of a mini-golf course and the power of the swing, determine if the ball will make it into the hole.

A course will be in this format:

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


The ball starts directly before the first piece of ground on the left and follows the contour of the course until it reaches the hole (an upper-case U below the current level of the ground). If it reaches the hole, output a truthy value. The power of the swing will be the initial speed of the ball. The ball moves to the next character on the right at each iteration, then the speed is altered depending on the character it is now on. If the speed reaches 0 or less before the hole, output a falsey value.

• _ decreases the speed by 1
• / decreases the speed by 5
• \ increases the speed by 4

Courses can optionally be padded with spaces. The power of the swing will always be a positive integer.

You do not need to worry about the ball going too fast to enter the hole, rolling backwards or jumping/bouncing off hills.

## Test Cases

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


This is code mini-golf, shortest answer in bytes wins!

• If your language has good array built-ins, then you can turn the input into a stream of operations (\_/) with the following steps: split into array of lines, rotate, flatten, strip spaces. Commented Jan 20, 2016 at 0:09
• This is really more of a fixed-track mechanism than a golf course :P Commented Jan 20, 2016 at 1:27
• I like that \/\/\/\/\/ is a more efficient course than __________. Commented Jan 21, 2016 at 0:53
• That's what I was thinking, 4 down, 5 up, then .5 must be average. Oh, flat is 1? Commented Jan 21, 2016 at 13:21
• Will each line in a course always be the same length (with trailing spaces filling in the end of shorter lines)? Commented Jan 25, 2016 at 17:02

# Pyth, 27 bytes

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


Demonstration

This code does something very clever and not at all type-safe with X. Check it out below.

Explanation:

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

• I might be missing something, but does it stop at Q? Ie the last example could cause some issues? Commented Jan 20, 2016 at 14:01
• @flindeberg That's not how it works. The < ... Q works as a numeric comparison up until the hole, not a slice. After the hole, all that matters is that the result is truthy. Commented Jan 20, 2016 at 22:45

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


Usage example:

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


How it works:

                            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 found 2 bytes to save. Thanks!

# Ruby, 104 87 characters

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


Sample run:

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


# Japt, 38 bytes

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


Try it here!

Beating CJam!

# Explanation

Basically takes the string input, rotates it 90deg clockwise, strips out spaces and newlines, removes the hole and everything after it, and splits along chars. Then checks if ball ever gets to zero or below using the every function.

• I think  should be positive (description looks wrong) Commented Jan 20, 2016 at 5:57
• I don't think that works. Picture this: a series of slopes gets the ball's speed to -2, but then there are a net +4 later on. The sum would reflect +2 so the ball made it. In reality, it would never get to the positive section after reaching the negatives. Commented Jan 20, 2016 at 6:13
• I think I fixed the problem. Commented Jan 20, 2016 at 6:40
• That's a cool button ;) Commented Jan 20, 2016 at 14:32
• Nice! So, golfing... The double backslash is replaceable with %, and >0 can be replaced with ¬, since the sqrt of a non-positive number is always falsy (0 -> 0, -1 -> NaN). Commented Jan 20, 2016 at 21:54

## CJam, 40 39 bytes

liqN/:.e>'U/0="\_/"[4W-5]er{1$+}/]:e<0>  Input has the power on the first line and the course starting on the second line. Output is 0 or 1. Test it here. ### Explanation 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.


## Retina, 828177746867 68 bytes

+(?<=(.)*) (?=.*¶(?<-1>.)*(.))
$2 \\ >>>> +>_|>{5}/|>¶ ^>*U  Try it online • Input is represented in unary base, as n >s - for example, 4 is >>>>\n. (is this legal?) • +(?<=(.)*) (?=.*¶(?<-1>.)*(.)) $2 - flatten the course - replace spaces with the character below them.

After this stage the data will look like this:

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


We can just ignore everything after the first U, we will not reach there anyway.

• > represent a step we are allowed to make, or the remaining energy.
• Replace each \ with four > - a slope gives us additional energy.
• Loop: contentiously remove >_ or >>>>>/ until there are none left. _s and /s consume energy.
• Finally, try to match ^>*U - check if we can reach U with positive energy (or no energy).
This will output 0 or 1.

Another close option with 91 79 bytes is:

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


Try it online

This is the same approach but with a balancing group instead of a contentious replace.

I'm sure both of these can be golfed further, so any one of them may end up shorter.

• Yes, unary input is legit (unless the challenge specifies "decimal"), although I'd probably use 0 or 1 as the digit if that doesn't incur any additional bytes. Commented Jan 21, 2016 at 14:27
• Also welcome to PPCG, I'm really glad to see you here! :) (And using Retina as well.) Commented Jan 21, 2016 at 14:28
• Sure! It was on the hot question list and looked fun. I thought I'd give it a try :-)
– Kobi
Commented Jan 21, 2016 at 14:29

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


Edit: Saved 4 bytes thanks to ՊՓԼՃՐՊՃՈԲՍԼ.

• @ՊՓԼՃՐՊՃՈԲՍԼ Thanks, I keep trying to optimise for speed...
– Neil
Commented Jan 21, 2016 at 0:15

# JavaScript (ES6), 108107 106 bytes

This is the solution I came up with when I created the challenge.

(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


## Explanation

Takes the power as a number and the course as a string. Returns 1 for true or 0 for false. The course must be padded with spaces.

(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


## Test

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>

## Python (3.5) 169 160 bytes

A recursive solution without the transpose function (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 for course, p for power, v for speed, h for height

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


## Usage

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


## Pyth, 35 bytes

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


Explanation

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


# Ruby, 85 characters

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


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
}


Usage

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

• My mistake; I thought I had copied in the first example with "27" as the first argument. I corrected this. Thank you. Commented Jan 20, 2016 at 19:15

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

• Flatten the course, because the y-coordinate doesn't matter, unfortunately Java doesn't have a vertical trim. It also doesn't have a String-transpose.

• Iterate over the flattened course and keep track of the ball speed.

# Octave, 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)))


### Explanation:

• Split the input on newlines and convert that annoying cell array to a matrix
• Flatten the matrix by finding the max for each column
• Map the characters '_/\' to [1, 5, -4] (all other characters less than '_' are mapped to 0)
• Calculate the cumulative sum of all elements of the mapped array
• Output True if all cumulative sums from the beginning of the course to the cup are less than the start velocity (False otherwise).

Here is a test case that I had already developed similar to the second one proposed by @Erwan and a couple of results:

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

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


And here's the first test case:

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

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

• i think if the course is like "//_U\\\\\\\_ the result is incorrect since you don't remove character after U same things if you have a course with local maximum like _//\\\\\U  Commented Jan 25, 2016 at 8:35
• @Erwan But I do remove the characters after the U. That's what the (1:find(m==85)) does; it takes subarray from the first index to the location of the U. I'll check your test case with a couple of starting velocities and get back to you. Commented Jan 25, 2016 at 15:45
• I couldn't run your solution (i don't have Octave) that why i just ask ... and because i find the issu with local maxima in the other python solution :) finally your solution work with local maxima since you use cumsum and not just sum (don't see that at the first read) Commented Jan 25, 2016 at 16:25
• @Erwan I've added the two test cases that you suggested. Please have a look and see if the results are what you expect. If you're trying this in MATLAB, then you're not going to be able to run it because it uses some indexing that only works in Octave. You would have to assign the result of cumsum to an intermediate variable and then use that for the final comparison all(v>tmp(1:find(m==85))). Commented Jan 25, 2016 at 16:34
• Your solution work fine miss lots of things at the first read (just test in Matlab so many intermediate variables to add) Commented Jan 25, 2016 at 16:59

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


Basically I just make one pass to convert the input string to fit everything in one line, then

• Welcome to Programming Puzzles & Code Golf! You can (and should) be able to reduce the size substantially by eliminating most whitespace; you can reduce some of your if/else e.g. x+=*n==' ')?1:*n=='\n'?-x:(olc[x]=*n,1. Another tip: in C, unsigned int can be written unsigned, saving 4 bytes right away. Commented Jan 25, 2016 at 22:09

# Python, 212201188 143 bytes

Much of the credit for this iteration of this script goes to @Erwan, who gave me an entirely different approach to try and some tips that saved me 55 bytes in the end.

Not recursive, so should be substantially different from the other python solution.

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 a bit:

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]

• if you want a shorter solution you can use Cyoce tip and use the transpose built-in function. somethings like that o=[''.join(x).split()[0] for x in zip(*c.split('\n'))] that win 40 bytes i think Commented Jan 25, 2016 at 8:10
• you can also replace break by return p>0 and remove if p... Commented Jan 25, 2016 at 8:26
• you need to add a condition if"U"==v or p<1  if there is a local maximum like _//\\\\\U Commented Jan 25, 2016 at 8:45
• @Erwan Your first tip does not work if the lines are not all the same length (short lines having trailing spaces to match long ones). Since the post said "Courses can optionally be padded with spaces" I'm not sure we can assume that that's true. I've asked about that in a comment. Commented Jan 25, 2016 at 17:03
• yes I assume all line have the same length (egalized with white space) maybe i'm wrong in this case i think my solution is bad Commented Jan 25, 2016 at 17:14

# J, 47 bytes

1 e.(<:4([:+/\1 5 _4{~i.&3{.])@-.~'_/\U',@i.|:)


Try it online!