13
\$\begingroup\$

Challenge:

You'll be given an ASCII image of a pile of weights as input, and must output the combined weight of the pile.

enter image description here

Format:

There are 5 different weights, weighing 1, 2, 5, 10, 20 Passerees (or some other arbitrary unit).

The weights looks like this, in ascending order:

1:   __
    |__|

2:   ______
    |______|

5:   ______
    |      |
    |______|

10:  ______________
    |              |
    |______________|

20:  ____________________
    |                    |
    |____________________|

The weighs will be symmetrically placed (as in the example image), not necessarily in a sorted order. Weighs will share boundaries, where applicable:

Test cases:

You may use all the single weights as test cases too.

   __
 _|__|_
|______|
|      |
|______|
1 + 2 + 5 = 8

 ____________________
|                    |
|____________________|
   |              |
   |______________|
        _|__|_
       |______|
       |      |
       |______|          
20 + 10 + 1 + 2 + 5 = 38 

 ______
|______|
|______|
|______|
|______|
2 + 2 + 2 + 2 = 8

Additional rules:

  • You may not assume additional leading spaces. The largest weight will be all the way to the left.
  • You may assume trailing spaces and newlines.
  • You may assume there will be maximum 10 weights
  • You may take the input on an optional format, but you can't substitute the characters used by something else

This is so the shortest code in bytes each languages wins. Explanations are encouraged as always.

\$\endgroup\$
  • \$\begingroup\$ Your challenge inspired me to write this one. Any tips are appreciated! \$\endgroup\$ – tgrass12 Apr 26 '18 at 22:50
7
\$\begingroup\$

Jelly,  24  23 bytes

ḟ⁶Ỵẹ€”|IFṚ’œṗ$Ḅ:3“ÇÞ‘yS

Try it online!

How?

The weights may be identified by their widths and heights. The widths may be measured by looking at the distance between the line's | characters. If we first remove all the spaces then those weights of height two will contribute such a line with a measured width of one.

The different weights have widths of 3, 7, 7, 15, 21 (for weights 1, 2, 5, 10, 20 respectively). Adding a trailing 1 for those of height two we find [3],[7],[7,1],[15,1],[21,1] converting from binary these are 3,7,15,31,43, integer dividing by three gives us 1,2,5,10,14, which are the weights except 14 needs replacing by 20.

ḟ⁶Ỵẹ€”|IFṚ’œṗ$Ḅ:3“ÇÞ‘yS - Link: list of characters    e.g. <example 2>
 ⁶                      - literal space character
ḟ                       - filter discard
  Ỵ                     - split at new lines
     ”|                 - literal pipe character
   ẹ€                   - get indices for €ach             [[],[1,2],[1,22],[1,2],[1,16],[2,5],[1,8],[1,2],[1,8]]
       I                - incremental differences          [[],[1],[21],[1],[15],[3],[7],[1],[7]]
        F               - flatten                          [1,21,1,15,3,7,1,7]
         Ṛ              - reverse                          [7,1,7,3,15,1,21,1]
             $          - last two links as a monad:
          ’             -   decrement                     [6,0,6,2,14,0,20,0]
           œṗ           -   partition at truthy indices   [[],[7,1],[7],[3],[15,1],[21,1]]
              Ḅ         - convert from binary             [0,15,7,3,31,43]
               :3       - integer divide by three         [0,5,2,1,10,14]
                 “ÇÞ‘   - code-page-indices               [14,20]
                     y  - translate                       [0,5,2,1,10,20]
                      S - sum                             38

Alternatively replace the measured widths of 21 with 30 prior to the conversion using “ßœ‘y:

ḟ⁶Ỵẹ€”|IF“ßœ‘yṚ’œṗ$Ḅ:3S
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Python 2, 77 bytes

lambda x:sum(i/21*x.count('|'+i%21*' _'[i<50]+'|')for i in[23,48,69,224,440])

Try it online!

[i/21, i%21, ' _'[i<50] for i in [23,48,69,224,440]] will generate the following triplets [1, 2, '_'], [2, 6, '_'], [3, 6, ' '], [10, 14, ' '], [20, 20, ' '] that represent the weight, the lenght and the character in the base of each weight, that will be used to make a unique single-line representation of each weight.
Since the 3rd weight would overlap with the 2nd, I replace it's base with it's body (_ -> ) and reduced the value to 3 (it will count the base as 2 and the body as 3, resulting in 5)

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Retina 0.8.2, 60 bytes

T`|`!
!__!
1
!_{6}!
11
! {6}!
3$*
!.{14}!
5$*
!.{20}!
10$*
1

Try it online! Explanation: The |s are replaced with !s for ease of matching, then the weights are converted into unary and totalled. The only interesting portion is that the 5 weight is considered to be the sum of a 2 and a 3 weight, while the 10 and 20 weights are just two lines of half the weight.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 73 bytes

x=>x.replace(/\|.*\|/g,s=>u+=s.length/4*(s[1]<1?s[21]?29/11:1.5:1),u=0)|u

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Python 3, 76 bytes

lambda t:sum([1,2,3,5,5,9,11][len(x)//4+(x<'_')]for x in t.split('|')[1::2])

Try it online!

How?

sum([1,2,3,5,5,9,11][len(x)//4+(x<'_')]for x in t.split('|')[1::2])
                                                t.split('|')         - split ascii art into pieces
                                                            [1::2])  - weights are at odd indexes
                                       for x in                      - iterates over the weights
                     len(x)//4                                       - map widths to 0,1,3,5,7
                              +(x<'_')                               - add 1 if the first row of 2-row weight
    [1,2,3,5,5,9,11][                 ]                              - value of each part of a weight
sum(                                                              )  - add 'em all up
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

I'm sure there are some improvements to be made, but this is what I have at the moment:

Groovy, 131 bytes

def f(s){s.split('\n').sum{n=0;[2:1,6:2,14:5,20:10].each{k,v->if(it==~".*\\|[ _]{$k}\\|.*"){n=v+(!it.contains('_')&&k==6?1:0)}};n}}

Converts the input String into a Collection<String> and then sums the results for each line to get the total. Uses a Map where the key is the number of spaces or underscores in between the pipe characters and the value is the corresponding Passerees amount. The key is plugged into the regex to determine if the line matches a significant pattern. The one caveat is the ternary to add 1 in the case where the length of the substring between the pipes is 6 and is composed of spaces (as opposed to underscores). If no pattern matches, the line has a value of 0.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Perl 6, 57 bytes

{sum map {.comb+>2*(1.5,3)[.comb>16]**!/_/},m:g/\|.*?\|/}

Try it online!

| improve this answer | |
\$\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.