# Will I tip over?

## Overview

Given a 3 line string, figure out if the structure falls to the left, balances, or falls to the right.

## Input structure

You can imagine the structure as metal rod with stuff on top, all being balanced on top of a vertical rod.

1  7 4        a
===============
|


The first line is the items. Each item's weight is calculated as the ascii value of the character minus 32. (Characters under 32 aren't considered and spaces weigh 0). Keep in mind that an item's force on the rod is its weight times the distance to the pivot point.

The second line is the rod. Each length of rod weighs 1 unit by itself. This line is exclusively equals signs (=).

The third line is the pivot point. This can be placed anywhere, and is represented by a number of spaces followed by a single pipe (|) character.

# Examples

Input:


=====
|


Output: Balance

Input:


=====
|


Output: Falls left

Input:

    %
=====
|


Output: Balance (Because % weighs enough to counteract the weight of the left side of the rod)

Input:

 a    a
=======
|


Output: Falls right (because the a on the right is further away from the pivot point)

Input:

1  7 4        A
===============
|


Output: Falls left

Input:

1  7 4        a
===============
|


Output: Falls right (lower case letters are heavy!)

Input:

            $~ =============== |  Output: Balance # Notes • Trailing whitespace is permitted, leading whitespace is not. • Your program may output in whatever format you like, as long as there are 3 distinct outputs for left, balance, and right. • Your program must accept the format shown as input. • This is so the shortest code in bytes wins • Closely related Jul 3, 2017 at 23:23 • May the program take the three lines as three separate strings (e.g. as three arguments to a function or as a three element list)? Jul 3, 2017 at 23:39 • @notjagan The input must be a single string separated by new line characters. Jul 3, 2017 at 23:40 • Related, possible dupe. – xnor Jul 4, 2017 at 0:08 • @xnor Not a dupe because that question deals with only uppercase letters, and its goal is to find the pivot. My question is about all ascii characters >= 32, and mine supplies the pivot and asks if the structure will fall over. Essentially the reverse of the one you linked. Jul 4, 2017 at 0:18 ## 16 Answers # JavaScript (ES6), 116111108 106 bytes -5 bytes by summing via eval(array.join+) instead of array.reduce(). -3 bytes by defaulting to 1 instead of 32 - 31, allowing parentheses to be removed. -2 bytes since pivot point is the length of the last line - 1 (s,[t,r,b]=s.split )=>Math.sign(eval([...r].map((_,i)=>(t.charCodeAt(i)-31||1)*(i-b.length+1)).join+))  Outputs -1, 0, or 1, for left, balanced, or right, respectively. Ended up similar to Chas Brown's python answer, so credit goes there. Can save 4 bytes if the first line is padded to match the length of the rod by using (31-t.charCodeAt(i))*(b.length+~i). ## Test Snippet Includes additional output (Left/Balanced/Right) along with the number. f= (s,[t,r,b]=s.split )=>Math.sign(eval([...r].map((_,i)=>(t.charCodeAt(i)-31||1)*(i-b.length+1)).join+)) <textarea id=I rows=3 cols=20></textarea><br><button onclick="O.value=I.value?${x=f(I.value)} (${['Left','Balanced','Right'][x+1]}):''">Run</button> <input id=O disabled> ### Another 106 byte method (s,[t,r,b]=s.split )=>Math.sign(eval(r.replace(/./g,(_,i)=>"+"+(t.charCodeAt(i)-31||1)*(i-b.length+1))))  Instead of joining an array on +s, we create a string of numbers, each prefixed by +. The leading + gets ignored. • I think (b.length+~i) might help to save a byte. (Also I don't understand why you have the ||1.) – Neil Jul 4, 2017 at 10:31 • @Neil b.length+~i returns the negative of i-b.length+1; that could help if I could negate the other part. As for the ||1, that was because I was assuming the first line wasn't padded to match the length of the rod, so t.charCodeAt(i) would return NaN beyond the end of the first line. Jul 4, 2017 at 16:20 • I hadn't though to try a non-padded test case; thanks for explaining. – Neil Jul 4, 2017 at 16:33 # Python 2, 112 110 bytes def f(s):w,b,p=s.split('\n');return cmp(sum((ord((w+' '*-~i)[i])-31)*(i-p.find('|'))for i in range(len(b))),0)  Try it online! EDIT: Finally managed to eliminate the enumerate and rjust for a measly 2 bytes... meh! Takes in a string; outputs -1,0, or 1 for falls left, balances, falls right, respectively. First pass at 112 bytes was: def f(s):w,b,p=s.split('\n');return cmp(sum((ord(c)-31)*(i-p.find('|'))for i,c in enumerate(w.rjust(len(b))),0)  • (ord(c)-31) Took me a while to realize that this is actually incorporating the weight of the rod itself along with the items. Very clever! Jul 3, 2017 at 23:54 • As per meta, you can replace return with print for -1 byte (although it doesn't really play nicely with the current TIO code). Jul 3, 2017 at 23:58 # Jelly, 24 bytes ṪO_31 ỴµṪLạÐ€ṪL$×Çṣ0S€IṠ


Try it online!

-1 for falling left, 0 for balancing, 1 for falling right (full program).
[-1] for falling left, [0] for balancing, [1] for falling right (function).

First line must have trailing spaces, last line must not.

First of all, we're working with individual lines, so we need to somehow get them. That's a job for Ỵ. Then, we need to treat the \n-split version of the input as if it was the original input, so we use µ to make a monadic chain applied to the current value.

Now we begin real work, and our first job would be computing the factors of the weights. Essentially this is a range [distance from far left to pivot..0..distance from pivot to far right]. First of all, we have to find the 1-based index of the pivot, which is essentially the length of the last line without trailing spaces. So we pop the last line (pivot line) from our original list with Ṫ, since we won't need it anymore, and then we take its length with L. We then need to take the length of the rod, for which we do the same thing to the now-last line (rod line) with ṪL$. Finally, to get the range, we map |x - y| to [1..rod length], where x is the pivot index and y is each element of the list we map upon. We do this using ạÐ€, where ạ calculates |x - y| and Ð€ makes a range from 1 up to and including the rod length. Now we'll have the range we want. After that, we have to multiply each integer, representing a piece of the rod, with its corresponding weight. To calculate the weights, we use Ç, going to the top line of our code. We take the remaining line with Ṫ, its charcodes with O, and then we calculate x - 31 using _31, x being each charcode. We then assign space to weight 1 (0 + rod piece = 1), ! to weight 2 (1 + 1) etc. We're done with the top line, so now Ç would return the list of weights, which we multiply with the corresponding integers representing the rod pieces with ×. After that, we split with ṣ0 on the pivot point, represented by a 0 (since any weight there won't affect the result), resulting in a list of the form [[1st weight, 2nd weight...weight just before pivot], [weight just after pivot, weight after the one before...last weight]]. Those lists represent the sides of the rod, left and right. We now sum each of the lists using S€ to get the total weights on each side, and use I to take the delta, which will be negative if left side is heavier, zero if they're equal-weighted, and positive if right side is heavier. So, to return the final result using this properly to our advantage, we take the sign with Ṡ. ## Haskell, 212 171 bytes (188 if take input as one string) o!p=map(fst)(zip[p-0,p-1..]o) x#p=sum(zipWith(\c w->(max(fromEnum c-32)0)*w)x(x!p))+sum(x!p) x?c=length(takeWhile(==c)x)  171 bytes variant r a b c=signum(take(b?'=')(a++repeat ' ')#(c?' '))  188 bytes variant x%y=lines x!!y r i=signum(take(i%1?'=')(i%0++repeat ' ')#(i%2?' '))  Explanation o!p=map(fst)(zip[p-0,p-1..]o) Creates weights coefs list. o - list, p - pivot position for list "abcdf" and p=3 (pivot under 'd') outputs [3,2,1,0,-1] x#p Calculates total balance x-list of "objects" on lever, p-pivot place sum(zipWith sum of zipped lists (\c w->(max(fromEnum c-32)0)*w) weight of ascii "object" times distance from pivot x(x!p)) x-ascii objects, (x!p)-distances list(weight coefs) +sum(x!p) balance of lever ("==") itself x?c=length(takeWhile(==c)x) length of list before non c element met used to find '|' position and length of "===" lever before right whitespaces met r a b c= Sums it all up =) a-ascii objects, b-lever, c-pivot line signum( 1-tips left, 0-balance, -1-tips right take(b?'=')(a++repeat ' ') takes all object on lever plus whitespaces up to length of the lever # calculate the balance (c?' ') determine place of pivot  • You can use fromEnum instead of ord and drop the import. c can be simplified to c p=max(ord p-32)0 (or with fromEnum) and as you are using it only once, inline it. – nimi Jul 6, 2017 at 17:18 • Or you could add (Lambdabot) to your title, this imports pretty much everything you need, see here. Jul 7, 2017 at 2:10 • The function c can even be simplified (characters under 32 aren't considered) further to c p=ord p-32. Also p is basically length (minus 1), so p x=length x-1 would work too (and you can inline it too). Also have a look at my solution, how I use signum - you could do r o l s = signum$ 2 * z ... which returns 0,1,-1 for B,L,R. Jul 7, 2017 at 2:27
• Apart from, that this solution seems to fail test cases [3,4,7] and takes 3 Strings instead of one. (see lines). Jul 7, 2017 at 2:33
• Here's a version with a few tips applied (saves you 29 bytes ;)). Jul 7, 2017 at 16:26

# Python 2, 90 bytes

def f(s):L=len(s)/3;print cmp(sum((ord(s[i])-31)*(i-s[-L:].find('|'))for i in range(L)),0)


Expects input lines to be padded (with spaces) to the correct length. Outputs -1 for falls left, 0 for balanced, and 1 for falls right.

Try it online!

## 94 bytes

For +4 bytes we can have a version which, using a while loop, requires stripped lines rather than padded lines:

def f(s):
i=r=0
while''<s[i]:r+=(ord(s[i])-31)*(i-s[-3::-1].find('='));i+=1
print cmp(r,0)


Try it online!

# Jelly, 30 bytes

O_31×J_¥A+\sṪ€µ÷ḢṪ_2Ṡ
ỴṪLç@ỴḢ$ Test Suite Outputs 0 for balanced, 1 for right, and -1 for left. How it Works O_31×J_¥A+\sṪ€µ÷ḢṪ_2Ṡ - helper function. Arguments position of pivot and first line O - char codes of first line _31 - subtract 31 to get weight × - elementwise product with: J_¥ - distances from the pivot A - absolute value +\ - cumulative sum s - split to get [[...,left weight],...,[..., right + left weight]] Ṫ€ - last element of each sublist: [left weight, ... right weight] µ÷Ḣ - get ratio of each element over left weight: ratio n indicates right + left = n × left ===> right = left if n = 2 _2 - subtract 2: positive is right>left and negative is right<left Ṡ - return the sign of this ỴṪLç@ỴḢ$              - main link. Argument: 3 line string.
ç@                  - apply helper function with arguments:
Ỵ                        - split by linefeeds
Ṫ                       - last line
L                      - length (returns position of pivot)
$- and Ỵ - split by linefeeds Ḣ - first line  ## Ruby, 543 bytes def willittip(s) leftw=0; rightw=0; arr=[]; fields=s.split("\n") pos=fields[2].index("|") fields[0].split("").each do |i| arr << i.ord-32 end arr[pos+1..-1].each_with_index do |x,y| rightw=rightw+1 if x>0 if pos>0 rightw=rightw+x*(pos-y).abs else rightw=rightw+x end end end arr[0..pos-1].each_with_index do |x,y| leftw=leftw+1 if x>0 if pos>0 leftw=leftw+x*(pos-y).abs else leftw=leftw+x end end end if leftw==rightw return "Equal" elsif leftw<rightw return "Right" elsif leftw>rightw return "Left" end end  • Welcome to PPCG! :D The goal for code-golf challenges is to make your code as small as possible. You can reduce your code size by making all variables and function names a single character, and by deleting whitespace wherever possible. Jul 4, 2017 at 8:40 # APL (Dyalog), 43 bytes* {×(¯31+⎕UCS⊃⍵)+.×(⍳≢⊃⍵)-'|'⍳⍨⊃⌽⍵}⎕TC[2]∘≠⊆⊢  Try it online! ⊆⊢ partition the argument into runs of characters that are ⎕TC[2]∘≠ different from the 2nd Terminal Control character (Linefeed)** {} apply the following anonymous function on the list of strings: ⊃⌽⍵ in the first string of the reversed list (i.e. the last) '|'⍳⍨ find the ɩndex of the pivot point ()- subtract that from the following list: ⊃⍵ the first string ≢ its length ⍳ all the ɩndices of that ()+.× weighted sum with those weights and the following values: ⊃⍵ the first string ⎕UCS code points in the Universal Character Set ¯31+ add negative thirty-one (32 for the required offset minus one for the rod) × signum of that * For 1 byte per char, use {×(¯31+⎕UCS↑⍵)+.×(⍳≢↑⍵)-'|'⍳⍨↑⌽⍵}⎕TC[3]∘≠⊂⊢ with ⎕ML←3. Try it online! ** ⎕TC is deprecated and used here only for golfing purposes. In production code, one should use ⎕UCS 10. # Haskell (Lambdabot), 142 bytes l=length g[a,c,b]=splitAt(l b)$a++(' '<$[1..l c-l a]) k e=sum$zipWith((*).(-31+).ord)e[1..]
f=signum.uncurry(-).(k.drop 1.reverse***k).g.lines


Try it online!

### Ungolfed version:

-- for readability, allows reading top-down/left-right
(.>) = flip (.)

ungolfed =
lines                                 -- separate out lines into..
.> (\[a,b,c] ->                          -- a,b,c (first,second,third)
-- ' ' pad the first line & split on pivot
splitAt (length c) (a ++ replicate (length b - length a) ' ')
)
.> (weight.drop 1.reverse *** weight)    -- reverse left half, drop element above pivot & get weight for both
.> uncurry (-)                           -- subtract right from left
.> signum                                -- get sign

-- get ord of the character subtract 31 ('=' char from bar),
-- then multiply with scales ([1..]) and sum it all up
weight es = sum $zipWith (ord .> subtract 31 .> (*)) es [1..]  # C (gcc), 106 107121123124129131 bytes c,b,l,i;f(char*a){l=strlen(a)/3;for(i=b=c=0;32/a[l*2+c];++c);for(;i<l-1;b+=(a[i]-31)*(i++-c));a=b>0?2:!b;}  Return 0 for falling left, 1 for balance and 2 for falling right. Require all three lines to have same length and finish with \n to determine the length of string. Try it online! • 96 bytes Jul 10, 2020 at 15:45 # Mathematica, 91 92 bytes Sign[(v=(g=ToCharacterCode)@#&@@(d=#~StringSplit~" ")-31).(Range@(l=Length)@v-l@g@Last@d)]&  The first line should have the same length with the rod. The third line should contain no trailing spaces. Return -1, 0, 1 for falling left, balance and falling right. # C# (.NET Core), 12795 90 + 18 = 108 bytes For this function the first line must be right padded with spaces to be the same length as the rod and the third line must not have trialing spaces. This conditions are allowed (see comments of the question). s=>s.Split('\n')[0].Select((c,i)=>(c-31)*(i-s.Split('\n')[2].Length+1)).Sum().CompareTo(0)  Try it online! Outputs: -1 for tip left 0 for balance 1 for tip right # Python 3, 217 bytes ### Also works in Python 2.7 def f(s):i,b,p=s.split('\n');c=p.find('|');l=sum((ord(e)-32)*(c-i.find(e))for e in i[:c])+sum(x for x in range(1,c+1));r=sum((ord(e)-32)*i[c:].find(e)for e in i[c:])+sum(x for x in range(len(b[c:])));return(l>r)-(r>l)  Returns 1 for left-side, -1 for right-side, or zero if balanced. ## Readable version: def f(s): i,b,p = s.split('\n') c = p.find('|') l = sum((ord(e)-32)*(c-i.find(e))for e in i[:c])+sum(x for x in range(1, c+1)) r = sum((ord(e)-32)*i[c:].find(e)for e in i[c:])+sum(x for x in range(len(b[c:]))) return(l>r)-(r>l)  • You don't need sum([...]), you can simply have sum(...) Jul 4, 2017 at 5:26 • @Daffy this should be 100% conformant to your specification and all given example inputs. If you agree please let me know so that I might further optimize it. Thank you. Jul 6, 2017 at 3:08 • @veganaiZe Passed all of my tests, looks good! :) Jul 6, 2017 at 3:20 • Stuff to shorten it: i[c:].find(e) can be i.find(e,c), use i,m,n=s.split('\n') and avoid the need for s at all, use return 2*(r>l) or l>r to dramatically reduce test cost at end (return value is numerically equivalent, but it's True instead of 1 and False instead of 0), or really, use a different set of return values and do return (l>r)-(r>l) to return the 1, 0 or -1 the way the old cmp function did. Jul 6, 2017 at 4:30 • Thanks ShadowRanger , Mr. Xcoder, and Daffy! @ShadowRanger I had to stick with the i[c:] because the shorter way caused a weird off-by-one issue for some corner-case input (try placing a | exactly in the middle -- above the bar). Jul 7, 2017 at 2:03 # PHP, 105 bytes for([$a,$b,$c]=explode("
",$argn);$b[$i];)$w+=(strpos($c,"|")-$i++)*8*(max(1,ord($a[$i])-31));echo$w<=>0;  prints -1/0/1 for left/balance/right. Run as pipe with -nR or try it online. breakdown for([$a,$b,$c]=explode("\n",$argn); # import input$b[$i];) # loop through bar$f+=                                # add to force:
($i-strpos($c,"|"))             # distance (<0 if left, >0 if right of pivot)
*8                              # *8
*(max(1,ord($a[$i++])-31));     # *weight
echo$f<=>0; # print -1 if$f<0, 1 if $f>0, 0 if$f==0


# Charcoal, 31 bytes

Ａ⁰ξＦＬθＡ⁺ξ×⁻ι⌕ζ|⁻℅§θι³¹ξＩ⁻›ξ⁰‹ξ⁰


Try it online! Link is to verbose version of code. Outputs 0 for balance or -1 or 1 for falling left or right. Edit: Changes in Charcoal now mean that ≔ΣＥθ×⁻κ⌕ζ|⁻℅ι³¹ξＩ⁻›ξ⁰‹ξ⁰ works for 24 bytes: Try it online! Link is to verbose version of code. Note: Both answers require padded input, but can be adapted to accept unpadded input at a cost of 3 bytes: ≔⁰ξＦＬη≔⁺ξ×⁻ι⌕ζ|⁻℅§◨θＬηι³¹ξＩ⁻›ξ⁰‹ξ⁰ Try it online! ≔ΣＥ◨θＬη×⁻κ⌕ζ|⁻℅ι³¹ξＩ⁻›ξ⁰‹ξ⁰ Try it online! Links are to verbose version of code.

• You may want to mention this this expects the input lines to be padded to the correct length with spaces, so an unpadded input might not work. Dec 26, 2017 at 10:59
• @FlipTack Better still, I've devised versions that accept unpadded input.
– Neil
Dec 26, 2017 at 11:19

# Jelly, 18 bytes

ỴµḢO_31×Ẉạ€/$ṣ0§IṠ  Try it online! This started as a golf of Erik's answer (so be sure to go upvote it), but it developed to be different enough, and Erik is no longer active on the site, that I thought posting a separate answer would be fine. Outputs [0] for balanced, [1] for tipping right and [-1] for tipping left ## How it works ỴµḢO_31×Ẉạ€/$ṣ0§IṠ - Main link. Takes a string S on the left
Ỵ                  - Split S into a list of lines [I, R, P]
µ                 - Use this list as the arguments
Ḣ                - Pop and yield I
O               - Convert to ordinals
_31            - Subtract 31, mapping space to 1, ! to 2 etc.