13
\$\begingroup\$

Balancing Act

A see-saw (supposedly from the French 'ci-ça', meaning 'this-that') forms a third of the holy trinity of playground equipment, along with the similarly ubiquitous slide and swing. A see-saw is in perfect balance if, and only if, the sum of the moments on each side are equivalent. A see-saw can therefore be balanced by adding a specific quantity of weight to the side with the lower moment sum; achieving this is your goal for this challenge.

Challenge

Your challenge is to take a depiction of a see-saw as input and output it again, with weight added to one end of the see-saw to balance it.

Input

Your program must take, in any reasonable format, an ASCII see-saw such as the following:

100             100
-------------------
         ^         

The first line contains two numbers, each representing weights on the see-saw. Exactly one weight is present on each side, each acting on the very end of its side of the plank. Weights are guaranteed to be integers, and always align with their corresponding end of the plank. These numbers will never overlap the fulcrum (^).

The second line represents the 'plank' of the see-saw. Each dash (-) represents an equal length to each other dash, with the sole exception of the dash directly over the fulcrum (^), which has no length.

The third line represents the fulcrum of the see-saw. This fulcrum is marked by the only character that is not a space on this line, a circumflex ('^'). The fulcrum can be positioned anywhere along the length of the plank in a valid input so long as enough space is left so that the numbers representing weights do not overlap the fulcrum in either the input or the output.

The input is guaranteed to have three lines, and have no white-space prior to or after the characters that constitute the see-saw (excepting, of course, the third line, which requires it).

Output

For output, the same see-saw depiction should be printed to stdout, but with one (and only one) of the weights replaced with a larger weight, so as to balance the see-saw. Inputs are guaranteed to make this possible using integers alone. Therefore, weights must be shown without decimal points or any other similar notations. If your language does not use stdout you should go by community / meta consensus on output. Trailing newlines are fine but any other changes to the depiction format are probably not OK.

Exemplification

Test Inputs and Corresponding Outputs

Input 1

12                22
--------------------
             ^      

Output 1

12                26
--------------------
             ^      

Input 2

42       42
-----------
     ^     

Output 2

42       42
-----------
     ^     

Input 3

3             16
----------------
        ^      

Output 3

14            16
----------------
        ^      

Input 4

1                56
-------------------
    ^              

Output 4

196              56
-------------------
    ^              

Reference Implementation - Python 3

# Takes a list of strings as input
def balance_seesaw(lines):
    weights = [int(w.strip()) for w in lines[0].split()]

    length  = len(lines[1])
    pivot   = lines[2].find("^")
    left_length    = pivot
    right_length   = length - 1 - pivot

    left_torque  = weights[0] * left_length
    right_torque = weights[1] * right_length

    if left_torque > right_torque:
        weights[1] = left_torque // right_length
    elif right_torque > left_torque:
        weights[0] = right_torque // left_length

    weights = [str(w) for w in weights]

    string_gap = " " * (length - sum(len(w) for w in weights))
    lines[0] = weights[0] + string_gap + weights[1]

    print("\n".join(lines))

balance_seesaw(["1                56",
                "-------------------",
                "    ^              "])

Rules

  • This is , so the shortest code wins counted in bytes. Check meta if counting bytes is awkward in your language.

  • Standard rules/loopholes apply.

  • Input must be taken in a reasonable format. A non-exhaustive list of appropriate formats are given as follows:

    • A single string with lines separated by newline characters
    • A list of strings, each string represented a line
    • A 2D Array or Matrix of characters

Related Challenges


\$\endgroup\$
4
  • \$\begingroup\$ Is there any reason you want output to stdout? We generally allow functions to output via their return value. \$\endgroup\$
    – corvus_192
    Nov 12, 2016 at 19:40
  • \$\begingroup\$ @corvus_192 I envisaged this as a 'display' type challenge, like an ASCII art one or 'Draw a flag' or whatever. A list of strings as output isn't really 'human friendly' as such. If a language has no inbuilt stdout support other output forms are allowed though. \$\endgroup\$
    – FourOhFour
    Nov 12, 2016 at 19:57
  • \$\begingroup\$ Welcome to PPCG! Nice first challenge. (and props for using the sandbox on it, too!) \$\endgroup\$ Nov 13, 2016 at 19:42
  • \$\begingroup\$ @TimmyD thanks, it's been good fun seeing how people tackle the problem. \$\endgroup\$
    – FourOhFour
    Nov 13, 2016 at 19:51

8 Answers 8

5
\$\begingroup\$

05AB1E, 60 51 50 49 47 45 bytes

Saved 10 bytes thanks to Emigna and 1 byte thanks to Adnan.

All input lines must have the same amount of characters.

#õKD³'^¡€gDŠ*¬-Os÷1®‚*D0›*+¬?DJg²gs-ð×?¤,²,³,

#                                             Split the first input line on spaces
 õKD                                          Push [first weight, second weight] twice
    ³'^¡€gD                                   Push both lengths from either side of the pivot '^' as an array [left, right] twice
           Š*                                 Multiply by weights to get torque
             ¬-O                              Evaluate rightTorque-leftTorque
                s÷                            Divide by each side's length to get the weights to add: [deltaLeft, deltaRight], keep integer values
                  1®‚                         Push [1,-1]
                     *D                       Yield [deltaLeft, -deltaRight]
                       0›*                    Replace the negative value by 0
                          +                   Add weights: old + deltaWeight
                           ¬?                 Print left weight
                             DJg              Take the size of total decimal representation
                                ²gs-ð×?       Print a string composed of filler spaces between both new weights
                                       ¤,     Print right weight and newline
                                         ²,³, Print the last two lines from input (unchanged)

Try it online!

There should be a rule of thumb, like "if your 05AB1E code is longer than 40 bytes, you're probably doing it wrong". It seems so golfable, any idea is welcome!

\$\endgroup\$
14
  • 1
    \$\begingroup\$ For a start ¬s¤s\‚ can be õK. \$\endgroup\$
    – Emigna
    Nov 12, 2016 at 14:34
  • 1
    \$\begingroup\$ kD²g->(‚ can be ¡€g if you add the missing spaces in bottom row of the test case \$\endgroup\$
    – Emigna
    Nov 12, 2016 at 14:39
  • 1
    \$\begingroup\$ Thanks for the explanation. I see it's quite similar to the reference algorithm (no bad thing) but there's some clever tricks in there too. Something about 05AB1E means that it seems to promote cleverer answers than some other golfing languages - it's perhaps my favourite especially when there's an included explanation. \$\endgroup\$
    – FourOhFour
    Nov 12, 2016 at 16:54
  • 1
    \$\begingroup\$ Nice answer! You can replace 31SÍ with 1®‚ :) \$\endgroup\$
    – Adnan
    Nov 12, 2016 at 22:17
  • 1
    \$\begingroup\$ Can you perhaps also replace / ï with ÷.? \$\endgroup\$
    – Emigna
    Nov 13, 2016 at 10:27
5
\$\begingroup\$

JavaScript (ES6), 136

Probably not working in Chrome,as it uses destructured assignment and default parameters.

Note that the standard JS output method alert is particularly unsuited for the task, because of the proportional font used.

(m,n,o,[p,q]=m.split(/ +/),l=n.length,h=o.indexOf`^`,g=l-h-1,c=p*h<q*g?q*g:p*h)=>alert((c/h+o).slice(0,h)+(o+c/g).slice(h-l)+`
${n}
`+o)

Less golfed

( m,n,o, // input parameters, 3 strings
  // default parameters used as local variables
  [p,q] = m.split(/ +/), // left and right weight
  l = n.length, // bar length
  h = o.indexOf`^`, // left length
  g = l-h-1, // right length
  // p*h left torque
  // q*g right torque
  c = p*h<q*g ? q*g : p*h // max torque
) => alert( (c/h+o).slice(0,h)+(o+c/g).slice(h-l) // o has enough spaces to pad left and right
     +`\n${n}\n`+o )

Test

F=
(m,n,o,[p,q]=m.split(/ +/),l=n.length,h=o.indexOf`^`,g=l-h-1,c=p*h<q*g?q*g:p*h)=>alert((c/h+o).slice(0,h)+(o+c/g).slice(h-l)+`
${n}
`+o)

function go()
{
  var [a,b,c]=I.value.split('\n')
  if(a.length!=b.length || a.length < c.length)
    alert('The strings are not of the same length')
  else 
  {  
    if (a.length > c.length)
      c = c+' '.repeat(a.length-c-length)
    F(a,b,c)
  }  
}
<textarea id=I>3             16
----------------
        ^      </textarea>
<button onclick='go()'>go</button>

\$\endgroup\$
2
  • \$\begingroup\$ According to kangax.github.io/compat-table/es6, Chrome 54 fully supports default parameters and destructuring, so I don't think you have to worry too much. \$\endgroup\$ Nov 13, 2016 at 4:22
  • \$\begingroup\$ Works on Chrome for me. \$\endgroup\$
    – DLosc
    Nov 15, 2016 at 2:29
3
\$\begingroup\$

Perl, 149+2=151 characters

Requires command line options -p0 (this gives me a 2 byte penalty on top of the 149 bytes in the program itself).

($_,$b,$c,$d)=map length,/(\d+) +(.+)
(-+)
( +)/;$r=$d/($c-$d-1);($x,$y)=$1*$r>$2?($1,$1*$r):($2/$r,$2);$_="$x$,$y",$,.=$"while$c>length;$\="
$3
$4^"

Explanation:

  • The -p0 switch reads the entire input up to the first NUL byte or EOF. This problem doesn't allow NULs, so we'll get the entire input in the variable $_ that's used for regexes, etc., by default.
  • We start with a regex that parses the input (between the first and second slash). There are several ways we could parse the first weight (e.g. .+?), but I can't get it below 3 characters so I may as well use the obvious \d+. The second number is at the end of the line so it can be parsed as .+ (2 characters). The central line is used to determine how wide the scales are; it's parsed as -+ (many other representations would work). The spaces before the caret on the last line are +. Once the caret (or indeed any nonspace) appears, we ignore the rest of the input.
  • Perl automatically captures the four groups of the regex (first weight, second weight, row of hyphens, spaces before the caret) into $1, $2, $3, $4. Giving a regex as an argument to map additionally uses an array of those groups as the array to map over. We therefore take their lengths; this is a convenient way to store the lengths of $3 and $4 without having to write length twice. We also overwrite $_ with the length of $1; we don't really care about the value of this (the number of digit in the left input is kind-of useless), but the fact that it's short ($_'s length is now the number of digits in the number of digits in the first weight, which is necessarily very small compared to the width of the scales).
  • We measure the ratio $r in which the scales are divided.
  • $1*$r>$2 checks to see which side is heavier. We store the new weights in $x and $y; these have very simple calculations once the ratio of weights is known.
  • We concatenate $x, $,, and $y into $_ to produce the top row, then keep adding spaces ($" contains a single space by default, and is shorter than a literal space ' ' would be) onto $, until it's the same length as the middle row (i.e. has length $c). (I chose the variable $, as it's a built-in variable that can safely be changed in this context and starts empty by default.) As length operates on $_ by default, we don't need to give it an argument explicitly. I used a Yoda conditional because it needs considerably less disambiguating syntax to parse correctly.
  • Finally, I redefine Perl's idea of the output line ending convention ($\) to contain the rest of the set of scales (which is the same as in the input, so I can simply use $3 and $4 directly to produce the bulk of it). Note that this means that there's no trailing whitespace on the third line; adding it would make the program slightly longer and doesn't seem to serve any purpose, so I left it out.
  • At the end of the program, the -p switch triggers again; this time, it outputs $_ followed by a "newline" ($\). Because I redefined the output newline, these two implicit prints generate the new set of scales between them (although as a side effect, there's no newline on the output).
  • The -p switch now tries to read input again, but we already slurped the entire file, so it reads EOF and ends the program.
\$\endgroup\$
1
\$\begingroup\$

PHP, 212 209 205 bytes

probably golfable

preg_match("#(\d+)( +)(\d+)\s*(-+)[\r\n]+( +)\^#",$s=$argv[1],$m);echo preg_replace("#\d+( +)\d+#",(($r=$m[3])>($q=$m[1]*($p=strlen($m[5]))/(-$p-1+$e=strlen($m[4])))?$r*$e/($p+1)-$q=$r:$m[1]).$m[2].$q,$s);

Takes input from command line argument; escape newlines. Run with -r.


Replacing with a placeholder did not work as expected; so I had to add more parens to the first regex.

\$\endgroup\$
1
\$\begingroup\$

Befunge, 223 217 bytes

&:00p&10p~$0>~#<2#+%#1_:20p0~>8#~%#+!#1_:3v
v\g01/g03*g01_v#!\g04`*g01g04:*g03p04-1-p0<
>#g>#0>#0>#/>#<:.2\5>5>#\+/#1:#\_$50p:50g\5>5>#\+/#1:#\_$20g\-v>
1#,>#*-#4:#8_$.55+,20g>:#,1#*-#9\#5_55+,30g>:#,1#*-#8\#4_"^",@>>

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 215 bytes, I think \$\endgroup\$
    – Adalynn
    Dec 7, 2018 at 14:30
  • \$\begingroup\$ @Zacharý I'm afraid not. At least one of those arrows is needed, otherwise it'll fail whenever left torque > right torque (the first test case for example). The other > I think was just left for aesthetic reasons. That said, I do seem to have a 215 byte solution in my notes, so it may be possible (it my also have bugs which would explain why I never submitted it - don't have time to test it now). \$\endgroup\$ Apr 23, 2019 at 1:38
1
\$\begingroup\$

Python 2, 184 183 bytes

Definitely golfable

i=raw_input
j=int
w=map(j,i().split())
W=len(i())
I=i().find('^')
R=W-I-1
a=[w[1]*R/I,w[0]*I/R]
h=a[1]>w[1]
w[h]=j(a[h])
k='\n'
print(' '*(W-len(str(w))+4)).join(map(str,w))+k+'-'*W+k+' '*I+'^'

Pretty straightforward. Just take the adjusted weights for adjusting both sides, see which one's larger than the original, and change that one, and output.

EDIT Switched multiplication and division because integer division is evile (thanks to @JonathanAllan for noticing this)

EDIT -1 byte Changed i().index('^') to i().find('^') (thanks to @JonathanAllan [again!])

\$\endgroup\$
2
  • \$\begingroup\$ You should swap the multiplication and division since the division is integer division - i.e. a=[w[1]*R/I,w[0]*I/R] (a simple example that would not work would be a 1 and 2 with I and R both 3). Currently 194 not 184 by the way since the newlines count as a byte each, but j and k are costing more bytes than they save. \$\endgroup\$ Nov 13, 2016 at 10:17
  • \$\begingroup\$ You can use I=i().find('^'), and the short form of __repr__, backticks to make the last line print`w[0]`+' '*(W-len(`w`)+4)+`w[1]`+'\n'+'-'*W+'\n'+' '*I+'^' and get down to 182 - repl.it/EW8f \$\endgroup\$ Nov 13, 2016 at 10:41
0
\$\begingroup\$

C++ 14, 482 bytes

include<iostream>#include<string>#include<math.h>usingnamespacestd;intmain(){stringa,b,c,d;intj=0;inte[2];getline(cin,a);getline(cin,b);getline(cin,c);for(inti=0;i<a.size();i){if(isdigit(a.at(i))){while(i<a.size()&&isdigit(a.at(i))){d=a.at(i);i;}e[j]=stoi(d);d="";}}strings(b.size()-(int)log10(e[0])-(int)log10(e[1])-2,'');intl1=(c.size()-1);intl2=(b.size()-c.size());intl=e[0]*l1;intr=e[1]*l2;if(l>r)e[1]=l/l2;elsee[0]=r/l1;cout<<e[0]<<s<<e[1]<<endl;cout<<b<<endl;cout<<c;return0;}

more readable version:

#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main() {
    string a,b,c,d;
    int j=0;
    int e[2];
    // input
    getline(cin,a);// 1st line
    getline(cin,b);// 2nd line
    getline(cin,c);// 3rd line
    for (int i=0;i<a.size();i++) {
        if(isdigit(a.at(i))){
            while(i<a.size() && isdigit(a.at(i))){
                d+=a.at(i);
                i++;
            }
            e[j++]=stoi(d);
            d="";
        }
    }
    // amount of white space in between 2 numbers
    string s(b.size()-(int)log10(e[0])-(int)log10(e[1])-2,' ');
    int l1 = (c.size()-1);
    int l2 = (b.size()-c.size());
    int l = e[0]*l1;
    int r = e[1]*l2;
    // change the side with smaller torque
    if (l>r)
        e[1]=l/l2;
    else
        e[0]=r/l1;
    // output
    cout<<e[0]<<s<<e[1]<<endl;// 1st line
    cout<<b<<endl;// 2nd line
    cout<<c;// 3rd line
    return 0;
}
\$\endgroup\$
0
\$\begingroup\$

Python 3, 235 230 bytes (minimized reference)

I just minimized the reference, since I'm very new to code-golfing.

def s(l):
 w,i,t=[int(z.strip())for z in l[0].split()],len(l[1]),l[2].find("^");k,o=i-1-t,w[0]*t;p=w[1]*k
 if o>p:w[1]=o//k
 else:w[0]=p//t
 w=[str(z)for z in w];s=" "*(i-sum(len(z)for z in w));l[0]=w[0]+s+w[1];print("\n".join(l))

You use it exactly the same as the example, but the function is s instead of balance_seesaw.

\$\endgroup\$
3
  • \$\begingroup\$ Lines 5 and 6 could become w[o>p]=[o//k,p//t][o>p]. Also, most of the lines could be joined to get rid of some extra whitespace. \$\endgroup\$
    – DJMcMayhem
    Nov 14, 2016 at 17:59
  • \$\begingroup\$ Thanks, as I said, I'm very new, so I overlook even the simplest fixes. \$\endgroup\$ Nov 14, 2016 at 18:05
  • \$\begingroup\$ Except, it doesn't work, instead providing 0,56 instead of 196,56. \$\endgroup\$ Nov 14, 2016 at 18:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.