Virus vs Antidotes code golf

Python 3, 131 bytes

g=lambda s:eval('j(s)'+4*'.replace("%s%s","%s%s")'%(*'vbbbbvbbavacvaca',))
f=lambda x:j(map(g,zip(*map(g,x)))).count('v')

Try it online!

-2 bytes thanks to Kevin Cruijssen


Replaces all 'v' to 'b' if found next to 'b'. Next, replaces all 'v' to 'c' if found next to 'a'. A second iteration with the transposed version of the array clears all vertical and diagonal viruses. Finally, it will return the remaining number of 'v's.

Without eval:

Python 3, 134 bytes

g=lambda s,m='vbbbbvbbavacvaca':m and g(j(s).replace(m[:2],m[2:4]),m[4:])or s
f=lambda x:j(map(g,zip(*map(g,x)))).count('v')

Try it online!

JavaScript (ES7), 108 bytes

Takes input as a matrix of characters.


Try it online!

Similar to my original answer, but doing V>'a'>(x-X)**2+y*y-2 is actually 1 byte shorter than using the hexa trick described below. ¯\_(ツ)_/¯

JavaScript (ES7), 109 bytes

Takes input as a matrix of characters.


Try it online!


The quadrance of two points \$A_1=(x_1,y_1)\$ and \$A_2=(x_2,y_2)\$ is defined as:


Considering integer coordinates, it looks as follows:

$$\begin{matrix} &8&5&4&5&8\\ &5&2&1&2&5\\ &4&1&\bullet&1&4\\ &5&2&1&2&5\\ &8&5&4&5&8 \end{matrix}$$


  • a type A antidote located at \$A_1\$ is able to kill a virus located at \$A_2\$ if \$Q(A_1,A_2)<2\$
  • a type B antidote located at \$A_1\$ is able to kill a virus located at \$A_2\$ if \$Q(A_1,A_2)<3\$

Conveniently, this exclusive upper bound (\$2\$ or \$3\$) can be obtained by converting the antidote character from hexadecimal to decimal and subtracting \$8\$:

  • \$\text{A}_{16} - 8_{10} = 2_{10}\$
  • \$\text{B}_{16} - 8_{10} = 3_{10}\$


f =                      // named function, because we use it to test if a character
                         // is below or above 'm'
m => (                   // m[] = input matrix
  g = (                  // g is a recursive function taking:
    y,                   //   y = offset between the reference row and the current row
    X,                   //   X = reference column
    V                    //   V = reference value, prefixed with '0x'
  ) =>                   // =>           // for each row r[] in m[]:, x) =>    //   for each value v at position x in r[]:
        V ?              //     if V is defined:
          v > f &        //       if v is equal to 'v'
          (x - X) ** 2 + //       and the quadrance between the reference point and
          y * y          //       the current point
          < V - 8 ?      //       is less than the reference value read as hexa minus 8:
            r[x] = n--   //         decrement n and invalidate the current cell
          :              //       else:
            0            //         do nothing
        :                //     else:
          v < f ?        //       if v is either 'a' or 'b':
            g(           //         do a recursive call:
              -y,        //           pass the opposite of y
              x,         //           pass x unchanged
              '0x' + v   //           pass v prefixed with '0x'
            )            //         end of recursive call
          :              //       else:
            n++          //         increment n
      ) | y++            //   end of inner map(); increment y
    )                    // end of outer map()
  )(n = 0)               // initial call to g with y = n = 0
  | n                    // return n

05AB1E, 33 30 29 bytes


Try it online or verify a few more test cases.

Port of @Jitse's Python 3 answer, so make sure to upvote him!
-1 byte thanks to @Jitse.


The legacy version has the advantage of being able to zip/transpose a string-list, where the new version would need an explicit S and J, since it only works with character-lists. But, the new version is still 3 bytes shorter by using €Â in combination with a shorter compressed string. In the legacy version, would only keep the last value on the stack inside the map, but in the new version, it will keep all values on the stack inside the map.

2F                  # Loop 2 times:
  .•s¯}˜?•          #  Push compressed string "vbvabbca"
   2ô               #  Split it into parts of size 2: ["vb","va","bb","ca"]
     €Â             #  Bifurcate (short for duplicate & reverse copy) each:
                    #   ["vb","bv","va","av","bb","bb","ca","ac"]
       2ä           #  Split it into two parts:
                    #   [["vb","bv","va","av"],["bb","bb","ca","ac"]]
         `          #  Push both those lists separated to the stack
          .:        #  Replace all strings once one by one in the (implicit) input-string
            S       #  Then split the entire modified input to a list of characters
             ¶¡     #  Split that list by newlines into sublists of characters
               ø    #  Zip/transpose; swapping rows/columns
                J   #  Join each inner character-list back together to a string again
                 »  #  And join it back together by newlines
}'v¢               '# After the loop: count how many "v" remain

See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?) to understand why .•s¯}˜?• is "vbvabbca".


Code Golf