9
\$\begingroup\$

The challenge

Given two strings, each of length up to 30, consisting of printable ASCII characters (codes \$[32, 126]\$), put them onto a balance scale in the fewest bytes of code! This consists of the following steps:

  1. Calculate and compare the weights of the strings
  2. Choose the appropriately tilted ASCII-art scale
  3. Place the two strings onto the scale

The strings may be passed as an array, two arguments, or any other reasonable method.


The weight of a string is defined as the sum of the weights of that string's characters, where:

  • Spaces have a weight of 0 ()
  • Lowercase letters have a weight of 2 (abcdefghijklmnopqrstuvwxyz)
  • Uppercase letters have a weight of 4 (ABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • All other symbols have a weight of 3 (!"#$%&'()*+,-./0123456789:;<=>?@[\]^_`{|}~)

The scales look like this:

          .     _
          |  _-*/\
          |-*  /  \
       _-*|   /    \
    _-*   |  /      \
   /\     |  *------*
  /  \    |
 /    \   |
/      \  |
*------*  |
    ______|______
    _     .
   /\*-_  |
  /  \  *-|
 /    \   |*-_ 
/      \  |   *-_
*------*  |     /\
          |    /  \
          |   /    \
          |  /      \
          |  *------*
    ______|______
          .
          |
    ______|______
   /\     |     /\
  /  \    |    /  \
 /    \   |   /    \
/      \  |  /      \
*------*  |  *------*
          |
          |
    ______|______

If the first string is heavier, use the first drawing as the base of your output; if the second string is heavier, use the second drawing; if the strings have equal weight, use the third. Trailing whitespace is allowed.


I will be using a segment of the third drawing as the base for all of the following examples.

The first string should be placed onto the left pan, and the second string onto the right pan.

Place a string on a pan by placing its non-space characters within the 6x5 area immediately above the dashes, as marked by #s here (you may end up overwriting part of the balance scale - that is fine):

 ######_
 ######
 ######
 ######
/######\
*------*

All of these characters should be "settled" ie. either above a - character or another character from the string:

  WRONG         WRONG        CORRECT
    ____          ____          ____
 f /\            /\            /\
  l  \          /  \          /  \
 /    \        / hov\        / s  \
/oating\      /eri ng\      /ettled\
*------*      *------*      *------*

Additionally, the whole stack should be as flat as possible, meaning that of the six 1-wide columns, the height of the tallest and the height of the shortest must not differ by more than 1:

    WRONG              WRONG             CORRECT            CORRECT
[tallest:  5]      [tallest:  4]      [tallest:  5]      [tallest:  2]
[shortest: 0]      [shortest: 2]      [shortest: 4]      [shortest: 2]
      5__5_               ____              5_5__               ____
     45445             & /\               445454               /\
     45445             $% &$@             445454              /  \
    /45445             &%@%$&             445454             %&$@%&
   / 45445\           /&$@$&%\           /445454\           /$@$%$$\
   *------*           *------*           *------*           *------*

The exact order/arrangement of the characters does not matter. The following are all valid arrangements for the string "Weigh your words!":

    ____          ____          ____          ____
   /\            /\            /\            /\
 ds! \          / owd         oe \u        !Wd \
 ourwor        Wihuos        yoiwgr        eghioo
/Weighy\      /egyrr!\      /Wrhd!s\      /rrsuwy\
*------*      *------*      *------*      *------*

Test cases

INPUT: "CODE GOLF", "coding challenges"
WEIGHTS: 32, 32
EXAMPLE OUTPUT:
          . 
          |
    ______|______
   /\     |     /\
  /  \    |    nge\s
 /OO  \   |   challe
/CFGLED\  |  /coding\
*------*  |  *------*
          |
          |
    ______|______ 
INPUT: "", "$"
WEIGHTS: 0, 3
EXAMPLE OUTPUT:
    _     .
   /\*-_  |
  /  \  *-|
 /    \   |*-_ 
/      \  |   *-_
*------*  |     /\
          |    /  \
          |   /    \
          |  /    $ \
          |  *------*
    ______|______
INPUT: "YOU KNOW WHAT THEY SAY!", "there's_always_a_relevant_xkcd"
WEIGHTS: 75, 65
EXAMPLE OUTPUT:
          .   tr_a_s
          |  _hekx_y
          |-* elcdta
       _-*|   revanw
    _-*   |  /e's_al\
  T/\     |  *------*
 AUYOHY   |
 A!HWYK   |
/OTSMEW\  |
*------*  |
    ______|______
\$\endgroup\$
  • 1
    \$\begingroup\$ Is trailing whitespace acceptable? \$\endgroup\$ – Hiatsu Aug 21 at 18:17
  • \$\begingroup\$ @Hiatsu Yep, that's fine. \$\endgroup\$ – negative seven Aug 21 at 19:59
  • 2
    \$\begingroup\$ I like this challenge, I really do. However there are 2 points preventing me from giving it my +1. Firstly: if spaces don't "weigh" anything and don't get included in the artwork then why include them at all? It's just unnecessary overhead to first filter them out. Secondly: this feels like a "2-in-1"/chameleon challenge to me - Challenge 1: Determine which string is "heavier", Challenge 2: Generate some ASCII-art. \$\endgroup\$ – Shaggy Aug 22 at 23:23
  • \$\begingroup\$ @Shaggy I think that's a fair assessment. Posting this has taught me to just keep things simple. \$\endgroup\$ – negative seven Aug 23 at 9:05
7
\$\begingroup\$

Charcoal, 110 bytes

UMθ⪫⪪ι ω≔⁰ηFθ≦⁻ΣEι⁻⁺³№ακ№βκηP-×⁷_↑χ.¶¶≔³ζ¿η«≔∨›⁰η⁵ζM±⁶±²_F⁴⁺¶*-§_|_ι¿›⁰η‖»P-⁺|×⁶_J±⁴±ζFθ«←⁶↑*↗⁴↓↘⁴←↖*←⪪ι⁶J⁹⁻ζ⁶

Try it online! Link is to verbose version of code. Takes input as an array of two strings. Explanation:

UMθ⪫⪪ι ω

Remove the spaces from both strings.

≔⁰η

Assume the weights balance.

Fθ

Loop over both strings.

≦⁻ΣEι⁻⁺³№ακ№βκη

Subtract the running difference from the weight of the string.

P-×⁷_↑χ.¶¶

Print the base of the balance scale.

≔³ζ

Assume that both pans are 3 off the ground.

¿η«

If the weights didn't balance...

≔∨›⁰η⁵ζ

... calculate the height of the left pan...

M±⁶±²_F⁴⁺¶*-§_|_ι

... draw the balance leaning down to the right...

¿›⁰η‖»

... and reflect if the left pan was heavier.

P-⁺|×⁶_

Otherwise draw a level balance.

J±⁴±ζ

Jump to the first scale pan.

Fθ«

Loop over the inputs.

←⁶↑*↗⁴↓↘⁴←↖*

Draw the scale pan.

←⪪ι⁶

Slice the input into substrings of length 6 and print them upside-down so that they fill the pan upwards.

J⁹⁻ζ⁶

Jump to the second scale pan.

\$\endgroup\$
6
\$\begingroup\$

Python 2, 1101 1071 855 837 bytes

-216 bytes with string compression

-18 bytes by reducing some repetition

from zlib import decompress as Z
from base64 import b64decode as D
r=range(6)
j="".join
w=lambda a:0if not a else(2+2*(a[0]<'[')if a[0].isalpha()else 3)+w(a[1:])
t=Z(D('eJxT0FKIV1BQ0AWT8SAIJsAcXTCppQAGumBSSx8MYsBAC0kCAiCySAIKEJW4ZHGpxA8AejMemQ=='))
p=lambda k,l,m:j(map(j,[(t[2*l+m::6][:30-len(k)]+k)[i::6]for i in r]))
def A(a,b):
 e=cmp(w(j(a.split())),w(j(b.split())))+1;return Z(D('eJxVUUGuhTAI3HOKWTdBW/U2SHoQ4O6ftvrMb0hLZJgZAYABFZB5KxD4zrZtNJOJMaHWIIoa0D6Ao+jrWRiHEI7kMcQg9VLBCo9O3dCbdanepOvZQztF9rRH2xUlwISehIZ96HltLFqu1IMF2p1QH/S+1Ge7CT5blIVOxqUWFudjqHPSwhitjPbzf7uZ1HaIaG2hShFTfU7Eca6J7MBr1K+3/YbRVLd2VlE5oilp7EG/gV7+DPQuSAsZPm7PZE9HBY2G+ctS/QzR+whSGlPAGz4mkkl5Sf18SMvkyL9iF6aLd2WLUm/KDVzvJu93k2tLZXlwetgLmFH4MzcKCaJnqX1Fz3iOf4//Pi7EwP4BHmyJpg=='))[e::3].format(*map(lambda c:[p(j(([a,b]*3)[c].split()),e,c)[i::5]for i in r],r))

Try it online!

Run as A(string_one, string_two.

w calculates the weight of the string recursively.

t is the compressed and interlaced text of all six possible scales, which happens to compress very nicely.

p takes the string (with spaces removed), the weight of the string, and the side of the balance that string is on, and creates a 5x6 block of characters.

A takes the strings, and builds their blocks with p. The giant string at the bottom is three format strings interlaced and compressed.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6),  340  337 bytes

Takes input as an array of 2 arrays of characters. Draws the output character by character.

S=>(s=Math.sign(~(g=i=>(S[i]=S[i].filter(c=>c>' '?i+=/[a-z]/gi.test(c)?c>{}?2:4:3:0),i))(0)+g(1))+1,g=x=>y>10?'':(X=(r=x>9)?20-x:x,Y=(r?2-s:s)*2+y,S[+r][X>0&&X<7&&47-Y*6+X]||`. /\\|-_*
`[~X?x-10?y>9?X>3?6:1:[x+y*3-17,2*y-4,x+~y*3][s]/2|X<4?Y<5|Y>8?Y-9|X>7?1:X%7?5:7:~X+Y?X+Y-8?1:2^r:3^r:[7-x%3,6,5+x%3][s]:y&&4:8])+g(x<21?x+1:!++y))(y=0)

Try it online!

How?

We define a first helper function that removes spaces from the input string \$S[i]\$ and returns its weight:

g = i => (                   // i = string index
  S[i] = S[i].filter(c =>    // for each character c in S[i]:
    c > ' ' ?                //   if c is not a space:
      i +=                   //     update i:
        /[a-z]/gi.test(c) ?  //       if c is a letter:
          c > {} ?           //         if c is in lower case:
            2                //           add 2 to i
          :                  //         else:
            4                //           add 4 to i
        :                    //       else (not a letter):
          3                  //         add 3 to i
    :                        //   else (a space):
      0                      //     remove c from S[i]
  ), i                       // end of filter(); return i
)                            //

NB: Because we re-use \$i\$ to compute the weight, it is off by one for \$S[1]\$.

We compute \$s\$, which is equal to \$0\$ if \$S[0]\$ is heavier, \$2\$ if \$S[1]\$ is heavier, or \$1\$ if both strings have the same weight:

s = Math.sign(~g(0) + g(1)) + 1

We now invoke the second helper function to draw the output:

g = x =>                     // given x:
  y > 10 ?                   //   if we've reached the last row:
    ''                       //     stop recursion
  :                          //   else:
    ( X = (r = x > 9) ?      //     r = true if we're on the right side
        20 - x               //       X = 20 - x on the right side
      :                      //     or:
        x,                   //       X = x on the left side
      Y = (r ? 2 - s : s)    //     Y is the position of the scale tray
          * 2 + y,           //     according to s and the current side
      S[+r][                 //     we try to extract a character from S[0] or S[1]:
        X > 0 && X < 7 &&    //       provided that we're located above the tray
        47 - Y * 6 + X       //       and using an index based on (X, Y)
      ] ||                   //     if this character doesn't exist,
      `. /\\|-_*\n`[INDEX]   //     we need to draw the balance instead
    ) +                      //     (see the next part)
    g(x < 21 ? x + 1 : !++y) //     append the result of a recursive call

Where INDEX is computed as follows:

~X ?                         // if this is not the last character of the current row:
  x - 10 ?                   //   if this is not the central column:
    y > 9 ?                  //     if this is the last row:
      X > 3 ? 6 : 1          //       draw the base ('_' or a space)
    :                        //     else:
      [ x + y * 3 - 17,      //       attempt to draw the beam:
        2 * y - 4,           //         using an equation depending on s
        x + ~y * 3           //         whose result must be -1, 0 or 1
      ][s] / 2 | X < 4 ?     //       if it's invalid or X is less than 4:
        Y < 5 | Y > 8 ?      //         if we're not over the chains:
          Y - 9 | X > 7 ?    //           if we're not over the pan:
            1                //             draw a space
          :                  //           else:
            X % 7 ? 5 : 7    //             draw the pan ('-' or '*')
        :                    //         else:
          ~X + Y ?           //           if this is not an interior chain:
            X + Y - 8 ?      //             if this is not an exterior chain:
              1              //               draw a space
            :                //             else:
              2 ^ r          //               draw the exterior chain ('/' or '\')
          :                  //           else:
            3 ^ r            //             draw the interior chain ('/' or '\')
      :                      //       else:
        [ 7 - x % 3,         //         draw the beam, using either '_' -> '-' -> '*'
          6,                 //         or just '_'
          5 + x % 3          //         or '*' -> '-' -> '_'
        ][s]                 //         depending on s
  :                          //   else:
    y && 4                   //     draw the central pillar ('|' or '.')
:                            // else:
  8                          //   append a line feed
\$\endgroup\$
1
\$\begingroup\$

Java 10, 1043 993 988 983 bytes

(a,b)->{var r=new char[11][21];for(var A:r)java.util.Arrays.fill(A,' ');a=a.replace(" ","");b=b.replace(" ","");int A=s(a),B=s(b),j,c,i=3;for(;++i<17;r[3][i]=A==B?'_':32)r[10][i]=95;for(i=11;i-->1;)r[i][10]=i>0?'|':46;if(A==B){r[8][0]=r[8][7]=r[8][13]=r[8][20]=42;for(i=0;++i<20;)if(i<8|i>13)r[8][i]=45;for(i=8;i-->4;r[i][7-i]=r[i][20-i]=47)r[i][i]=r[i][i+13]=92;A=B=8;}else{r[5][i=A<B?0:13]=r[5][i+7]=r[9][13-i]=r[9][20-i]=42;for(i=5;i-->1;r[i][A>B?18-i*3:2+i*3]=42)r[i][A>B?17-i*3:3+i*3]=45;for(i=0;++i<20;)r[i>13?A>B?5:9:A>B?9:5][i>13|i<7?i:1]=45;for(i=9;i-->1;r[i][i>4?A>B?8-i:21-i:A>B?17-i:4-i]=47)r[i][i>4?A>B?i-1:i+12:A>B?i+16:i+3]=92;A=(A>B?r[i=0][16]=r[1][13]=r[3][7]=r[4][4]=95:(r[0][i=4]=r[1][7]=r[3][13]=r[4][16]=95));A=9-i;B=5+i;}c(r,a,A,7);c(r,b,B,20);return r;};int s(String s){int r=0;for(int i:s.getBytes())r+=i>64&i<91?4:i>96&i<123?2:3;return r;}void c(char[][]r,String s,int p,int q){for(int c=0,i=p,j;i-->p-5;)for(j=q;j-->q-6&c<s.length();)r[i][j]=s.charAt(c++);}

-5 bytes thanks to @ceilingcat.

Input are two Strings, which will result in a character-matrix as result.

Try it online.

Explanation:

// Method with two String parameters and character-matrix return-type:
(a,b)->{
  // Result matrix, with 11 rows and 21 columns:
  var r=new char[11][21];
  // Initially fill the entire matrix with spaces:
  for(var A:r)java.util.Arrays.fill(A,' ');
  // Remove all spaces from the input-Strings:          
  a=a.replace(" ","");b=b.replace(" ","");
  // Call a separated method to calculate the scores of both input-Strings:
  int A=s(a),B=s(b),

  // Fill the cells for the base with '_',
  // and also fill the cells for the balance-bar with '_' when the scores are equal:
  j,c,i=3;for(;++i<17;r[3][i]=A==B?'_':32)r[10][i]=95;
  // Fill the cells for the stand with '|':
  for(i=11;i-->1;)r[i][10]=i>0?'|'
  // And the top of it with '.':
  :46;

  // If the scores are equal:
  if(A==B){
    // Fill the four appropriate cells for the sides of the scales with '*':
    r[8][0]=r[8][7]=r[8][13]=r[8][20]=42;
    // Fill the appropriate cells for the scales themselves with '-':
    for(i=0;++i<20;)if(i<8|i>13)r[8][i]=45;
    // Fill the appropriate cells of the robes with '/' and '\':
    for(i=8;i-->4;r[i][7-i]=r[i][20-i]=47)r[i][i]=r[i][i+13]=92;
    // Set A and B both to 8 to use later on:
    A=B=8;}
  // If the scores aren't equal:
  else{
    // Fill the four appropriate cells for the sides of the scales with '*':
    r[5][i=A<B?0:13]=r[5][i+7]=r[9][13-i]=r[9][20-i]=42;
    // Fill the appropriate four cells of the balance-bar with '-':
    for(i=5;i-->1;r[i][A>B?18-i*3:2+i*3]=42)r[i][A>B?17-i*3:3+i*3]=45;
    // Fill the appropriate cells of the scales with '-':
    for(i=0;++i<20;)r[i>13?A>B?5:9:A>B?9:5][i>13|i<7?i:1]=45;
    // Fill the appropriate cells of the robes with '/' and '\':
    for(i=9;i-->1;r[i][i>4?A>B?8-i:21-i:A>B?17-i:4-i]=47)r[i][i>4?A>B?i-1:i+12:A>B?i+16:i+3]=92;
    // Fill the four appropriate cells of the balance-bar with '_',
    // and set A and B to 9 and 5 depending on which score is higher:
    A=(A>B?r[i=0][16]=r[1][13]=r[3][7]=r[4][4]=95:(r[0][i=4]=r[1][7]=r[3][13]=r[4][16]=95));A=9-i;B=5+i;}
  // Call a separated method to fill the cells above the scales with the input-characters:
  c(r,a,A,7);c(r,b,B,20);
  // And finally return the resulting character-matrix:
  return r;};

// Separated method to calculate the score of the given String:
int s(String s){
  // Initially start the score-sum at 0:
  int r=0;
  // Loop over the characters of the given String:
  for(int i:s.getBytes())
    // Increase the sum by:
    r+=
      // 4 for uppercase letters:
      i>64&i<91?4
      // 2 for lowercase letters:
      :i>96&i<123?2
      // 3 for any other character:
      :3;
  // And return the resulting sum:
  return r;}

// Separated method to draw the strings on top of the scales:
void c(char[][]r,String s,int p,int q){
  // Keep a counter so we know when we're done drawing the given String:
  for(int c=0,
  // Loop over the appropriate rows bottom to top:
  i=p,j;i-->p-5;)
    // Inner loop over the appropriate cells of this row left to right,
    for(j=q;j-->q-6
    // as long as we're not done yet with the input-String:
        &c<s.length();)
      // And fill that appropriate cell with the next character in line of the given String:
      r[i][j]=s.charAt(c++);}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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