Count my Pluses

What Pluses?

• The no plus: 0 Points
-

• The naïve Plus: 1 Point
+

• The double Plus: 2 Points
 +
+++
+

• The mega double plus: 3 Points
    +
+++
+
+  +  +
+++++++++
+  +  +
+
+++
+


Pluses of higher order than 3 must be ignored.

Rules

• Input will only consist of two characters - and +, and it will always be rectangular.
• Input can be a string, an array or a binary matrix (then + is 1 and - is 0).
• Output must be the sum of all detected pluses (trailing newline/ whitespace allowed).
• Pluses can overlap (see Examples below)
• Default I/O rules apply
• Default Loop holes apply

Examples

-+-
+-+
+--


Out: 4

-+-
+++
+++


Out: 9 (7 naïve pluses and 1 double plus)

++++++
++++++
++++++
++++++


Out: 40 (24 naïve pluses and 8 double pluses)

----+-----
+--+++----
----++----
-+--+--++-
+++++++++-
-+--+--++-
----+-+---
---+++----
+---++++++


Out: 49 (36 naïve pluses, 5 double pluses and 1 mega double plus)

++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++


Out: 208 (90 naïve pluses, 56 double pluses and 2 mega double plus)

• sandbox
– math
Jun 24 at 10:35
• Could you add a test case where one or more intersections of a "mega double plus" overlap, thereby invalidating it? Jun 24 at 14:00
• I'm not entirely sure what Shaggy means, but I would suggest a test case with the same dimensions as the last one but with all pluses--my current Jelly solution is incredibly wrong for that input Jun 24 at 14:45
• @Shaggy and Unrelated String I'll do it tommorow, but I don't know too what Shaggy meant
– math
Jun 24 at 18:57
• @simonalexander2005 If you mean something like this, then I think it is still valid, space doesn't mean -. I am adding just the second testcase suggested by Unrelated String for now.
– math
Jun 25 at 8:02

MATL, 2928 24 bytes

z2Y6ttX*,GbZ+5Mz=z]yytvs


Input is a binary matrix with 1 for '+' and 0 for '-'.

Explanation

z       % Implicit input. Number of nonzeros. This is the number of naive pluses
2Y6     % Push [0 1 0; 1 1 1; 0 1 0] (predefined literal): pattern of double plus
ttX*    % Duplicate twice. Kronecker product: pattern of mega-double plus
,       % Do twice
G     %   Push input again
b     %   Bubble up third-topmost entry in the stack. This moves either the
%   double of mega-double pattern to top
Z+    %   2D convolution, maintaining size
5M    %   Push the last input to the last function again: the pattern
z     %   Number of nonzeros. This gives 5 or 25 for double or mega-double
=     %   Equal? Element-wise. This detects if the result of the convolution
%   equals the number of ones in the pattern, which implies that the
%   pattern has been found
z     %   Number of nonzeros. This is how many times the pattern has been found
]       % End
yyt     % Duplicate the top two elements, then the top element. This effectively
% gives weight 2 and 3 to double and mega-double pluses
vs      % Concatenate all stack contents. Sum. Implicit display


JavaScript (ES6),  146 ... 140  137 bytes

Expects a binary matrix.

m=>m.map((r,y)=>r.map((c,x)=>t+=c+=(g=(X,k=6)=>k>>8||(m[y+Y+k%5%3]||0)[x-X+k%27%4]&g(X,k+46))(Y=0)&&2+3*g(Y=3)*g(-3)*g*g(0,Y=6)),t=0)|t


Try it online!

How?

Helper function

The helper function $$\g\$$ tests whether there's a 'Double Plus' inside the $$\3\times3\$$ submatrix whose top-left corner is located at position $$\(x-X,y+Y)\$$.

We start with $$\k=6\$$ and add $$\46\$$ to $$\k\$$ after each iteration. The relative coordinates in the submatrix are given by:

\begin{align}&dx=(k\bmod 27)\bmod 4\\ &dy=(k\bmod 5)\bmod 3\end{align}

  k | k%27 | dx=k%27%4 | k%5 | dy=k%5%3 | (dx, dy)          | 0 1 2
----+------+-----------+-----+----------+--------------  ---+-------
6 |   6  |     2     |  1  |     1    | (+2, +1) (A)    0 | - C -
52 |  25  |     1     |  2  |     2    | (+1, +2) (B)    1 | E D A
98 |  17  |     1     |  3  |     0    | (+1, +0) (C)    2 | - B -
144 |   9  |     1     |  4  |     1    | (+1, +1) (D)
190 |   1  |     1     |  0  |     0    | (+1, +0) (C)
236 |  20  |     0     |  1  |     1    | (+0, +1) (E)


The cell at $$\(+1, +0)\$$ is tested twice, which is not an issue.

The next value of $$\k\$$ is $$\282\$$ which triggers the test k >> 8 and stops the recursion.

g = (X, k = 6) =>    // g is a recursive function taking X and a counter k
k >> 8 || (        //   if k = 282, stop the recursion and return 1
( m[ y + Y +     //   otherwise, test the cell located at
k % 5 % 3 ] //   row y + Y + ((k mod 5) mod 3)
|| 0           //
)[ x - X +       //   and column x - X + ((k mod 27) mod 4)
k % 27 % 4 ]  //
)                  //
& g(X, k + 46)     //   do a recursive call with k + 46


Main function

NB: Among many different possible choices, the initial value of $$\k\$$ in $$\g\$$ was forced to $$\6\$$ so that it allows us to do g(0, Y = 6) in the main function without breaking anything.

m =>                 // m[] = input matrix
m.map((r, y) =>      // for each row r[] at position y in m[]:
r.map((c, x) =>    //   for each cell c at position x in r[]:
t +=             //     add to t:
c +=             //       1 point if c = 1
g(Y = 0) && 2  //       2 points if there's a Double Plus at (x, y)
+ 3 *          //       3 points if there are also Double Pluses at:
g(Y = 3) *     //         (x - 3, y + 3)
g(-3) *        //         (x + 3, y + 3)
g *          //         (x, y + 3)
g(0, Y = 6)    //         (x, y + 6)
),                 //   end of inner map()
) | t                // end of outer map(); return t

• Output for the last test case seems to be off by three. Yours outputs 208 while the actual result is 205
– user100690
Jun 25 at 8:10
• @RecursiveCo. The correct answer is 208. (Now fixed by the OP.) Jun 25 at 9:20
• ES6, 138 bytes: m=>m.map((r,y)=>r.map((c,x)=>t+=c+=(g=X=>k=k>8||(325>>k|(m[y+Y+k/3|0]||0)[x-X+k++%3])&g(X))(Y=0)&&2+3*g(Y=3)*g(-3)*g*g(!(Y=6))),k=t=0)|t; ES2020, 135 bytes: m=>m.map((r,y)=>r.map((c,x)=>t+=c+=(g=X=>k=k>8||(325>>k|m[y+Y+k/3|0]?.[x-X+k++%3])&g(X))(Y=0)&&2+3*g(Y=3)*g(-3)*g*g(!(Y=6))),k=t=0)|t
– tsh
Jun 25 at 9:49
• 137: m=>m.map((r,y)=>r.map((c,x)=>t+=c+=(g=X=>k=k>8||(325>>k|(m[y+Y+k/3|0]||0)[x-X+k++%3])&g(X))(Y=0)&&2+3*g(Y=3)*g(-3)*g*g(0,Y=6)),k=t=0)|t
– tsh
Jun 25 at 10:04
• @tsh Nice optimization. I was trying to find a version of g that directly tests the relevant points rather than iterating over all of them. The result is also 137 bytes for now. Jun 25 at 10:57

Jelly, 33 bytes

×3\€ḊṖ
ZÇZaÇḤ
ÇJ%3ZƙƲ⁺€Ç€€a3,,ÇFS


Try it online!

:/

I want to say this is very golfable, but the entire approach is probably not the ideal one. Now agrees with Luis Mendo's MATL solution on a test case I made up, and at the cost of only one byte so that's cool I guess

×3\€ḊṖ    Helper link 1: detect centers of +++
€      For each row,
3\       reduce over overlapping windows of length 3:
×         multiply.
ḊṖ    Remove the first and last rows.

ZÇZaÇḤ    Helper link 2: detect double plus centers
aÇ     Keep the horizontal (centers of) +++es which align with
ZÇZ       the vertical (centers of) +++es,
Ḥ    and double.

ÇJ%3ZƙƲ⁺€Ç€€a3,,ÇFS    Main link: sum each tier of plus
Ç                      Get the matrix of double plus centers.
ƙƲ                Group rows by
J%3                   their indices mod 3
Z                  and transpose each group;
⁺€              do it again to each group.
€€           For each group in each group,
Ç             detect the double plus pattern,
a3         and replace the 16s with 3s.
,        Pair the result with the input,
,Ç      pair that pair with the double pluses,
FS    then flatten that all and return the sum.

• nice, but I can't vote anymore.
– math
Jun 24 at 12:27

R, 141 bytes

function(m)sum(m,a<-f(m,n<-nrow(m))*2,f(a,n,3)*3,na.rm=T)
f=function(m,n,k=1)sapply(n*k+seq(!m),function(i)all(i%%n>1,m[i+k*c(0,1,-1,n,-n)]))


Try it online!

This can probably be improved by a lot.

The helper function f scans the matrix. For each cell, it counts 1 iff the cell and the cells at distance k in each of the 4 directions are all worth 1. For k=1, this corresponds to checking the 4 neighbours, and creates a which encodes the centres of the double pluses. We then run f on a with k=3 to find the triple pluses. The entries near the edges end up as NA; they are ignored thanks to na.rm=T.

J, 80 69 60 bytes

[:+/@,[,2 3*((;[:,./^:2#"{~)#:2 7 2)4 :'y(x-:x&*);._3~$x'&><  Try it online! -9 thanks to xash • Two small golfs for -9 – xash Jun 25 at 17:23 • btw. nice solution with the inline 4 : – xash Jun 25 at 17:30 • Very nice, thanks! Jun 25 at 17:30 • For showing previous scores, it makes more sense to use <strike>num</strike> Jul 2 at 13:09 • I don’t like how that looks as much even though i agree it’s semantically more accurate. Jul 2 at 14:06 Charcoal, 71 bytes ＷＳ⊞υιυＦＬυＦＬθ«Ｊκι¿⁼⁷ＬΦ⪫ＫＶＫＫΣλ3»ＦＬυＦＬθ«Ｊκι¿∧⁼3ＫＫ⬤urdl‹1⊟ＫＤ⁴✳λ6»≔Σ⪫ＫＡωθ⎚Ｉθ  Try it online! Link is to verbose version of code. Takes input as a binary matrix of newline-terminated strings. Explanation: ＷＳ⊞υιυ  Read in the matrix and print it to the canvas. ＦＬυＦＬθ«Ｊκι  Loop over all of the cells. ¿⁼⁷ＬΦ⪫ＫＶＫＫΣλ3»  If this cell and all of its neighbours are 1s or 3s then change this cell to a 3. ＦＬυＦＬθ«Ｊκι  Loop over all of the cells again. ¿∧⁼3ＫＫ⬤urdl‹1⊟ＫＤ⁴✳λ6»  If this cell is a 3 and all of the cells 3 away in all four orthogonal directions are greater than 1 then change this cell to a 6. ≔Σ⪫ＫＡωθ⎚Ｉθ  Take the sum of the grid, clear the canvas, and output the sum in decimal. Python 3.8 (pre-release), 150 149 145 bytes lambda a:len(x("\+",a)+2*x((d:="\+(?="+(s:="\W"*~-a.find("\n"))+3*"\+"+s+"\+)..")[:-2],a)+3*x(d+f"(?={3*s+3*d+3*s+d})",a)) import re x=re.findall  Try it online! Input is a multiline string Thanks to @Tipping Octopus for -1 byte Thanks to @Neil for -4 bytes Ungolfed version import re def f(a): s="\W"*(a.find("\n") - 1) d=f"\+(?={s}\+\+\+{s}\+).." return len(re.findall("\+", a) + 2 * re.findall(d[:-2], a) + 3 * re.findall(d + f"(?={3*s + 3*d + 3*s + d})", a) )  Try it online! How it works : I created a regex that can detect double plusses and mega-double-pluses • s="\W"*~-a.find("\n") stock in s the string \W\W...\W whose length is equal to the number of character of a line minus 1. (\W matches any non-word character including \n) • d=f"\+(?={s}\+\+\+{s}\+).." is the pattern for double plus (+ .. wich will be removed on the double plus check) • re.findall(<pattern>, a) returns a list containing all the matches of pattern. • len(re.findall()+2*re.findall()+3*re.findall() concatenate theses lists and return the length • -1 byte Jun 24 at 21:27 • "\W%r"%{a.find("\n")-1} can be "\W"*~-a.find("\n"). – Neil Jun 25 at 9:52 • @Neil and Tipping Octopus, thanks for suggestions Jun 25 at 14:49 Ruby, 135 bytes ->a{i=0;[1,186,0x101c04125ff490407010].sum{|s|a.each_cons(y=3**i).sum{|w|w.transpose.each_cons(y).count{|z|z.join.to_i(2)&s==s}}*i+=1}}  Try it online! Jelly, 37 bytes Zœs3Ɗ⁺€aZ$2ịP))
3*³ṡZ€ṡ€ɗÇ⁸¡
3’Ç×Ɗ€FS


Try it online!

A full program taking a Boolean matrix as its argument and printing the number of pluses. This is extensible to higher degrees of plus by changing the 3 at the beginning of the last line to a higher number. For example, here is a version that goes up to mega-mega-mega double pluses in a matrix of 82x82 1s.

JavaScript (ES2020), 136 bytes

m=>m.map((r,y)=>r.map((c,x)=>t+=(d=X=>D=Y=>e+2?m[Y+e--%3%2]?.[X+e%2]*D(Y):e=3)(x)(y,e=3)?D(y-3)*D(y+3)*d(x-3)(y)*d(x+3)(y)?6:3:c),t=0)|t


f=

m=>m.map((r,y)=>r.map((c,x)=>t+=(d=X=>D=Y=>e+2?m[Y+e--%3%2]?.[X+e%2]*D(Y):e=3)(x)(y,e=3)?D(y-3)*D(y+3)*d(x-3)(y)*d(x+3)(y)?6:3:c),t=0)|t

testcases = 
-+-
+-+
+--

-+-
+++
+++

++++++
++++++
++++++
++++++

----+-----
+--+++----
----++----
-+--+--++-
+++++++++-
-+--+--++-
----+-+---
---+++----
+---++++++

++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
.trim().split('\n\n').map(s => s.split('\n').map(r => [...r].map(c => c === '+' ? 1 : 0)));

testcases.forEach(t => { console.log(f(t)); });

m=> // input 0-1 [m]atrix
m.map((r,y)=> // for each [y]-th [r]ow
r.map((c,x)=> // for each [x]-th [c]eil
(d=X=> // Check if [d]ouble plus exist on [X], [Y]
D=Y=>e+2?         // for [e]ach 3, 2, 1,  0, -1
m[Y+e--%3%2]?.    //         Y+ 0, 0, 1,  0, -1
[X+e%2]           //         X+ 0, 1, 0, -1,  0
// check if certain position is a plus sign
*D(Y,e)           // return 0 or NaN as falsy
:e=3              // return 3 as truthy
)
(x)(y,e=3)? // Is [x][y] a double plus?
D(y-3)*D(y+3)*d(x-3)(y)*d(x+3)(y)? // Is [x][y] a double double plus?
6:3:c // assign different points
),
t=0 // initial [t]otal points to 0

Perl 5 (-00p), 125 bytes
/(....)?(..)?(.)
/;($a,$:,$;,$,)=map"."x$_,@-;/(1$,111$,1)(?{$x+=2})($;(1..1..1)$:1{9}$:(?3)$;(?1)(?{$x+=3}))?^/s;$_=y/1//+$x  Try it online! Using 1 instead of + and using regex to match pluses. Or 124 bytes using }{ at the end trick /(....)?(..)?(.) /;($a,$:,$;,$,)=map"."x$_,@-;$\=y/1//;/(1$,111$,1)(?{$\+=2})($;(1..1..1)$:1{9}$:(?3)$;(?1)(?{\$\+=3}))?^/s}{