40
\$\begingroup\$

Overview

The cover of a book will be provided in the following ASCII format:

______
|    |
|    |
|    |
|    |
------

The input can be in any reasonable format (eg. a list of strings, a nested list of characters, etc.)

Inside the "borders" of the cover, other printable ascii characters might appear, which contribute to the "popularity index" (the definition of which has been completely made up for this challenge).

Popularity Index

Let the popularity index of a book be the number of unique characters that appear on the book cover (this does not include space characters or the edges of the cover). A book may have no unique characters on the cover (the cover is blank), in which case the popularity index is 0.

Examples

______
|\/ /|
|/\/ |
| /\/|
|/ /\|
------

Two unique characters (/ and \) so the popularity index is 2.

______
| / /|
|/ / |
| / /|
|/ / |
------

One unique character (/), so the popularity index is 1

______
|    |
|    |
|    |
|    |
------

No unique characters, the popularity index is 0

______
|\^$@|
|/\/ |
| 456|
|/ /\|
------

8 unique characters, so the popularity index is 8.

______
|\^$@|
|987 |
| 456|
|/hi!|
------

14 unique characters, so the popularity index is 14.

______
|////|
|////|
|////|
|////|
------

One unique character (/), so the popularity index is 1.

Damaged Books

The edges of the book might also be damaged:

Top         Left        Right       Bottom

_~____      ______      ______      ______
|    |      |    |      |    |      |    |
|    |      |    |      |    |      |    |
|    |  or  {    |  or  |    }  or  |    |
|    |      |    |      |    |      |    |
------      ------      ------      ---~--

The book may have several of these "scratches". The scratches at the top and bottom will always be represented by a ~, while the scratches on the left and right will always be represented by a { and } respectively. Each scratch will decrease the popularity index by 1.

As a result, it is possible for a book to have a negative popularity index.

Task

Given an ASCII representation of a book cover in the format described above, determine the "popularity index" of the book

Assumptions

  • You can assume that the characters |, _, and - will not appear elsewhere on the book cover (only on the edges). However, the scratch characters ({, }, and ~) may appear on the book cover in which case they should be treated as any other unique character on the cover.

  • All characters appearing on the cover will be printable ascii

  • Note that spaces do not count as a unique character. As the examples above show, a "blank" cover is one that only contains spaces.

  • The book will always be the same size (height and width are fixed). Hence, the popularity index will never exceed 16.

Scoring

This is . Happy golfing!

More Examples

______
|{. }|
|/. /|
|/. /}
|/. /|
------

4 unique characters ({, }, . and /) and one scratch (} on the right) so the popularity index is 3.

______
{    |
| .. |
|    }
{    |
--~~--

One unique character (.) and 5 scratches so the popularity index is -4.

Test Cases

______
|    |
|    |
|    |
|    |
------    ->    0

______
|\/ /|
|/\/ |
| /\/|
|/ /\|
------    ->    2

______
| / /|
|/ / |
| / /|
|/ / |
------    ->    1

______
|\^$@|
|/\/ |
| 456|
|/ /\|
------    ->    8

______
|!!!!|
|+  +|
| ** |
|<**>|
------    ->    5

______
|\^$@|
|987 |
| 456|
|/hi!|
------    ->    14

______
|THIS|
| is |
| a. |
|BOOK|
------    ->    11

______
|////|
|////|
|////|
|////|
------    ->    1

______
|abcd|
|efgh|
|ijkl|
|mnop|
------    ->    16

______
|{. }|
|/. /|
|/. /}
|/. /|
------    ->    3

______
{    |
| .. |
|    }
{    |
--~~--    ->    -4

~~~~~~
{    }
{    }
{    }
{    }
~~~~~~    ->    -20

______
|~~~~|
|.   |
{....}
|.   |
------    ->    0

______
|{~~}|
|    |
|    |
|    |
------    ->    3

__~~__
|{~~}|
|    |
|    |
{    |
-----~    ->    -1
\$\endgroup\$
  • 3
    \$\begingroup\$ Why am I thinking of Pawn Stars' book expert while reading this?... :p \$\endgroup\$ – Arnauld May 27 at 21:09
  • 9
    \$\begingroup\$ The more scratches a book has, the more popular the book is. Like, I borrowed TAOCP from the library with about 56 scratches on the cover of a book. \$\endgroup\$ – user92069 May 28 at 8:04
  • 1
    \$\begingroup\$ @Arnauld Yes that's fine, since the length will always be the same \$\endgroup\$ – math junkie May 28 at 14:25
  • 3
    \$\begingroup\$ By the way there's a software challenge at the Internet Archive too: blog.archive.org/2019/01/05/… \$\endgroup\$ – Nemo May 28 at 19:07
  • 1
    \$\begingroup\$ The examples in the "Damaged books" section have dashes at the top. \$\endgroup\$ – Brian Minton May 29 at 14:04

18 Answers 18

18
\$\begingroup\$

JavaScript (ES6),  75 74  73 bytes

Takes a single string of 36 characters as input, i.e. without any line feed.

s=>s.replace(o=/[^ |_-]/g,(c,n)=>t+=n*9%56%37%9&1?o[c]^(o[c]=1):-1,t=0)|t

Try it online!

How?

We filter out spaces, pipes, underscores and hyphens:

/[^ |_-]/g

It means that we're going to match only:

  • scratches on the border (-1 point)
  • or non-space characters on the cover (+1 point the first time each of them appears)

Given the 0-indexed position \$n\$ of the character in the input string, the shortest solution I've found so far to figure out if we're located on the border or on the cover is the following convoluted modulo chain:

$$\big(((9\times n)\bmod 56)\bmod 37\big)\bmod 9$$

which gives:

$$\begin{pmatrix} 0&1&2&3&4&5\\ 6&7&8&9&10&11\\ 12&13&14&15&16&17\\ 18&19&20&21&22&23\\ 24&25&26&27&28&29\\ 30&31&32&33&34&35 \end{pmatrix} \rightarrow \begin{pmatrix} \color{blue}0&\color{blue}0&\color{blue}0&\color{blue}0&\color{blue}0&\color{blue}8\\ \color{blue}8&7&7&7&7&\color{blue}6\\ \color{blue}6&5&5&5&5&\color{blue}4\\ \color{blue}4&3&3&3&3&\color{blue}2\\ \color{blue}2&1&1&1&1&\color{blue}0\\ \color{blue}0&\color{blue}0&\color{blue}8&\color{blue}8&\color{blue}8&\color{blue}8 \end{pmatrix}$$

With even numbers on the border and odd numbers on the cover.

Generalization of the formula

Given a square matrix of width \$w>3\$ whose cells are indexed from \$0\$ to \$w^2-1\$, the \$n\$-th cell is located on a border iff the result of the following expression is even:

$$\big(((p\times n)\bmod m_0)\bmod m_1\big)\bmod p$$

with:

$$p=2w-3$$ $$m_0=2\cdot (w-1)^2+w$$ $$m_1=2\cdot (w-2)^2+w-1$$

Try it online!

NB: This is an empirical result that I didn't attempt to prove.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ @FilipHaglund My initial formula was n/6%5<1|n%6%5<1 (which gives the opposite result) and I was not able to reduce it further with conventional tricks. I know from experience that such modulo chains often work well if the input domain is arranged in a non-random manner and the output domain is small. So I tried that, and it was brute-forced indeed. \$\endgroup\$ – Arnauld May 29 at 11:31
  • 1
    \$\begingroup\$ @FilipHaglund See my post update for an a-posterioti generalization of the formula. \$\endgroup\$ – Arnauld May 29 at 12:07
  • 1
    \$\begingroup\$ @Joe85AC I think the best we can do is (n*n%35)**.5%1. It's pretty neat and looks simpler than the current formula, but it's actually 1 byte longer. \$\endgroup\$ – Arnauld Jun 5 at 8:28
  • 1
    \$\begingroup\$ @Joe85AC Interestingly, your formula works for 1, 2, 4, 6, 12, 18, 30, 42, 60, 72, 102, 108, 138, 150, ... \$\endgroup\$ – Arnauld Jun 6 at 9:06
  • 1
    \$\begingroup\$ @Arnauld -- That seems to be A014574. The sequence of the average of two twin primes... Seems we're on the verge of publishing a "number theory" paper... :-) mathworld.wolfram.com/TwinPrimes.html \$\endgroup\$ – Joe85AC Jun 6 at 9:23
13
\$\begingroup\$

Python 2, 73 bytes

Input is taken as a 2D list \$ b \$. Output is the popularity index of \$ b \$.

lambda b:len({j.pop(1)for j in b[1:5]*4}-{' '})-sum(map(`b`.count,'{}~'))

Try it online!


The left part of the expression does two things: adds up the popularity index inside the cover, and removes its characters. The right part subtracts the damaged characters from the remaining characters.

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

J, 51 41 40 bytes

_1#.1#.(+./~#:33)e.&'{}~'`(' '~:~.)/.&,]

Try it online!

-11 bytes thanks to Bubbler!

Both the function table trick to compress #:@68208171135 down to +./~@#:@33, and the "negative one base trick" are due to them.

how

  1. +./~@#:@33 Let's begin with this phrase, which produces:

    1 1 1 1 1 1
    1 0 0 0 0 1
    1 0 0 0 0 1
    1 0 0 0 0 1
    1 0 0 0 0 1
    1 1 1 1 1 1
    

    How? 33 in binary #:@33 is 1 0 0 0 0 1. Then create an "or" function table +./ of this list with itself. It is easy to verify this will be 1 exactly on the border cells.

  2. /.&,] Flatten the input and use the mask above to split the input into two groups, using J's Key /. adverb:

    Apply this verb to the              Damage:
    1st group, the edges:    -------->  Is each character an 
         |                              element of '{}~'?
     ___/____                           Returns a 0-1 list.
     e.&'{}~'`(' '~:~.)
              ^^^^^^^^^
                   |                    Reputation:
        And this one to the second -->  Is space not equal 
        (the interior)                  to each character
                                        of the uniq? Also
                                        a 0-1 list.
    

    We now have two 0-1 lists. For example:

    Reputation: 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
    Damage:     1 1 0 1 1
    

    J will extend the shorter list to the length of the longer, filling it with zeros:

    0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
    1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    
  3. 1#. Sum rowwise:

    1 4
    
  4. _1#. This uses a -1 base as a golfy way to subtract 1 from 4. By definition of base:

    (1 * -1^1) + (4 * -1^0)
    (1 * -1) + (4 * 1)
    3
    
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 41 bytes. \$\endgroup\$ – Bubbler May 28 at 0:10
  • \$\begingroup\$ Save one more byte with +./~@#:@33 -> (+./~#:33). \$\endgroup\$ – Bubbler May 28 at 7:33
  • \$\begingroup\$ @Bubbler Impressive stuff. I learned at least 2 new tricks. The compression of the mask using +. is great, and I've never seen negative base used like that either. Hats off to you! \$\endgroup\$ – Jonah May 28 at 22:58
9
\$\begingroup\$

Python 2, 68 bytes

lambda s:len(set((s[8:-6]*4)[::7])-{' '})-20+sum(map(s.count,'_|-'))

Try it online!

Instead of counting defects on the borders, counts non-defects _|- throughout and subtract from 20, using the rule that only the borders can contain these characters. The (s[8:-6]*4)[::7] is a nice string-slicing way to extract the characters on the cover without borders.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @dingledooper Nice one, you should post an answer for the outgolfing bounty. \$\endgroup\$ – xnor May 29 at 18:47
8
\$\begingroup\$

05AB1E, 25 22 bytes

4Fćˆøí}˜ðKÙg¯˜…~{}S¢O-

-3 bytes by taking inspiration of @JonathanAllan's Jelly answer, so make sure to upvote him!

Input as a matrix of characters.

Try it online or verify all test cases.

Original 25 bytes approach:

|¦¨ε¦¨}ðýê¦gIJ…_|-S¢O20-+

Default input as loose lines in STDIN.

Try it online or verify all test cases.

Explanation:

4F            # Loop 4 times:
  ć           #  Extract head; pop and push remainder-matrix and first line separately
   ˆ          #  Pop and add this first line to the global array
    ø         #  Zip/transpose the remaining matrix; swapping rows/columns
     í        #  Reverse each line
              #  (`øí` basically rotates the matrix once clockwise)
}˜            # After the loop: flatten the remaining matrix
  ðK          # Remove all spaces
    Ù         # Uniquify it
     g        # And pop and push the amount of remaining unique (non-space) characters
¯˜            # Push the global array, and flatten it as well
  …~{}        # Push string "~{}"
      S       # Convert it to a list of characters: ["~","{","}"]
       ¢      # Count each in the flattened global array
        O     # Sum those
-             # Subtract the two from one another
              # (after which the result is output implicitly)                  

|             # Push all lines of inputs as a list of strings
 ¦¨           # Remove the first and last lines
   ε  }       # Map over each line:
    ¦¨        #  And also remove the first and last character of each line
       ðý     # Join everything together with space delimiter
         ê    # Uniquify and sort the characters
          ¦   # Remove the first character (the space)
           g  # And pop and push its length
I             # Push the input-list of lines again
 J            # Join them all together
  …_|-        # Push string "_|-"
      S       # Convert it to a list of characters: ["_","|","-"]
       ¢      # Count each in the joined input
        O     # Take the sum of those counts
         20-  # Subtract 20 from this
+             # Add the two together
              # (after which the result is output implicitly)
| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ This sure beats what I was thinking of. I was heading down a probably 50-100 byte answer before I saw this. Good job! \$\endgroup\$ – Lyxal May 28 at 8:04
  • \$\begingroup\$ @Lyxal And here I actually had the feeling 1 or 2 more bytes could be saved. :) Out of curiosity, what approach did you had in mind? One with a matrix similar as the J/APL answers? \$\endgroup\$ – Kevin Cruijssen May 28 at 8:13
  • \$\begingroup\$ I was going to port my literal interpretation approach in my python answer. As I said, many more bytes than yours. This answer is most likely golfable ;P \$\endgroup\$ – Lyxal May 28 at 8:14
  • \$\begingroup\$ Actually, this seems like a more golfed version of my said approach. Huh. Who'da thunk it? \$\endgroup\$ – Lyxal May 28 at 8:16
  • \$\begingroup\$ @Lyxal Yeah, the count part is rather similar indeed. First part is a bit different, although that's to expected, since I doubt unique and sort the characters for example is cheap in Python. ;) \$\endgroup\$ – Kevin Cruijssen May 28 at 8:20
7
\$\begingroup\$

Jelly, 25 bytes

Ḣ;ɼȧZṚµ4¡FQḟ⁶,®f“~{}”¤Ẉ_/

A full program accepting a single argument as a list of Python strings which prints the result.

Try it online! Or see the test-suite.

How?

Ḣ;ɼȧZṚµ4¡FQḟ⁶,®f“~{}”¤Ẉ_/ - Main Link: list of lists of characters (the lines)
      µ4¡                 - repeat this monadic chain four times:
Ḣ                         -   head (gives us the head AND modifies the chain's input)
  ɼ                       -   recall from the register (initially 0) and apply & store:
 ;                        -     concatenate
    Z                     -   transpose the chain's (now modified) input
   ȧ                      -   logical AND (the concatenate result with the transpose, to get us the transpose of the chain's input)
     Ṛ                    -   reverse (together with the transpose this is rotate one quarter)
         F                - flatten (what we have left is the cover's inner characters)
          Q               - de-duplicate
           ḟ⁶             - discard spaces
                     ¤    - nilad followed by link(s) as a nilad:
              ®           -   recall from the register (the cover's edge characters)
               f“~{}”     -   keep only "~{}" characters
             ,            - pair (the two lists of characters)
                      Ẉ   - length of each
                        / - reduce by:
                       _  -   subtraction
                          - implicit print (a list containing only one entry prints just that entry)
| improve this answer | |
\$\endgroup\$
6
+100
\$\begingroup\$

Python 2, 66 bytes

lambda s:len(set((s[8:-6]*4)[::7]+' '))-21+sum(map(s.count,'_|-'))

Try it online!


A slight improvement over @xnor's answer. Instead of removing spaces from the cover, we add spaces to the cover, and then subtract 1.

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

Python 3, 106 102 80 bytes

lambda b:len({*(b[8:12]+b[15:19]+b[22:26]+b[29:33])})-21+sum(map(b.count,"-|_"))

Try it online!

I know there's a shorter Python answer, and I know that this isn't the most optimal method. But I had come up with a solution which I golfed, and I'm posting it for the sake of completion. -2 thanks to @Kevin and -2 thanks to OVS. A further -22 thanks to @mathjunkie.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ return len(set(m))-s-1 can be return~s+len(set(m)) for -2 \$\endgroup\$ – Kevin Cruijssen May 28 at 8:16
  • \$\begingroup\$ And another -1 by switching to Python 2 and use print instead of return. :) Try it online. \$\endgroup\$ – Kevin Cruijssen May 28 at 8:19
  • 1
    \$\begingroup\$ Back to Python 3 with {*m} instead of set(m) ;). And if you replace 20 with 19 the -1 can be removed, this doesn‘t save any bytes though. \$\endgroup\$ – ovs May 29 at 14:42
  • \$\begingroup\$ 80 bytes, by converting to a lambda and using map instead of c=b.count: Try it online! \$\endgroup\$ – math junkie May 29 at 22:20
  • 1
    \$\begingroup\$ This currently fails for cases with no spaces. There are a few ways to deal with this... \$\endgroup\$ – dingledooper May 30 at 3:23
5
\$\begingroup\$

perl -M5.010 -n -0543, 82 bytes

$i--for/\}$|^\{|~(?=[-_~]*$)/gm;s/^[-_~]+$|^.|.$//gm;$c{$_}++for/\S/g;say$i+keys%c

Try it online!

First, the penalty is calculated by counting {s which start a line, }s which end a line, and any ~ in the top and bottom lines. We then strip off the boundaries, and count the number of unique non-space characters; the penalty is added to that, to get the final score.

Reads a single cover from STDIN, writes the score to STDOUT.

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

APL (Dyalog Unicode), 42 35 bytes

-6 thanks to Bubbler.

Anonymous tacit prefix function. Requires ⎕IO←0 (0-based indexing).

-⍨/(,∘.⍱⍨6⍴5↑1){≢∪⍣⍺⊢⍵~⊃⍺↓⊂'_|-'}⌸∊

Try it online!

ϵnlist (flatten)

(){}⌸ apply the below function to each of the two groups identified by 1s and 0s in:

5↑1 take five elements from 1; [1,0,0,0,0]

6⍴ cyclically reshape that to length six; [1,0,0,0,0,1]

∘.⍱⍨ NOR-table of that;
  [[0,0,0,0,0,0],
   [0,1,1,1,1,0],
   [0,1,1,1,1,0],
   [0,1,1,1,1,0],
   [0,1,1,1,1,0],
   [0,0,0,0,0,0]]

, ravel (flatten)

 The following function will be applied to each multiset (0: edge characters; 1: inner characters):

'_|-' a string; "_|-"

  enclose it; ["_|-"]

⍺↓ drop 1 element if the set is that of inner characters, otherwise drop 0 elements

 get the first element; the above string or " " if gone

⍵~ remove those characters from the edge/inner set

 ∪⍣⍺⊢ if inner, then get the unique of that, else leave as-is

 tally that

-⍨/ subtract the first count from the last count

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

Charcoal, 49 41 bytes

≔⪫E⁶S¶θPθB⁶ WΦKA¬№υκ⊞υ⊟ι⎚I⊖⁻Lυ⁻²⁰ΣE-_|№θι

Try it online! Link is to verbose version of code. Explanation:

≔⪫E⁶S¶θ

Input the cover.

PθB⁶ 

Print the cover, but immediately erase the border.

WΦKA¬№υκ⊞υ⊟ι

Collect all the unique characters, which always includes a space, as we used that to erase the border. (I feel that I should be able to use W⁻KAυ⊞υ⊟ι but Charcoal crashes when I try.)

⎚I⊖⁻Lυ⁻²⁰ΣE-_|№θι

Clear the canvas and output the popularity, adjusting for the extra space collected and the number of missing border characters in the original string.

I also tried counting the popularity by directly inspecting the string instead of printing it and deleting the border but it turns out that that costs bytes overall.

Previous 49-byte solution does not assume that edge characters only appear on the edge:

≔⪫E⁶S¶θPθB⁶ WΦKA¬№υκ⊞υ⊟ιPθ↘UO⁴ ≔ΦKA№{~}ιθ⎚I⊖⁻LυLθ

Try it online! Link is to verbose version of code. Explanation:

≔⪫E⁶S¶θ

Input the cover.

PθB⁶ 

Print the cover, but immediately erase the border.

WΦKA¬№υκ⊞υ⊟ι

Collect all the unique characters, which always includes a space, as we used that to erase the border. (I feel that I should be able to use W⁻KAυ⊞υ⊟ι but Charcoal crashes when I try.)

Pθ↘UO⁴ 

Print the cover again, but this time keep only the border.

≔ΦKA№{~}ιθ

Collect all the {, ~ and } characters.

⎚I⊖⁻LυLθ

Clear the canvas and output the calculated popularity, adjusting for the extra space collected.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ @mathjunkie Sorry about that, I introduced a silly typo while golfing (ω should have been ). \$\endgroup\$ – Neil May 27 at 23:39
5
\$\begingroup\$

Java (OpenJDK 8), 326 320 319 305 bytes

int f(List<Character>[]c){int s=0,i=3;c[0].addAll(c[5]);for(;i>1;)S(50*i---55,c[0]);c[5].clear();for(;i<5;c[5].addAll(c[i++]))s+=c[i].remove(0)-c[i].remove(4);S(32,c[5]);for(;c[5].size()>0;i++)S(c[5].get(0),c[5]);return i-5-c[0].size()+s;}void S(int x,List c){c.removeAll(Collections.singleton((char)x));}

Try it online!

THANKS to Muskovets's suggestion of using List (-4), I also omitted the generic type in the second method (List instead of List< Character>)

Takes input as List< Character>[] and outputs an int.

It uses 2 methods (I'm not entirely sure how "allowed" that is)

See inside for comments and ungolfed and alternate solutions (including a single method one).

Interesting part: the ascii values for { | } are 123, 124, 125. That means that this part changes the popularity index by:

for each row: the left char minus the right char

{...} 123 - 125 = -2

{...| 123 - 124 = -1

|...} 124 - 125 = -1

|...| 124 - 124 = 0

It only works with only exactly the given possible inputs, none else (illegal inputs like }...{). Pretty lucky.

This was done with ArrayList, but possibly some other Collection with a shorter name or better methods would be better. Edit: indeed there is: Vector. updated. (Now List)


Takes input as String[]. Only one method.

Java (OpenJDK 8), 267 261 bytes

int f(String[]c){int s=0,i=4;c[0]=c[0].replace("_","")+c[5].replace("-","");c[5]="";for(;i>0;c[5]+=c[i--].substring(1,5))s+=c[i].charAt(0)-c[i].charAt(5);for(;c[5].trim().length()>0;i++)c[5]=c[5].replace(c[5].trim().substring(0,1),"");return i-c[0].length()+s;}

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Uhm... List is a collection. It'd give you -4 :) \$\endgroup\$ – Muskovets May 29 at 6:16
  • 1
    \$\begingroup\$ +1 for triple minus in F(50*i---55 \$\endgroup\$ – Franky May 29 at 7:06
  • 1
    \$\begingroup\$ 301 bytes \$\endgroup\$ – ceilingcat May 31 at 5:35
4
\$\begingroup\$

Perl 5 + -p0 -MList::Util+uniq, 55 bytes

s/^.{5}|.
.|.{5}$/$\-=$&=~y!~{}!!;""/ge;$\+=uniq/\S/g}{

Try it online!

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

PHP, 104 93 bytes

Original code from yesterday:

while($s<35+$c=ord($b[$t=$s++]))$p-=$t>5&$s<31?$t%6?$s%6?0&$i[$c]=1:$c:-$c:$c%5;echo$p+count($i)-$i[32];

Try it online!

Improved with a mod-expression from @Arnauld, cf. his solution.

for(;$s<36;$s++)$p-=$s*9%56%37%9&1?!$i[$b[$s]]=1:ord($b[$s])%29%8>0;echo$p+count($i)-$i[" "];

Try it online!


Explanation

  • I was using the fact that char codes of intact top and bottom edges are %5=0, and left and right edges have char codes that are in sequence.
  • I've now researched the char codes of the six edge chars a little better.
    Try [45,95,124,123,125,126]%18%15. There are also other options like $c%29%8==0 and so on.



Please Help Me Get Better

I appreciate any comments or suggestions.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Hi, welcome to the site! I'm not a PHP golfer myself but you can check out tips for golfing in PHP for some suggestions (there's a similar thread for basically every language). \$\endgroup\$ – Asone Tuhid Jun 4 at 15:56
  • 1
    \$\begingroup\$ Could you also add a link to somewhere your code could be tested online, such as: Try it online! (for that site, you'll probably need to add some code to the header and footer to demonstrate how to call your function/program) \$\endgroup\$ – math junkie Jun 4 at 16:27
  • 1
    \$\begingroup\$ @mathjunkie -- I added a link. Thanks for the question! \$\endgroup\$ – Joe85AC Jun 4 at 17:10
2
\$\begingroup\$

Bash + standard tools 121 Bytes

bc<<<$(sed '1d;$d;s/.//;s/.$//' $1|grep -o '[^ ]'|sort -u|wc -l)-$(sed -E '2,${$!s/(.)..../\1/}' $1|tr -cd '[~{}]'|wc -c)

Input is a file of the book.

Try it online! (+6 bytes because input needs to be a string here)

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

C (gcc), 174 bytes

//N(c)=p-=*s++!=c
p,v,i,j,k;f(char*s){char u[16]={};for(v=p=0,i=6;i--;N(95));for(j=4;j--;N(124))for(N(124),i=4;i--;)strchr(u,k=*s++-32)||(u[v++]=k);for(i=6;i--;N(45));s=p+v;}

Try it online!

Pretty standard: I count the number of unique characters in the cover (which is built up in a string), then deduct the amount of damage.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Suggest {v=p=0};for(i=6 instead of {};for(v=p=0,i=6 \$\endgroup\$ – ceilingcat May 31 at 4:20
0
\$\begingroup\$

Erlang (escript), 184 bytes

Just a port of Lyxal's Python answer. (Where's the unique function in Erlang?)

u([H|T])->[H]++u([I||I<-T,I/=H]);u(X)->X.
f(X)->length(u(lists:flatten([lists:droplast(tl(I))||I<-lists:droplast(tl(string:split(X,"
",all)))])))-21+length([I||I<-X,([I]--"_|-")==[]]).

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ This doesn't work when the cover has no spaces: Try it online! should be 16 but gives 15 \$\endgroup\$ – math junkie May 31 at 14:39
0
\$\begingroup\$

Ruby, 101 98 bytes

->s{a,*b,c=s.lines;(b.flat_map{x,*y,z,_=_1.chars;a+=x+z;y}|[' ']).size-22+(a+c).tr('{}~','').size}

100 byte version because TIO doesn't support ruby 2.7

->s{a,*b,c=s.lines;(b.flat_map{|i|x,*y,z,_=i.chars;a+=x+z;y}|[' ']).size-22+(a+c).tr('{}~','').size}

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.