text:
Find the area of the smallest rectangle to contain squares of sizes up to n
This is a sequence question of the usual type, as applied to OEIS sequence A038666. That is, do either of the following:

Accept no or any input, and output A038666 until the heat death of the universe.
Accept a positive integer as input, and output the \$n\$th term of A038666 or its first \$n\$ terms. (If using \$0\$- instead of \$1\$-indexing, then of course you also have to output 1 on 0 input.)

The \$n\$th term of A038666 is the least area among rectangles that contain non-overlapping squares of sizes \$1\times1,2\times2,\dots n\times n\$ if you're using \$1\$-indexing.
Example:
The smallest-area rectangle which can contain non-overlapping squares of sizes \$1\times1\$ through \$4\times4\$ has dimensions \$7\times5\$:
4 4 4 4 3 3 3
4 4 4 4 3 3 3
4 4 4 4 3 3 3
4 4 4 4 2 2 1
x x x x 2 2 x

Therefore, \$a(4)=7\times5=35\$ (\$1\$-indexed).
Similarly, the least-area rectangle containing non-overlapping squares of sizes \$1\times1\$ through \$17\times17\$ has dimensions \$39\times46\$, so \$a(17)=39\times46=1794\$ (\$1\$-indexed).

JavaScript (ES6), 172 bytes
Slower but shorter version suggestion suggested by @JonathanAllan (also saving 4 bytes in the original answer):
f=(n,A,S=(n,c)=>n>=0?c(n)||S(n-1,c):0)=>S(A,w=>(F=(l,n)=>n?S(w-n,x=>S(A/w-n,y=>l.some(([X,Y,W])=>X<x+n&X+W>x&Y<y+n&Y+W>y)?0:F([...l,[x,y,n]],n-1))):A%w<1)([],n))?A:f(n,-~A)

Try it online!

Original answer,  209 183 178  174 bytes
Returns the \$N\$th term of the sequence, 1-indexed.
f=(n,A,S=(n,c)=>n>=0?c(n)||S(n-1,c):0)=>S(A,w=>A%w?0:(F=(l,n)=>n?S(w-n,x=>S(A/w-n,y=>l.some(([X,Y,W])=>X<x+n&X+W>x&Y<y+n&Y+W>y)?0:F([...l,[x,y,n]],n-1))):1)([],n))?A:f(n,-~A)

Try it online!
Commented
Helper function
We first define a helper function \$S\$ which invokes a callback function \$c\$ for \$n\$ to \$0\$ (both included) and stops as soon as a call returns a truthy value.
S = (n, c) =>               // n = integer, c = callback function
  n >= 0 ?                  // if n is greater than or equal to 0:
    c(n) ||                 //   invoke c with n; stop if it's truthy
    S(n - 1, c)             //   or go on with n - 1 if it's falsy
  :                         // else:
    0                       //   stop recursion and return 0

Main function
We start with \$A=1\$.
For each pair \$(w,h)\$ such that \$w\times h = A\$, we try to insert all squares of size \$1\times1\$ to \$n\times n\$ (actually starting with the largest one) in the corresponding area, in such a way that they don't overlap with each other.
We keep track of the list of squares with their position \$(X,Y)\$ and their width \$W\$ in \$l[\text{ }]\$.
We either return \$A\$ if a valid arrangement was found, or try again with \$A+1\$.
f = ( n,                    // n = input
      A ) =>                // A = candidate area (initially undefined)
S(A, w =>                   // for w = A to w = 0:
  A % w ?                   //   if w is not a divisor of A:
    0                       //     do nothing
  : (                       //   else:
    F = (l, n) =>           //     F = recursive function taking a list l[] and a size n
      n ?                   //       if n is not equal to 0:
        S(w - n, x =>       //         for x = w - n to x = 0
          S(A / w - n, y => //           for y = A / w - n to y = 0:
            l.some(         //             for each square in l[]
            ([X, Y, W]) =>  //             located at (X, Y) and of width W:
              X < x + n &   //               test whether this square is overlapping
              X + W > x &   //               with the new square of width n that we're
              Y < y + n &   //               trying to insert at (x, y)
              Y + W > y     //
            ) ?             //             if some existing square does overlap:
              0             //               abort
            :               //             else:
              F([ ...l,     //               recursive call to F:
                  [x, y, n] //                 append the new square to l[]
                ],          //
                n - 1       //                 and decrement n
              )             //               end of recursive call
          )                 //           end of iteration over y
        )                   //         end of iteration over x
      :                     //       else (n = 0):
        1                   //         success: stop recursion and return 1
    )([], n)                //     initial call to F with an empty list of squares
) ?                         // end of iteration over w; if it was successful:
  A                         //   return A
:                           // else:
  f(n, -~A)                 //   try again with A + 1

Save 6* by not defining h and moving the test for a%w<1 to the tail of the recursion TIO. Of course it's much slower. (* at least - I'm no JavaScript expert!)

@JonathanAllan Thanks. :) Actually, I wonder if a%w<1 could be replaced with just 1. I'll have to double-check that later.

Python 2 (PyPy), 250 236 bytes
-14 bytes thanks to msh210's suggestions.
Outputs the 1-indexed nth term of the sequence.
n=input()
r=range
k=n*-~n*(n-~n)/6
m=k*k
for Q in r(m):
 P={0}
 for X in r(n,0,-1):P|=([x for x in[{(x+a,y+b)for a in r(X)for b in r(X)}for x in r(Q%k-X+1)for y in r(Q/k-X+1)]if not x&P]+[{0}])[0]
 if len(P)>k:m=min(Q%k*(Q/k),m)
print m

Try it online! For n>4, this takes lot of time. I have verified the result up to n=7 locally.

Would you mind including an explanation of how it works? Also, I imagine you can shave bytes by indenting one space at a time instead of seven (for the second indentation). (In fact, I think maybe the two for lines can be on one line, and you only need to indent once.)

@msh210 the "7 spaces" are in fact a tab, as in Python 2 you can indent first with a space, then with a tab. Putting the two for loops on one line would be invalid syntax unfortunately.

@msh210 I found a different way to combine those for loops. Those 7 spaces where only on line, thanks for the catch. I will try to write an explanation tomorrow


text:
Magical Modulo Squares
I'm a big fan of number theory. A big thing in number theory is modular arithmetic; the definition being \$a\equiv b\mod m\$ if and only if \$m\mid a-b\$. A fun thing to do is raising to powers: especially when the modulus is a prime number. In particular, it has been proven that if \$a\$ and \$m\$ are relatively prime (share no common factors besides \$1\$) then there exists a number \$e\$ such that \$a^e\equiv 1\mod m\$.
I will explain what the exercise is by an example. Let's take a modulus \$m=7\$. A possible output of the program or function would be:
3 2 6 4 5 1
2 4 1 2 4 1
6 1 6 1 6 1
4 2 1 4 2 1
5 4 6 2 3 1
1 1 1 1 1 1

Each row is a list of the powers of the first number in that row: the first row is \$3, 3^2, 3^3, \cdots, 3^6\$, which is equivalent to \$3,2,6,4,5,1\$ modulo \$7\$. The second row of the square above is the powers of \$2\$, etcetera, up to the last row, which are just powers of \$1\$.
This is a magical modulo square because:

The square is symmetric; that is, the \$i\$th column is the same as the \$i\$th row.
All values \$1\$ to \$m-1\$ appear at least once.

Below is the only other valid output for \$m=7\$, starting with powers of \$5\$:
5 4 6 2 3 1
4 2 1 4 2 1
6 1 6 1 6 1
2 4 1 2 4 1
3 2 6 4 5 1
1 1 1 1 1 1

The challenge
Create a function or program that given a prime p outputs a magical modulo square, that is, a square with side lengths p-1, such that each row is a list of the consecutive powers of the first element in the row, and the same for the columns. All numbers between 0 and p must occur, and the square can only contain numbers in that range.
Input is a number or a string, and output can be ascii, a matrix, an array of arrays (any reasonable format).
This is code-golf, so the shortest code wins.

Related OEIS sequence: A001918 (the lowest valid value for the top-left corner).

"I will explain what the exercise is by an example." Don't. Explain it in its own terms and then give an example to illustrate. I think that what you're asking for is a matrix $A$ such that $A_{1,1}$ is a primitive root modulo $p$ and $A_{i,j} = A_{1,1}{}^{ij} \bmod p$, but it's a lot of effort to extract that specification from the question as it stands.

@PeterTaylor true, and that is what I mean, but firstly, that spoils part of the exploration fun, and second, it relies on knowledge about primitive roots and modular arithmetic. I wanted this question to be answerable by a wider audience than that, so I tried to explain what I mean in easier terms.

Jelly, 13 10 bytes
-3 thanks to Nick Kennedy
Feels like the repeated code should be is golf-able, but I have did not managed it...
*€Ṗ%µQƑƇḢị

Try it online! (footer pretty-formats as a grid)
How?
*€Ṗ%µQƑƇḢị - Link: integer, p
 €         - for each n in [1..p]
*          -   exponentiate with:
  Ṗ        -     pop = [1..p-1]
           - ...i.e [[1^1,1^2,...,1^(p-1)],[2^1,2^2,...,2^(p-1)],...,[....,p^(p-1)]]
   %       - modulo p
    µ      - start a new monadic chain (call that list of lists X)
       Ƈ   - keep those which:
      Ƒ    -   are invariant under:
     Q     -     de-duplicate
        Ḣ  - head
         ị - index into the list of lists X

Here’s a 10: https://tio.run/##ASMA3P9qZWxsef//KuKCrOG5liXCtVHGkcaH4bii4buL/8OHR///Nw

Ahha, now I feel slow ;p thanks!

Charcoal, 36 bytes
≔Ｅ…¹θ﹪Ｘι…¹θＩθηＥ⊟Φη⁼¹№ι¹⪫Ｅ§η⊖ι◧ＩλＬ⊖θ

Try it online! Link is to verbose version of code. Note: Trailing space. Explanation:
≔Ｅ…¹θ﹪Ｘι…¹θＩθη

Create a p-1 by p-1 array of powers of 1..p-1 to indices 1..p-1 (modulo p).
Ｅ⊟Φη⁼¹№ι¹

Map over one of the rows which has exactly one 1.
⪫Ｅ§η⊖ι◧ＩλＬ⊖θ

Rearrange the rows into the order given by the selected row and format the output.

Wolfram Language (Mathematica), 46 43 bytes
Mod[PrimitiveRoot@#^Array[1##&,{#,#}-1],#]&

Try it online!
-3 thanks to alephalpha

J, 35 32 31 bytes
[:(/:0/:@{]\:#@~."1)]|^/~@}.@i.

Try it online!

Zsh, 117 90 bytes
b=$1
c=(eval set -- '$[x**'{1..$[b-1]}%b\])
for ((;${#${(u)@}}-b+1;++x))$c
for x;$c&&<<<$@

Try it online!
Try it online!
May God have mercy on my soul. There's a lot of bad practice all wrapped up here, let me explain the biggest offender at least:
c=(eval set -- '$[x**'{1..$[b-1]}%b\])
                      {1..$[b-1]}        # brace expansion, expands immediately
               '$[x**'           %b\]    # string literals, expand during eval
   eval set --                           # sets the positional parameters
c=(                                   )  # defines c to the words contained

Example for b=4:
c=(eval set -- '$[x**'{1..$[b-1]}%b\])
c=(eval set -- '$[x**'{1..3}%b\]     )                # $[b-1] => 3
c=(eval set -- '$[x**1%b]' '$[x**2%b]' '$[x**3%b]' )  # brace expansion

Finally, where $c appears in the rest of the program, the array elements are evaluated as eval set -- .....
Lastly, ${#${(u)@}} counts the unique elements int the positional parameters (i.e.: is there a cycle / are there 1s?)
Comments relevant to the 117 byte answer below.

Challenges we have to overcome:

No multidimensional or nested arrays. Instead we print out the strings as we get them in a loop.
Options for testing if a given row has multiple 1s:

${#${(M)a:#1}: :# removes matching, and (M) reverses the match. So, this will expand to the number (${#  }) of 1s in the array. Unfortunately this expansion doesn't play nicely with the arithmetic for loop we use here. If it did, it could potentially save a byte.
${${:-1}:*a}: This is the set intersection between the singleton 1 and the set a. This will expand to the single 1 if it is found in the array. Using this option, we save one character here, but lose 1 overall having to put off adding the 1s in the last row and column until the end.

f(){ # f [element] [modular base], puts powers up to n-2 into array $a
    a=()
    for i ({1..$[$2-2]})
        a+=($[$1**i%$2])
}
a=(1)                     # put 1 in a to force first loop iteration
for ((;${${:-1}:*a};))    # test for 1 in array $a
    f $[++x] $1           # increment x, iterate through all elements mod $1
for y ($a 1){             # for all elements in the [last array, 1]
    f $y $1               # put that row in $a
    <<<$a\ 1              # print out $a with 1 appended (space-delimited string)
}

Perl 6, 65 57 bytes
{.[|.first(*.Set+2>$_)]}o{.&{@=(($++X**1..^$_)X%$_)xx$_}}

Try it online!
There's probably some way to just output the square itself, but this does the same process outlined in the question, sorting the lists by their positions in the first list that is just a permutation of 1 to input-1. Returns as a list of lists.
BTW, there's a lot of jockeying around, trying to get around some of Perl 6's annoying limitations involving sequences vs arrays, and anonymous variables.
Explanation:
                               $++               xx$_    # Map 0 to i-1 to
                              (   X**1..^$_)             # n, n^2, n^3... n^(i-1)
                             (              X%$_)        # All modulo i
{                      }o{.&{                        }}  # Pass to the next function
 .[                   ]    # Index into that list of lists
   |.first(          )     # The list of the first list that
           *.Set+2>$_        # Has all the elements in the range 1 to i-1

JavaScript (ES7),  91  86 bytes
This version attempts to compute the powers before applying the modulo and will fail for \$p\ge11\$ because of loss of precision. It is otherwise using the same logic as the commented version below.
f=(p,k)=>(g=k=>[...Array(i=p-1)].map(_=>k**++i%p))(k).sort()[1]>1?g(k).map(g):f(p,-~k)

Try it online!

JavaScript (ES6),  92  87 bytes
This version uses modular exponentiation to support (much) higher input values.
f=(p,k)=>(g=k=>[...Array(p-1)].map(_=>n=n*k%p,n=1))(k).sort()[1]>1?g(k).map(g):f(p,-~k)

Try it online!
How?
Finding the first row
Given \$1\le k<p\$, we use the helper function \$g\$ to compute \$a_k(n)=k^n\bmod p\$ for \$1\le n<p\$.
g = k =>              // k = input
  [...Array(p - 1)]   // generate an array of size p - 1
  .map(_ =>           // for each entry in there:
    n = n * k % p,    //   update n to (n * k) mod p
    n = 1             //   starting with n = 1
  )                   // end of map()

We look for \$k\$ such that there's only one value \$n\$ such that \$a_k(n)=1\$. We do that by sorting the array and testing if the 2nd element is greater than \$1\$.
g(k).sort()[1] > 1

This works even in lexicographical order -- which is the default behavior of sort() -- because:

if there are several \$1\$'s, they will all be moved to the front just like they would in numeric order
if there's only a single \$1\$, the 2nd value will be greater than \$1\$, no matter if it's really the 2nd value in numeric order or not

Example:
For \$p=17\$:

for \$k=1\$, we get:

\$a_1=[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]\$
sorted as \$[ 1, \color{red}1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]\$

for \$k=2\$, we get:

\$a_2=[ 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9, 1 ]\$
sorted as \$[ 1, \color{red}1, 13, 13, 15, 15, 16, 16, 2, 2, 4, 4, 8, 8, 9, 9 ]\$

for \$k=3\$, we get:

\$a_3=[ 3, 9, 10, 13, 5, 15, 11, 16, 14, 8, 7, 4, 12, 2, 6, 1 ]\$
sorted as \$[ 1, \color{red}{10}, 11, 12, 13, 14, 15, 16, 2, 3, 4, 5, 6, 7, 8, 9 ]\$

Building the matrix
Once we've found \$k\$, we invoke \$g(k)\$ again (to retrieve the unsorted version of the array) and invoke \$g\$ on each element of \$g(k)\$ to build the rows of the matrix.
This part can be simply written as:
g(k).map(g)

.indexOf(1)>p-3 saves 3 bytes over .every.

@Neil Thanks. But I've found a shorter way after a good night's sleep. :)

05AB1E, 19 16 bytes
LεI<LmI%}ÐΘOÏн<è

-3 bytes thanks to @Emigna.
Try it online (the footer is to pretty-print the 2D list).
Explanation:
L          # Create a list in the range [1, (implicit) input]
 ε         # Map each number `y` in the list to:
  I<L      #  Create a list in the range [1, input-1]
     m     #  Get number `y` to the power of each number in this list
      I%   #  Take modulo-input on each number
 }Ð        # After the map: triplicate this modified matrix
   ΘO      # Get the amount of 1s in each row
     Ï     # And only leave the rows with exactly one 1
      н    # Then only leave the first row which contains a single 1
       <   # Decrease each value by 1 to make it 0-indexed
        è  # And index each into the rows of the modified matrix to create a new matrix
           # (which is output implicitly as result)

LεI<LmI%}ÐΘOÏн<è for 16 bytes.

@Emigna Thanks! Didn't realize <è would have been enough instead of the UΣXyk I had.

Python 2, 108 bytes
def f(p):R=range(1,p);return[m for m in[[[j**(k*i)%p for i in R]for k in R]for j in R]if sorted(m[0])==R][0]

Try it online!

Can't you do print instead of return?

Wolfram Language (Mathematica), 67 bytes
(s=Thread@Mod[x^#&/@(x=Range[#-1]),#])[[#&@@Select[s,Sort@#==x&]]]&

Try it online!

Pari/GP, 45 bytes
n->lift(matrix(n-1,,i,j,znprimroot(n)^(i*j)))

Try it online!

APL(NARS), 29 chars, 58 bytes
{k←⍵∣⍺*⍳⍵-1⋄⊃{m∣k*⍵}¨⍳¯1+m←⍵}

test:
  f←{k←⍵∣⍺*⍳⍵-1⋄⊃{m∣k*⍵}¨⍳¯1+m←⍵}
  3 f 7
3 2 6 4 5 1
2 4 1 2 4 1
6 1 6 1 6 1
4 2 1 4 2 1
5 4 6 2 3 1
1 1 1 1 1 1
  5 f 7
5 4 6 2 3 1
4 2 1 4 2 1
6 1 6 1 6 1
2 4 1 2 4 1
3 2 6 4 5 1
1 1 1 1 1 1

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Roots of Arbitrary Numbers
One day, when I was bored in maths class, I learned of a neat trick for solving the real cube root of a number!
Let's use the number \$79,507\$ as an example.
First, take digit in the one's place and compare it to this table:
\begin{array} {|r|r|}
\hline
\text{Extracted Digit} &\text{Resulting Digit} \\
\hline
\text{1} &\text{1} \\
\text{2} &\text{8} \\
\text{3} &\text{7} \\
\text{4} &\text{4} \\
\text{5} &\text{5} \\
\text{6} &\text{6} \\
\text{7} &\text{3} \\
\text{8} &\text{2} \\
\text{9} &\text{9} \\
\text{0} &\text{0} \\
\hline
\end{array}
In this example, the Resulting Digit will be \$3\$ since the extracted digit is \$7\$.
Next, remove all digits that are less than \$10^3\$:
$$ 79507 → 79 $$
Then, find the largest perfect cube that does not exceed the input:
$$ 64 < 79 $$
\$64=4^3\$, thus the next digit needed is \$4\$.
Finally, multiply the digit found in the previous step by \$10\$ and add the Resulting Digit found in the first step:
$$ 10*4+3=43 $$
Thus, the cube root of \$79,507\$ equals \$43\$.
However, there a neat quirk about this trick: it doesn't apply to only cubed numbers.  In fact, it works with all \$n>1\$ where \$n\bmod2\ne0\$.
The steps mentioned above can be summed up in this generalization for an \$n\$ power:

Step 1) Take the digit in the one's place in the input.  Compare it to the one's place digit of the \$n\$th powers of \$1\$ to \$10\$, then use the corresponding digit.
Step 2) Remove all digits of the input less than \$10^n\$.  Compare the resulting number to the perfect powers definied in Step 1.  Use the \$n\$th root of the largest perfect power less than said number.  (Largest perfect power can exceed \$10^n\$)
Step 3) Multiply the number from Step 2 by 10 then add the number from Step 1.  This will be the final result.

Task
Given two positive integers \$n\$ and \$m\$, return the \$n\$th root of \$m\$.
Input:

Two positive integers \$n\$ and \$m\$.
\$m\$ is guaranteed to be a perfect \$n\$th power of an integer.
\$n\$ is guaranteed to be odd and greater than \$2\$.  (This method doesn't work if \$n\$ is even.)

Output:

The values calculated in steps 1 and 2.
The \$n\$th root of \$m\$.
Output can be on multiples lines or a list, whichever is more convenient.

Rules:

This is code-golf, so the fewer bytes, the better!
Standard I/O rules apply.
The output must be calculated using the aforementioned method.
No builtins allowed that already calculate this.  A prime example being TI-BASIC's x√ command.

Examples:
Input      | Output
-------------------
3, 79507   | 3
           | 4
           | 43
3, 79507   | [3, 4, 43]
5, 4084101 | 1
           | 2
           | 21
5, 4084101 | [1, 2, 21]

Sandbox post.

Are we allowed to use a built-in root command for step 2? Or are we only allowed to compute numbers to the $n$th power and compare?

Do x using y challenges are frowned upon usually as per meta consensus (as it is often difficult to enforce that they've gotten to x using y only).

I second @MagicOctopusUrn 's comment about "Do X with method Y" challenges; also I'd note that this trick works with $n=1$ although it is of course trivial.

To make the algorithm requirement observable, you could require that our code output the results of specific intermediate steps.

@RobinRyder yes, you are allowed to use a built-in root method to get the 10's place digit as is described in Step 2, but nothing else

@xnor i didn't include a requirement for printing out the intermediate steps; the source code will be able to show whether the method was used or not.

However, if the general consensus deems it necessary, I will edit the challenge to include this.

Requirement added.

Well... One could now compute $x=m^{1/n}$ with a built-in and output $[floor(x/10),x\bmod 10]$...

@Arnauld "No builtins allowed that already calculate this.  A prime example being TI-BASIC's x√ command".  What i meant by my response to RobinRyder was that you can use a root function to get the 10's place digit, but you can't use it for Step 1's value.

My point is that using the required algorithm is still non-observable.

Hm, fair point.  I suppose that this was a very subjective challenge in the first place.

You may want to add a couple smaller test cases, 3, 1 = [1,0,1] and 5, 32 = [2, 0 2]

And the sandbox didn't catch the issues...what else is new???

05AB1E, 18 bytes
Saved 1 byte thanks to Kevin Cruijssen
mθ=²¹°÷DÝ¹m@O<=ìï=

Try it online!

As per general consensus, the challenge has been edited to require the printing of intermediate steps.

‹_ can be @ to save a byte.

@KevinCruijssen: What! I am 100% certain that didn't work when I tried it before :(

@Tau: Now prints intermediate results.

Not really in spec with the challenge, but just putting it out there: 9 bytes: zmò¤,D¨,, or zmòÐ¨sθr»

JavaScript (ES7),  58  56 bytes
Saved 11 many bytes thanks to @Emigna
Takes input as (m)(n). Returns the 2 intermediate values and the final result as an array.
m=>g=(n,k)=>k**n>m/10**n?[u=m**n%10,--k,k*10+u]:g(n,-~k)

Try it online!

JavaScript (Node.js), 62 bytes
This version uses BigInts as I/O to support larger inputs.
m=>g=(n,k=0n)=>k**n>m/10n**n?[u=m**n%10n,--k,k*10n+u]:g(n,++k)

Try it online!

As per general consensus, the challenge has been edited to require the printing of intermediate steps.

This fails when the final digit is a 0. For example f(1000,3) returns 0 instead of 10.

@RobinRyder Should be fixed now. (However, the 58-byte version only support very small inputs.)

R, 74 bytes
function(m,n)c(a<-match(m%%10,(1:9)^n%%10,0),b<-(m/10^n)^(1/n)%/%1,a+10*b)

Try it online!
match(m%%10,(1:9)^n%%10,0) compares the last digit of m  to the reference table (and outputs 0 if no match is found), thus performing step 1.
(m/10^n)^(1/n)%/%1 gives the output of step 2.

clever use of nomatch, although of course match(...,(0:9)^n%%10)-1 would be just as golfy

@Giuseppe Yes, I had that version initially as well, but decided I liked the version with nomatch better. :-)

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Hungry Blobs KoTH
Contest Finished! Read comments on blobs to view their score.
This KoTH is loosely inspired by Primer's Natural Selection Simulation. Your bot is a blob. In order to survive, you must eat pellets to regain energy, which is used to move. With extra energy, blobs can split into two.
Energy and Movement
Your blob starts off each round with 100 energy, and it has no limit on the amount of energy it can collect. Each round is run in turns, with each blob having the option to move North, East, South, or West in any given turn, or stand still. Moving uses 1 energy, and standing still uses 0.25 energy. The map's side length is ceil(0.25 * blobCount) * 2 - 1 units, with a minimum of 9 units. All blobs start on the edge of the map, with one placed in each corner and every subsequent blob being placed 2 units away from any others. Every 30 turns, a wave of pellets are placed in random spots around the map, at least 1 unit from any edge. Each time a wave of pellets appears, the quantity of pellets (originally twice the number of blobs or the width of the map, whichever is larger) in the next wave is decreased by 1, forcing the number of blobs to decrease over time. Each pellet restores between 5 and 15 energy. When a blob's energy is less than or equal to 0, it dies.
Eating
If two or more blobs attempt to occupy the same location, the one with the most energy will eat the others, receiving their energy. If both have equal energy, both vanish.
Detection and Information
Blobs can see any pellets or other blobs within a distance of 4 units. When their functions are called, blobs are provided with:

The side length of the map
The position of the blob on the map
The positions of all pellets within their search radius, as well as their values
The positions of all blobs within their search radius, as well as their energy and UIDs
The energy, UID, and locations of the blob whose function is being executed
A storage object unique to the blob
A storage object shared by all blobs related to the blob through splitting

Splitting
If a blob has more than 50 energy, it can choose to split. Splitting costs 50 energy, and any remaining energy is divided evenly between the two blobs. All blobs are either originals or split copies, with every copy tracing back to an original. All of these together are "relatives." All relatives have one communal storage object. Relatives can still eat each other, and can split, use their own storage object, or collect energy without affecting others.
Energy Transfer
If two blobs are next to each other (after moving), one of the bots can transfer energy to the other. This is done by returning SendNorth(amt), SendEast(amt), SendSouth(amt), or SendWest(amt), with amt being a number representing the amount sent. This can be any amount that the sender can afford, including all of their energy. It is recommended that the blob who is receiving energy is told to stay still through communal storage, so that it does not move away when the energy is being transferred (though the energy would not be deducted from the sender's total in this case).
Functions, Storage, and UIDs
In order to allow more complex learning behaviors, all blobs will be given an integer UID (Unique Identifer). These UIDs will be randomly generated each map, preventing strategies based on individual targets. When a blob's function is called, it is passed four arguments:

The side length of the map as an integer
An object with two arrays: pellets, and blobs. Both arrays contain objects, both having a pos property containing the pellet or blob's position formatted as [x,y]. Pellets will have an energy property, while blobs will have a uid property and an energy property
An object containing various properties of the blob it is passed to: energy, uid, and pos. The pos array is formatted as [x,y]
An object containing the two storage objects of the blob. A self property contains an individual storage object which can be modified however the blob sees fit (by manipulating properties of the object that is passed), and a communal property which can be modified by any relative.

Blobs are not moved immediately to prevent earlier/later turns having an advantage. All movements are processed in groups (All collisions/eating, then all pellets, then splitting, etc.) If a blob lands on a pellet or smaller blob and, in the process uses its last energy, the blob will still consume the pellet/energy independent of whether that would would bring its total energy above 0.
In order for relative blobs to recognize one another, the communal storage must be used for each blob to record its UID in an array, or through some other system.
Return Values
In order to move or split, the return value of the function is used. First, the meaning of the cardinal directions in terms of coordinates:

North = -Y
East = +X
South = +Y
West = -X

Note that [0,0] is the top left corner, and Y increases as you go down. The return value of the function should follow these rules:

To do Nothing: Return nothing, 0, null, undefined, false, or any other value that equates to false
To Move: Return one of four global variables: North, East, South, or West, which equate to "north", "east", "south", or "west" (which could also be used as a return value)
To Split: Return the global variable SplitNorth, SplitEast, SplitSouth, or SplitWest, the direction indicating where to place the new blob

If a split command is returned and the amount of energy required is greater than or equal to the energy of the blob, nothing will happen. Blobs will not be able to leave the map.
Predefined Library Functions
There are a few basic functions available by default, to save some time:
taxiDist(pt1, pt2)
Returns the taxicab distance between two points (X distance plus Y distance).
taxiDist([0, 0], [2, 2]) //4
taxiDist([3, 4], [1, 5]) //3
taxiDist([1.25, 1.3], [1.3, 1.4]) //0.15
taxiDist([0, 0], [5, 2.5], 2.5) //3
taxiDist([0, 0], [2, 4], 2.5) //2.4

hypotDist(pt1, pt2)
Returns distance between two points according to the pythagorean theorem
hypotDist([0, 0], [5, 12]) //13
hypotDist([4, 6], [8, 9]) //5
hypotDist([0, 1], [2, 1]) //2
hypotDist([1, 1], [2, 2]) //sqrt(2)

modDir(dir, amt)
Takes the inputted direction, rotates 90 degrees clockwise amt times, then returns the new value.
modDist(North, 1) //East
modDist(East, 2) //West
modDist(West, 3) //South
modDist(South, 4) //South

Example Blob
This blob will not move until it finds a pellet nearby. Then, it will move in the direction it thinks is most likely to reward it. If its energy is ever above 150, it will split.
function(map, near, me, storage) {
    if (me.energy > 150)
        return SplitNorth;
    if (!near.pellets.length)
        return null;
    var dirs = [0, 0, 0, 0];
    for (let p, i = 0; i < near.pellets.length; i++) {
        p = near.pellets[i];
        dirs[0] += me.pos[1] - p.pos[1];
        dirs[1] += p.pos[0] - me.pos[0];
        dirs[2] += p.pos[1] - me.pos[1];
        dirs[3] += me.pos[0] - p.pos[0];
    }
    return [North, East, South, West][dirs.indexOf(Math.max(...dirs))];
}

Rules

Standard Loopholes are prohibited. Also, no Unstandard Loopholes.
No blob may attempt to modify or read any data not passed to it via its parameters
No blob may attempt to modify a return-value variable to sabotage other blobs
A round lasts until the only remaining blobs are relatives
No blob may modify data by injecting functions into its parameters which modify values using the this keyword
All submissions must either be in Javascript or a language which is not too different from Javascript (Python, for example). All answers will be converted to Javascript for the competition.
The winner is the blob which has collected the highest amount of energy in total across all rounds (from either pellets or consuming smaller blobs that are not relatives)

Controller: https://gist.github.com/Radvylf/1facc0afe24c5dfd3ada8b8a2c493242
Chatroom: https://chat.stackexchange.com/rooms/93370/hungry-blobs-koth

Can you expand this to other languages besides javascript?

@EmbodimentofIgnorance Submit it in whatever language you choose, and I'll do the conversion to JS.

Can blobs cross over each other Ex: blob1 at [0][0] moves right and blob2 at [0][1] moves left or will the blob with lower energy be eaten?

Related

@fəˈnɛtɪk Yes, bots can cross over each other. Also, the related challenge was mine (:

Introvert
The Introvert doesn't like other blobs. When it sees an unrelated blob, it eats it if it can, and begrudgingly accepts its presence it if it can't, though running away if it sees signs of aggression. When it sees a related blob, it distances itself. However, it can't help but split apart a lot.
Technical Details
The core feature of this blob is to split apart and spread out so as to maximize the combined vision of the blobs. It also employs a system to prevent two of them from competing over a pellet.
function introvert(mapSize, vision, self, storage) {
  if (!storage.communal.friends)
    storage.communal.friends = {};
  if (!storage.communal.claims)
    storage.communal.claims = {};
  storage.communal.friends[self.uid] = true;
  for (var i in storage.communal.claims)
    if (storage.communal.claims[i] === self.uid) {
      storage.communal.claims = {};
      break;
    }
  var food = {};
  for (var p of vision.pellets) {
    var score = p.energy - taxiDist(p.pos, self.pos);
    if (score > 0)
      food[p.pos] = score;
  }
  var danger = {};
  for (var i = 0; i < mapSize; i++) {
    danger['-1,' + i] = true;
    danger[mapSize + ',' + i] = true;
    danger[i + ',' + mapSize] = true;
    danger[i + ',-1'] = true;
  }
  var relatives = {};
  for (var b of vision.blobs) {
    if (b.uid in storage.communal.friends) {
      relatives[b.pos] = true;
    } else if (!storage.self.justSplit && b.energy < self.energy - taxiDist(b.pos, self.pos) * 0.75) {
      var score = b.energy - taxiDist(b.pos, self.pos) * 1.25;
      if (score > 0)
        food[b.pos] = score;
    } else {
      danger[b.pos] = true;
      danger[b.pos[0] + ',' + (b.pos[1] - 1)] = true;
      danger[b.pos[0] + 1 + ',' + b.pos[1]] = true;
      danger[b.pos[0] + ',' + (b.pos[1] + 1)] = true;
      danger[b.pos[0] - 1 + ',' + b.pos[1]] = true;
    }
  }
  storage.self.justSplit = !danger[self.pos] && self.energy > 150;
  function fromData(n) {
    return n.split(',').map(s => parseInt(s));
  }
  function fs(f) {
    return food[f] / taxiDist(f, self.pos);
  }
  var target = Object.keys(food).filter(f => !(f in storage.communal.claims)).map(fromData).sort((a, b) => fs(b) - fs(a))[0];
  if (target)
    storage.communal.claims[target] = self.uid;
  function ms(m) {
    if (danger[m])
      return 99999999;
    var dists = Object.keys(relatives).map(r => hypotDist(fromData(r), m));
    return (target ? taxiDist(target, m) : 0) - (dists.length ? dists.reduce((a, b) => a + b) / dists.length : 0);
  }
  var candidates = [
    {p: self.pos},
    {p: [self.pos[0], self.pos[1] - 1], d: storage.self.justSplit ? SplitNorth : North},
    {p: [self.pos[0] + 1, self.pos[1]], d: storage.self.justSplit ? SplitEast : East},
    {p: [self.pos[0], self.pos[1] + 1], d: storage.self.justSplit ? SplitSouth : South},
    {p: [self.pos[0] - 1, self.pos[1]], d: storage.self.justSplit ? SplitWest : West}
  ];
  if (storage.self.justSplit)
    candidates.shift();
  return candidates.sort((a, b) => ms(a.p) - ms(b.p))[0].d;
}

This looks like a pretty nice bot! The contest should be soon (bounty expires tomorrow).

@RedwolfPrograms I actually tested it out in the runner and it always wins by a pretty large margin.

Average Score per Round: 357.544

Animated Meal
A simple bot, just to start off the competition. Finds the nearest coin, and goes toward it. Based off the example bot.
function(map, near, me, storage) {
    var targs = near.pellets.map(el => taxiDist(el.pos, me.pos));
    var targ = near.pellets[targs.indexOf(Math.max(...targs))].pos;
    if (targ[0] == me.pos[0])
        return targ[1] < me.pos[1] ? North : South;
    return targ[0] < me.pos[0] ? West : East;
}

Average Score per Round: 24.933

And, in a surprising turn of events, the (modified slightly to reduce bugs) 5-liner wins 2nd

bloblib tester
function(map, near, me, storage) {
    // BlobLib, the main purpose of this post
    const bloblib = {
        // Returns only pellets and blobs that are within the immediate neighbourhood (within 1 space of) me
        getNeighbours: (known) => {
            let neighbours = {};
            neighbours.pellets = known.pellets.filter(x => x.pos[0] >= me.pos[0] - 1 && x.pos[0] <= me.pos[0] + 1 && x.pos[1] >= me.pos[1] - 1 && x.pos[1] <= me.pos[1] + 1);
            neighbours.blobs = known.blobs.filter(x => x.pos[0] >= me.pos[0] - 1 && x.pos[0] <= me.pos[0] + 1 && x.pos[1] >= me.pos[1] - 1 && x.pos[1] <= me.pos[1] + 1);
            return neighbours;
        },
        // Gets the blob or pellet at the given location
        getByPos: (pos, known) => {
            let pellets = known.pellets.filter(x => x.pos[0] == pos[0] && x.pos[1] == pos[1]);
            let blobs = known.blobs.filter(x => x.pos[0] == pos[0] && x.pos[1] == pos[1]);
            if (blobs.length) return blobs[0];
            if (pellets.length) return pellets[0];
            return null;
        },
        // Returns a 2d array of size, containing any known blobs or pellets
        areaMatrix: (size, known) => {
            let matrix = [];
            for (let x = 0; x < size; x++) {
                let row = [];
                for (let y = 0; y < size; y++) {
                    let realPos = [me.pos[0] - (x + Math.floor(size / 2)), me.pos[1] - (y + Math.floor(size / 2))];
                    row.push(getByPos(realPos, known));
                }
                matrix.push(row);
            }
            return matrix;
        },
        // Gets a cardinal direction pointing from from to to
        cardDirTo: (to, from = me.pos) => {
            let diff = bloblib.multiDist(from, to);

            if (diff[0] == 0 && diff[1] == 0) return null;

            if (Math.abs(diff[0]) > Math.abs(diff[1])) {
                // Gunna be east or west
                return diff[0] > 0
                    ? East
                    : West;
            } else {
                return diff[1] > 0
                    ? South
                    : North;
            }
        },
        // Returns a vector of the X and Y distances between from and to
        multiDist: (from, to) => {
            return [to[0] - from[0], to[1] - from[1]]
        },
        // Gets the closest object in objs to position to
        getClosest: (objs, to = me.pos) => {
            if (!objs || !objs.length) return null;

            let sorted = objs.concat().sort((a, b) => taxiDist(a.pos, to) - taxiDist(b.pos, to));
            return sorted[0];
        },
        // Should be run at startup. Calculates which directions are unsafe to move in
        dangerSense: (origin) => {
            let neighbours = bloblib.getNeighbours(near);
            let matrix = bloblib.areaMatrix(3, neighbours);

            if (me.pos[1] == 0 || (matrix[1,0] && isThreat(matrix[1,0]))) bloblib.unsafeDirs.push(North);
            if (me.pos[0] == map - 1 || (matrix[2,1] && isThreat(matrix[2,1]))) bloblib.unsafeDirs.push(East);
            if (me.pos[0] == 0 || (matrix[0,1] && isThreat(matrix[0,1]))) bloblib.unsafeDirs.push(West);
            if (me.pos[1] == map - 1 || (matrix[1,2] && isThreat(matrix[1,2]))) bloblib.unsafeDirs.push(South);
        },
        isThreat: (blob) => {
            if (!blob.uid) return false;
            if (storage.communal.blobs.includes(blob.uid)) return true;

            return blob.energy >= me.energy - 1;
        }
        // Attempts to move in the given direction
        // Rotates the direction 90 if it can't safely move
        attemptMove: (dir = North) => {
            for (let i = 0; i < 4; i++) {
                if (bloblib.unsafeDirs.includes(dir)) dir = modDir(dir, i);
                else return dir;
            }
            return null;
        },
        // Attempts to split in the given direction
        // Rotates the direction 90 if it can't safely split
        attemptSplit: (dir = SplitNorth) => {
            for (let i = 0; i < 4; i++) {
                if (bloblib.unsafeDirs.includes(dir)) dir = modDir(dir, i);
                else return dir;
            }
            return null;
        },
        // Returns the next direction in which to move toward pos
        // Don't bother checking if we have enough energy, because if
        // we have < 1 energy we're basically dead anyway
        moveTo: (pos) => {
            return bloblib.performAction(bloblib.attemptMove(bloblib.cardDirTo(pos)));
        },
        // Simply registers the action in communal history, then returns it unmodified
        performAction: (action) => {
            storage.communal.history[me.uid].push(action);
            return action;
        },

        // Stores directions in which there is another blob
        // This wouldn't make sense to store across turns, so we don't bother
        unsafeDirs: []
    };
    bloblib.dangerSense(me.pos);

    // Register this blob
    if (!storage.communal.blobs) storage.communal.blobs = [];
    if (!storage.communal.blobs.includes(me.uid)) storage.communal.blobs.push(me.uid);

    // Register history for this blob
    if (!storage.communal.history) storage.communal.history = {};
    if (!storage.communal.history[me.uid]) storage.communal.history[me.uid] = [];

    // Split if we can and there are fewer than 10 blobs in our community
    if (me.energy > 150 && storage.communal.blobs.length < 10) {
        let split = bloblib.getSplit();
        if (split) return split;
    }

    // If we can't see any pellets or blobs, don't do anything
    if (!near.pellets.length && !near.blobs.length) return null;

    // Move toward the nearest pellet
    return bloblib.moveTo(bloblib.getClosest(near.pellets));
}

The actual bot is fairly simple, but this is more designed as a proof of concept of bloblib, a collection of functions and functionality I plan to use and develop across other bots (feel free to use/expand on it yourself too)
In short, this bot does the following:
If energy > 150 and blobs_in_team < 10: Try to split
If visible_pellets = 0 and visible_blobs = 0: do nothing
Move toward the closest pellet in a safe way
    that avoids moving into other stronger or equal blobs
    or off the edge of the map

You can now see a blob's energy, that might come in handy

@RedwolfPrograms updated bloblib to determine whether enemy blobs are a "threat" based on their energy levels.

Average Score per Round: 7.913

This system could probably have been used for some good blobs, but this one seemed to act a bit strangely.

Greedy Coward
import random

def greedy_coward(map_length, near, me, storage):
    interesting_objects = [] #objects I can eat
    bad_objects = [] #objects that eat me
    allowed_directions = ["North", "East", "South", "West"]

    # add pellets to objects that I'm interested in
    for i in near.pellets:
        interesting_objects.append(i)

    # figure out which blobs are good and which are bad
    for i in near.blobs:
        # if I'm under or equal powered, add it to bad_objects
        if i.energy >= me.energy:
            bad_objects.append(i)
        # if I can eat it, add it to interesting objects.
        else:
            interesting_objects.append(i)

    # if there are any bad objects, process them.
    if not len(bad_objects) == 0:

        # find the nearest bad object and make sure I don't move towards it
        bad_objects_distances = []
        for i in bad_objects:
            bad_objects_distances.append(taxiDist(i.pos, me.pos))
        worst_object = bad_objects[bad_objects_distances.index(min(bad_objects))]

        # find the direction of the worst object
        bad_object_xy_distance = [worst_object.pos[0] - me.pos[1], worst_object.pos[1] - me.pos[1]]
        closest_number = min(bad_object_xy_distance)
        bad_object_direction_vague = [["West","East"],["North","South"]][bad_object_xy_distance.index(closest_number)]
        if closest_number < 0:
            bad_object_direction = bad_object_direction_vague[1]
        else:
            bad_object_direction = bad_object_direction_vague[0]

        # remove bad object direction from allowed directions
        allowed_directions.remove(bad_object_direction)

    # process interesting objects if they exist
    if not len(interesting_objects) == 0:

        # find the nearest interesting object
        interesting_objects_distances = []
        for i in interesting_objects:
            interesting_objects_distances.append(taxiDist(me.pos, i.pos))
            interesting_object = interesting_objects[interesting_objects_distances.index(min(interesting_objects_distances))]

        # find the direction of the best object
            good_object_xy_distance = [interesrting_object.pos[0] - me.pos[1], interesting_object.pos[1] - me.pos[1]]
            closest_number = min(good_object_xy_distance)
            good_object_direction_vague = [["West","East"],["North","South"]][good_object_xy_distance.index(closest_number)]
            if closest_number < 0:
                good_object_direction = good_object_direction_vague[1]
            else:
                good_object_direction = good_object_direction_vague[0]

        # if the good and bad objects are in the same direction, move randomly in a different direction
        if good_object_direction == bad_object_direction:
            return random.choice(allowed_directions)
        else: # otherwise go towards the good object.
            return good_object_direction

    return 0 # when in doubt, stay still

Or, in JavaScript,
function(map_length, near, me, storage) {
    var interesting_objects = []; //objects I can eat
    var bad_objects = []; //objects that eat me
    var allowed_directions = ["north", "east", "south", "west"];

    //add pellets to objects that I'm interested in
    for (let i in near.pellets) {
        interesting_objects.push(near.pellets[i]);
    }

    //figure out which blobs are good and which are bad
    for (let i in near.blobs) {
        //if I'm under or equal powered, add it to bad_objects
        if (near.blobs[i].energy >= me.energy) {
            bad_objects.push(near.blobs[i]);
        }
        //if I can eat it, add it to interesting objects.
        else {
            interesting_objects.push(near.blobs[i]);
        }
    }

    //if there are any bad objects, process them.
    if (bad_objects.length) {

        //find the nearest bad object and make sure I don't move towards it
        var bad_objects_distances = [];
        for (i in bad_objects) {
            bad_objects_distances.push(taxiDist(bad_objects[i].pos, me.pos));
        }
        var worst_object = bad_objects[bad_objects_distances.indexOf(Math.min(...bad_objects_distances))];

        //find the direction of the worst object
        var bad_object_xy_distance = [worst_object.pos[0] - me.pos[1], worst_object.pos[1] - me.pos[1]];
        var closest_number = Math.min(...bad_object_xy_distance.map(el => Math.abs(el)));
        var bad_object_direction_vague = [["west","east"],["north","south"]][bad_object_xy_distance.map(el => Math.abs(el)).indexOf(closest_number)];
        if (closest_number < 0) {
            var bad_object_direction = bad_object_direction_vague[1];
        } else {
            var bad_object_direction = bad_object_direction_vague[0];
        }

        //remove bad object direction from allowed directions
        allowed_directions = allowed_directions.filter(el => el !== bad_object_direction);

    }

    //process interesting objects if they exist
    if (interesting_objects.length) {

        //find the nearest interesting object
        var interesting_objects_distances = [];
        for (i in interesting_objects) {
            interesting_objects_distances.push(taxiDist(me.pos, interesting_objects[i].pos))
        }
        var interesting_object = interesting_objects[interesting_objects_distances.indexOf(Math.min(...interesting_objects_distances))];

        //find the direction of the best object
        var good_object_xy_distance = [interesting_object.pos[0] - me.pos[1], interesting_object.pos[1] - me.pos[1]];
        var closest_number = Math.min(...good_object_xy_distance.map(el => Math.abs(el)));
        var good_object_direction_vague = [["west","east"],["north","south"]][good_object_xy_distance.map(el => Math.abs(el)).indexOf(closest_number)];
        if (closest_number < 0) {
            var good_object_direction = good_object_direction_vague[1];
        } else {
            var good_object_direction = good_object_direction_vague[0];
        }

        //if the good and bad objects are in the same direction, move randomly in a different direction
        if (good_object_direction == bad_object_direction) {
            return allowed_directions[allowed_directions.length * Math.random() | 0];
        } else{ //otherwise go towards the good object.
            return good_object_direction;
        }

    }

    return 0; //when in doubt, stay still
}

This bot isn't very interesting. It acts according to two priorities:

Don't get eaten.
Eat the nearest thing.

It never spits to maximize its ability to eat other things.

I'll get to work translating this! When I finish, I'll suggest an edit with the JS version.

@RedwolfPrograms Sounds good, thank you very much.

I think you need to add an if/else to check if there actually are any good/bad objects. It's causing several issues in the JS version.

@RedwolfPrograms It should be fixed now. I just added an if statement that checks the created lists of interesting and bad objects to make sure they are non-empty. Again, thank you for the help.

@RedwolfPrograms Do you have the JS version ready?

Average Score per Round: 8.221

SafetyBlob
This bot uses some of the same logic as Safetycoin from the previous KOTH.
How it functions
This bot will head towards food which it can either reach before any bigger bots do or at the same time/before a smaller bot. If it can't see any food which meets these criteria, it will move in a random direction(biased towards the center). If it gets to 150 energy and can not see safe food, it will split in one of the directions it has labeled as safe to move.
This bot doesn't keep track of its own children but they should not collide anyway due to the safety mechanisms.
 function SafetyBlob(map,local,me,stor){
  var center=(map/2|0)+1;
  var [x,y]=me.pos
  var uid=me.uid
  var others=local.blobs;
  var pellets=local.pellets;
  //Bot doesnt use storage because it just tries to find what it can.
  var willSplit=me.energy>150;
  var bestSafePelletValue=0;
  var bestSafePellet=null;
  var pellet;
  var other;
  //Head towards the best valued pellet (energy/distance) which can be reached before any larger or equal sized blobs or can be reached at the same time as smaller blobs
  for(i=0;i<pellets.length;i++){
    pellet=pellets[i]
    if(bestSafePelletValue<=pellet.energy/taxiDist(pellet.pos,me.pos)){
      for(j=0;j<others.length;j++){
        other=others[j];
        if(other.energy<me.energy){
          if(taxiDist(pellet.pos,me.pos)<=taxiDist(other.pos,pellet.pos)){
            if(taxiDist(pellet.pos,me.pos)<taxiDist(bestSafePellet.pos,me.pos)){
              bestSafePellet=pellet;
              bestSafePelletValue=pellet.energy/taxiDist(pellet.pos,me.pos);
            }
          }
        }
        if(other.energy>=me.energy){
          if(taxiDist(pellet.pos,me.pos)<taxiDist(other.pos,pellet.pos)){
            if(taxiDist(pellet.pos,me.pos)<taxiDist(bestSafePellet.pos,me.pos)){
              bestSafePellet=pellet;
              bestSafePelletValue=pellet.energy/taxiDist(pellet.pos,me.pos);
            }
          }
        }
      }
    }
  }

  if(bestSafePellet){
    [xPellet,yPellet]=bestSafePellet.pos;
    if(x<xPellet&&Math.abs(x-xPellet)>=Math.abs(y-yPellet)){
      return East;
    }
    if(x<xPellet&&Math.abs(x-xPellet)>=Math.abs(y-yPellet)){
      return West;
    }
    if(y<yPellet&&Math.abs(x-xPellet)<Math.abs(y-yPellet)){
      return South;
    }
    if(y<yPellet&&Math.abs(x-xPellet)<Math.abs(y-yPellet)){
      return North;
    }
  }

  var validMoves=["North","East","South","West","Stay"];
  var removeIndex=0;
  var safeEnergy;
  if(x==0)
    validMoves.splice(validMoves.indexOf("West"));
  if(x==map)
    validMoves.splice(validMoves.indexOf("East"));
  if(y==0)
    validMoves.splice(validMoves.indexOf("North"));
  if(y==map)
    validMoves.splice(validMoves.indexOf("South"));

  var possibleMoves=[...validMoves];
  possibleMoves.splice(possibleMoves.indexOf("Stay"));
  //If there is no safe pellet try to stick somewhat towards the middle
  //Ignore enemies unless at 2 distance from self and there is no safe pellet
  for(i=0;i<others.length;i++){
    other=others[i];
    safeEnergy=willSplit?(me.energy-50)/2:me.energy;
    if((other.energy>=safeEnergy)&&(taxiDist(me.pos,other.pos)<=2)){
      if(taxiDist(me.pos,other.pos)==1){
        if((removeIndex=validMoves.indexOf("Stay"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[0]<x){
        if((removeIndex=validMoves.indexOf("West"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[1]<y){
        if((removeIndex=validMoves.indexOf("South"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[0]>x){
        if((removeIndex=validMoves.indexOf("East"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[1]>y){
        if((removeIndex=validMoves.indexOf("North"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
    }
  }
  //If there are no safe moves move in a random direction (Reduce energy as much as possible with a slight chance of survival)
  if(!validMoves.length){
    switch (possibleMoves[Math.random()*possibleMoves.length|0]){
      case "North":
        return North;
      case "South":
        return South;
      case "East":
        return East;
      case "West":
        return West;
    }
  }
  //If there are safe moves bias towards moving towards the center block of 1/3 of the way from the sides
  if(!willSplit){
    //bias moving towards near the center
    biasedMoves=[];
    for(var i=0;i<validMoves.length;i++){
      switch(validMoves[i]){
        case "North":
          biasedMoves=biasedMoves.concat(y>center?"0".repeat(center/3|0).split``:"0".repeat(y-center).split``);
          break;
        case "South":
          biasedMoves=biasedMoves.concat(y<center?"2".repeat(center/3|0).split``:"2".repeat(center-y).split``);
          break;
        case "East":
          biasedMoves=biasedMoves.concat(y>center?"1".repeat(center/3|0).split``:"1".repeat(x-center).split``);
          break;
        case "West":
          biasedMoves=biasedMoves.concat(y<center?"3".repeat(center/3|0).split``:"3".repeat(center-x).split``);
          break;
        case "Stay":
          biasedMoves=biasedMoves.concat(["4"]);
          break;
      }
    }
  }
  if(willSplit){
    switch (biasedMoves[Math.random()*biasedMoves.length|0]){
      case "0":
        return SplitNorth;
      case "2":
        return SplitSouth;
      case "1":
        return SplitEast;
      case "3":
        return SplitWest;
      case "4":
        return Stay;
    }
  }
  else{
    switch (biasedMoves[Math.random()*biasedMoves.length|0]){
      case "0":
        return North;
      case "2":
        return South;
      case "1":
        return East;
      case "3":
        return West;
      case "4":
        return Stay;
    }
  }
}

I've already run the controller, but I might do it again later with this new bot. It's too late to reassign the bounty if it wins, but I'm curious about the result.

@RedwolfPrograms The goal wasn't to win the bounty.

I know, just making sure you know (:


text:
Is it a Munchausen Number?
A Munchausen Number in base \$b\$, also known as a Perfect digit-to-digit invariant or PDDI is a peculiar type of positive integer where the sum of its base-\$b\$ digits raised to themselves is equal to the number itself. They are named for the fictional Baron Munchausen, who apparently hoisted himself up via his own ponytail to save himself from drowning. A related concept is Narcissistic numbers.
For instance, \$1\$ is trivially a Munchausen number in every base because \$1^1=1\$. Additionally, every positive integer is a base-1 Munchausen number by definition.
More interestingly, \$3435\$ is a base-10 Munchausen number because \$3^3+4^4+3^3+5^5=3435\$, and in fact is the only other base-10 Munchausen number.
A partial list of Munchausen numbers in every base up to 35 can be found on the OEIS as sequence A166623.
Given a positive integer \$n>0\$, determine if it is a Munchausen number in any base \$b\geq2\$.
Rules

Default I/O rules apply, so:

Full program or functions are acceptable.
Input can be from STDIN, as a function argument, and output can be to STDOUT, as a function return value, etc.

Default loopholes apply.
The output must be one of two distinct, consistent results. So TRUE is fine for truthy and FALSE is fine for falsy, but you can reverse that or return None for truthy and 1 for falsy or whatever. Please specify the selected results in your answer.
Your answer has to work at least theoretically for any positive integer.
Munchausen numbers use the convention \$0^0=1\$, so \$2\$ is a base-2 Munchausen number as \$1^1+0^0=2\$. Your code must follow this convention.
Explanations are strongly encouraged, even though submissions will most likely use the brute-force search method.
Using esoteric languages earns you brownie points since Munchausen was apparently a strange person.

Test Cases
Truthy
1 (all bases)
2 (base 2)
5 (base 3)
28 (base 9 and base 25)
29 (base 4)
55 (base 4)
3435 (base 10)
923362 (base 9)
260 (base 128)
257 (base 64 and base 253)

Falsy
3
4
591912
3163
17
This is code-golf, so the shortest answer in each language (in bytes) wins!

Can we assume the maximum base we need to calculate is 35/36?

@BenjaminUrquhart no you may not; determine if it's a Munchausen number in any base b≥2.

How about just guessing "no."  There are a countably infinite number of integers and a provably finite number of Munchausens, so    probability of choosing a Munchausen number is   (n)/(Infinity) = 0 .   //ducks and runs

05AB1E, 7 bytes
LвDmOQZ

Try it online!
The larger test cases will time out on TIO.
Explanation
L         # push range [1 ... input]
 в        # convert input to a digit list in each of these bases
  Dm      # raise each digit to the power of itself
    O     # sum each
     Q    # check each for equality with input
      Z   # max

How is this filtering base-1 from the results?

@Shaggy: With this base conversion, all numbers are 1 in base-1. The only number that will return true for 1^1 is 1.

Jelly, 8 bytes
bŻ*`§ċ⁸Ị

Yields 0 for Munchausen and 1 otherwise.
Try it online!
Or see the first five hundred positive integers split up as [[Munchausen], [non-Munchausen]].
How?
bŻ*`§ċ⁸Ị - Link: integer, n
 Ż       - zero-range -> [0,1,2,3,4,...,n]
b        - (n) to base (vectorises)
   `     - with left as both arguments:
  *      -   exponentiation (vectorises)
    §    - sums
     ċ   - count occurrences of:
      ⁸  -   n
       Ị - is insignificant (abs(x) <= 1)

Alternative for 1 for Munchausen and 0 otherwise:
bŻ*`§ċ>1

Um... why do I think that your previous version was valid and this one is invalid?

I think my previous version was invalid since it did not say that 1 was Munchausen.

J, 33 28 27 bytes
e.1#.i.@>:^~@(#.inv ::1)"0]

Try it online!

e. is the input an element of...
1#. the sum of each row of...
i.@>: ... ] 0..input and the input itself, passed as left and right args to...
^~@(#.inv)"0 convert the right arg (input) to each base in the left arg and raise each result elementwise to itself ^~@.
::1 finally this is needed because you can't convert uniquely to base 1, so it errors.  in this case, we simply return 1, which won't match for any number except 1, which is what we want

R, 72 69 bytes
-1 byte thanks to digEmAll
function(x){for(b in 1+1:x)F=F|!sum((a=x%/%b^(0:log(x,b))%%b)^a)-x;F}

Try it online!
Outputs TRUE for Munchausen numbers and FALSE otherwise.
x%/%b^(0:log(x,b))%%b) converts x to base b, and the for loop does the rest of the work (reassigning F, which  is FALSE by default).
We need to allow the base b to go all the way to x+1 instead of x to handle the case x=1.

71 using a for loop

@digEmAll Thanks! I shaved off another 2 bytes by using booleans instead of integers.

I was trying to understand what you changed to save 2 bytes from mine besides changing + with | and removing !, then I realized I wrote 71 but my code was actually 70 :D

Great idea using | BTW !

@digEmAll Oh yes, I didn't even think to check your byte count! :)

Redefining F as potentially TRUE seems even worse than using F as a counter...

ahah, yes... assigning F/T to other boolean values makes me really guilty :D

JavaScript (ES7), 60 bytes
Returns a Boolean value.
n=>(F=b=>(g=n=>n&&g(n/b|0)+(n%=b)**n)(n)==n||b<n&&F(b+1))(2)

Try it online!
Commented
n =>                   // n = input
  ( F = b =>           // F = recursive function taking a base b
    ( g = n =>         //   g = recursive function taking an integer n
      n &&             //     if n is not equal to 0:
        g(n / b | 0) + //       do a recursive call with floor(n / b)
        (n %= b) ** n  //       and add (n mod b) ** (n mod b)
    )(n)               //   initial call to g with the original value of n
    == n ||            //   return true if the result is equal to n
    b < n &&           //   otherwise, if b is less than n:
      F(b + 1)         //     try with b + 1
  )(2)                 // initial call to F with b = 2

Japt, 13 bytes
õ@ìXÄ x_pZ
øN

Saved one byte thanks to @Shaggy
Try it

@Shaggy Fixed at the cost of a byte

You can get that byte back by replacing ÃÃøU with <newline>øN.

@Shaggy Nice trick with N, I never used it before!

Perl 6, 51 bytes
{?grep {$_==sum [Z**] .polymod($^a xx*)xx 2},^$_+2}

Try it online!
Explanation:
{                                                 } # Anonymous code block
 ?grep {                                  }         # Do any
                                           ,^$_+2   # Of the bases from 2 to n+1
            sum                              # Have the sum of
                      .polymod($^a xx*)      # The digits of n in that base
                [Z**]                  xx 2  # Raised to the power of themselves
        $_==                                 # Equal to the original number?

Ruby, 50 bytes
TIO timed out on 591912. Somehow edges out Perl by 1 byte... (at time of writing)
->n{(2..n+1).any?{|b|n.digits(b).sum{|d|d**d}==n}}

Try it online!

APL (dzaima/APL), 23 13 bytes
⊢∊⊂+.*⍨⍤⊤⍨¨2…

Try it online!
Thanks to Adám, ngn and dzaima, we managed to shave 10 bytes off this answer by using dzaima/APL.
Prefix tacit function. Munchausen numbers return 1, else 0.
How
⊢∊⊂+.*⍨⍤⊤⍨¨2… ⍝ Prefix tacit function, argument will be called ⍵

             2… ⍝ Generate the integer sequence [2..⍵]
          ⊤⍨¨  ⍝ Convert ⍵ to each base in the vector
     +.*⍨⍤      ⍝ Raise each digit of each element in the vector to itself, then sum
⊢∊⊂            ⍝ Check if ⍵ is in the resulting vector.

Wolfram Language (Mathematica), 65 bytes
#<2||!Tr[Check[#^#,1]&/@#~IntegerDigits~i]~Table~{i,2,#}~FreeQ~#&

Try it online!
-4 bytes from @attinat

65 bytes which also included some bugfixes

C (gcc) -lm, 79 75 bytes
f(n,b,i,g,c){for(g=b=1;b+++~n;g*=!!c)for(c=i=n;c-=pow(i%b,i%b),i/=b;);n=g;}

Try it online!
Returns 0 for Munchausen numbers, and 1 otherwise.

also 75 bytes
a,b;f(n){for(a=b=1;b+++~n;a*=g(n)!=n);n=a;}g(n){n=n?g(n/b)+pow(n%b,n%b):0;}

Try it online!

Charcoal, 17 bytes
Ｎθ¬Φθ⁼θΣＥ↨θ⁺²ιＸλλ

Try it online! Link is to verbose version of code. My 16-byte attempt didn't work but that might be a bug in Charcoal, so watch this space. Outputs - unless the number is a Munchausen number. Explanation:
Ｎθ                  Input `n` as a number
   Φθ               Try bases `2` .. `n+1`
       Σ            Sum of
         ↨θ         `n` converted to base
           ⁺²ι      Next trial base
        Ｅ           Each digit
              Ｘλλ   Raised to its own power
     ⁼              Equals
      θ             `n`
  ¬                 Logical Not

16 bytes using the newer version of Charcoal on ATO: Ｎθ⊙θ⁼θΣＥ↨θ⁺²ιＸλλ Attempt This Online Link is to verbose version of code. Outputs - for a Munchausen number, nothing if not.

C# (Visual C# Interactive Compiler), 99 bytes
n=>Enumerable.Range(2,n).Any(x=>{int g=0,t=n;for(;t>0;t/=x)g+=(int)Math.Pow(t%x,t%x);return g==n;})

Try it online!

Haskell, 61 bytes
_#0=0
b#n|m<-mod n b=m^m+b#div n b
f n=elem n$1:map(#n)[2..n]

Returns True for Munchausen and False otherwise.
Try it online!

Python 2, 83 81 bytes
def f(n,b=2):
 s=0;m=n
 while m:k=m%b;s+=k**k;m/=b
 return s==n or b<n>0<f(n,b+1)

Try it online!
Returns 1 for truthy and 0 for falsey. Because of the recursion, can't practically deal with 591912, but it works in the abstract.

Perl 6, 66 65 bytes
{$^a==1||[+] map {$a==[+] map {$_**$_},$a.polymod($_ xx*)},2..$a}

Try it online!

JavaScript (ES6), 88 bytes
f=n=>{for(b=2;n-b++;){for(c=0,r=n;r;r=(r-a)/b)c+=(a=(r%b))**a;if(n==c)return 1}return 0}

Icon, 109 bytes
procedure m(n)
every k:=2to n&{i:=n;s:=0
while{a:=i%k;a<:=1;s+:=a^a;0<(i/:=k)}
n=s&return 1}
return n=1|0
end

Try it online!
Times out for 591912. Icon treats 0^0 as an overflow and that's why I need an additional check for zero.

Stax, 15 bytes
╡!←!║╝âñoêû►╦ä▓

Run and debug it
Takes very long for the larger test cases.
Explanation:
{^xs|E{c|*m|+x=m|a Full program, unpacked
                   Implicitly input x
{              m   Map over bases [1 .. x]
 ^                   Increment base (effectively mapping over [2 .. x+1])
  xs                 Tuck x below base
    |E               Get digits of x in base
      {   m          Map over digits:
       c|*             copy and power
           |+        Sum
             x=      sum = x?
                |a Check if any element in array is true
                   Implicit output


text:
Output the date in the Mel calendar
The Mel calendar is used in the fictional world of Kaldia. Your goal is to convert dates into the Mel calendar.
This calendar has 13 months of 28 days each, plus 1 or 2 extra days after the last month. A year that is divisible by 4 but not by 100, or divisible by 400 has 366 days, and other years have 365 (i.e. our leap year rules, but with years in the Mel calendar).
You should use the month and day name abbreviations:
months: dia vio lis gil ful dyu mel ral zan pal mik fav ruj
days: dia vio lis gil ful dyu mel ral zan pal mik fav ruj ser rav tan lin rez jil din ket len lax nen pin mat kun mir
The extra days outside of any month have the month name of myuxet (no abbreviation here), and the day names are axet and teems, respectively.
0 dia dia is 1988/11/30.
You can take the input date as a string or a (year, month, day) tuple; alternatively, for functions, the parameter can be in your standard library's date type. The output should be a space-separated string.
Test cases
1776-07-04 => -213 ral ket
1859-12-15 => -129 dia rav
1917-04-14 => -72 ful nen
1981-02-04 => -8 lis mik
1988-11-30 => 0 dia dia
1988-12-01 => 0 dia vio
1988-12-28 => 0 vio dia
2017-01-01 => 28 vio ful
2019-04-22 => 30 dyu lis
2019-11-30 => 30 myuxet axet
2019-12-01 => 31 dia dia
2021-11-29 => 32 myuxet axet
2021-11-30 => 32 myuxet teems
2089-11-30 => 101 dia dia
2389-11-30 => 400 myuxet teems

You should be able to handle dates from 1 AD to 9999 AD at least.
Reference implementation in Perl 6
Standard loopholes are forbidden.

You should probably include in your post that axet and teems are at the end of the year, I was confused until I looked at the link

It has to be a space-separated string.

Can we take input as a three value named tuple or a list of three values each signifying year, month, and day?

Yes, that's fine.

May we output month and day in Title Case? -213 Ral Ket?

No, the date must be entirely in lowercase.

What range of years are allowed to handle? C# does not support dates before christ

I'd say that's good enough.

Perl 6, 174 bytes
{~(.year,(|[X]("diaviolisgilfuldyumelralzanpalmikfavrujserravtanlinrezjildinketlenlaxnenpinmatkunmir".comb(3)xx 2)[^364],|("myuxet"X <axet teems>))[.day-of-year-1])}o*-726436

Try it online!
Generate a list of all the valid dates and then indexes the day of the year into that list.
Explanation
{                                                   }  # Anonymous code block
                                                     o*-726436  # Subtract some days from the input
  (.year,                               # Output the year
           [X]("...".comb(3))[^365]     # Then produce a list of all months/days
         (|                        ,
          |("myuxet"X <axet teems>))    # And the extra days
                                    [.day-of-year-1]   # And get the current date
 ~   # Stringify the list

Ruby, 199 195 193 bytes
Oof, only 23 27 29 bytes saved over the sample Perl code...
-4 bytes from @NickKennedy.
-2 bytes from @Neil.
->d{d-=62764e6;y=d.yday;s="diaviolisgilfuldyumelralzanpalmikfavrujserravtanlinrezjildinketlenlaxnenpinmatkunmir".scan /.../;[d.year,y<364?s[y/28]:"myuxet",(y<364?s:%w[axet teems])[y%28-1]]*' '}

Try it online!

195 bytes (by using a less exact number for subtraction) https://tio.run/##PY3bjoIwFEXf/QqCGi@xSKtykUF/Yt4YYjrTMqm2lbRFrcZfHwSZ8LaysvY5qvq2dZF@1WBHHgSkAQqDNQ0SmxLPEmwTkdolihKduoThCztzpn8ZLypObCUoV5jfsSwxF@xU4IuqjpoqhS8GS86kovcj44TJEzWcSo5vksqSSYHNqZKCKdfTP1g6S8/zlknWvKRYLcQHXO11JvKtK2x1o8ZdTDu3HV8z3AjHUCp0PsvsGEUA5vl84kyedVkZ7bjD0WHnDB9F9skE9SS9Tuejg6dLzsx0D2az/OnWMAwD4IfAXw9gtIkBRABuBjCGrQKwsXEEgY/eQRw1PyBY@f/YWNgjigbIb2ewtQ3G7QWEOuxmHaIuQLC1KO7xHUR9u@rx71wadpa6BvIF

193 bytes by using y<364 instead of m<13 and then inlining the last use of m. Try it online!

Japt -S, 148 bytes
ÐUVW;f1Uf -726436
-ÐTT i1Ui¹z864e5
`¹avio¦sgÅ~ldyu´llzpal·kfavruj rvt¦nzjÅanket¤nlaxnpµtkun·r`pD ò3
[Ui Vz28 gW¯D p"myuxet")VgWp"axet"`ems`]

Saved 4 bytes thanks to @Shaggy. +A lot more bytes due to bug-fixes. Takes months as 0-indexed numbers.
Japt does have built-in date handling, but it's not very good. Seriously, 34 bytes to initialize a date, then subtract days from it, and then calculate which day of the year it is?
Try it
ÐUVW;                Initialize date object with given inputs
f1Uf -726436         Subtract 726436 days; Store in variable 'U'
-ÐTT i1Ui¹z864e5     Store the day of year in variable 'V'
`...`                Compressed string of all the days
  pD                 Repeated 13 times
    ò3               Split into chunks, where each chunks is 3 chars long, store in variable 'W'
[Ui                  Year
Vz28 gW¯D p"myuxet") Month
VgWp"axet"`ems`]    Day

Due to the (unnecessarily) strict output format, this should be "Japt -S". You can save 2 bytes by replacing both occurrences of 13 with D. I'll take another look in the morning (when I'm not down the pub, on my phone) to see if I can see any other savings but have a +1 in the meantime for beating Jelly by a significant margin.

Just spotted the sT; there's a shortcut for that ;)

Sadly, it looks like your byte count is off; TIO is counting in SBCS instead of UTF-8.

Jelly, 181 164 bytes
“BƥṠĿZȧ{ḷċ'#1ƇIræżzḤ$ḅ3ṃefɲ⁴S⁵ẊKḲ&8ɲz⁸Ẋ⁼ṣẸÇɼ:İ~¢ȥ³QⱮ:Ṗỵrɼ¬ṂĿZ⁵ṣ»Ḳḣ€3ḣ13pƊ;“¬ỵƇnḄẋFƬ@§Żị»ḲḢWpƊ¤
“ÇġƁʠÇỤḷṁÑWðṫ⁷m¥ṛʂɲðḊk¶`Ḣ»ḲjḢ$;;“","%Y%m%d"))+3499e5)”ŒVm7_2ȷ;ị¢$}ʋ/K

Try it online!
Jelly has no built-in date handling, so this falls back on the functionality within Python’s time module.
Explanation
“Bƥ...⁵ṣ»                      | Compressed string "diact viol lisk gild full dyu mela rale zanja palay miked fava ruj ser rave tanas linac rez jilt dinar ket lend lax nene pinas mat kune mire"
         Ḳ                     | split at spaces
          ḣ€3                  | first 3 characters of each
                 Ɗ             | following links as a monad
             ḣ13               |    first 13
                p              |    Cartesian product (with all 28)
                 ;           ¤ | concatenate to:
                  “¬...ị»      |   compressed string "myuxet axet teems"
                         Ḳ     |   split at spaces
                            Ɗ  |   following two links as a monad
                          Ḣ    |     head
                           p   |     Cartesian product (with last two)

“Ç...Ḣ»                             | Compressed string 'time  .local ( .mk ( .strp ("'
       Ḳ                            | split at spaces
        jḢ$                         | join using first item (i.e. time)
           ;                        | concatenate to input
            ;“"...)”                | concatenate this to '","%Y%m%d"))+3499e5)'
                    ŒV              | eval as Python
                      m7            | take every 7th item (year and day in year)
                                ʋ/  | reduce using following links as a dyad
                        _2ȷ         |   subtract 2000 (from first value, the year)
                           ;ị¢$}    |   concatenate with right argument (day in year) indexed into above link
                                  K | join with spaces

"this falls back on the functionality within Python’s time module." Ah, smart! I was trying to make an answer in 05AB1E (also lacking date builtins), and although I was able to get the amount of days between 1988-11-30 and the input-date, it wasn't really useful since I need the date-difference (years, months, and days) instead of days-difference. I have done a few other date related challenges in 05AB1E in the past (i.e. this one and some derivatives). I might try again with part of the code as compressed Python, being inspired by you. :)

Let me guess: the first string (diact viol lisk...) is written weirdly to compress better?

@bb94 yes it uses the shortest dictionary word for each where one is available.

That's actually really clever.

JavaScript (ES6), 297 269 252 249 245 bytes

f=
d=>(d=new Date(+d+3498336e5),d=(d-Date.UTC(y=d.getUTCFullYear(a=`diaviolisgilfuldyumelralzanpalmikfavrujserravtanlinrezjildinketlenlaxnenpinmatkunmir`.match(/.../g))))/864e5,y-2e3+` ${d<364?a[d/28|0]+` `+a[d%28]:`myuxet ${d&1?`teems`:`axet`}`}`)
<input type=date oninput=o.textContent=f(this.valueAsDate)><pre id=o>

Takes input as a JavaScript date object in UTC (would be 1 byte less as a JavaScript timestamp number). Edit: Saved 3 7 bytes thanks to @Arnauld.
Try it online! if the snippet still isn't working for you for some reason.

Unfortunately, I get something like 30 dyu undefined for this on Firefox.

Same here on chrome

@bb94 Odd, I use Firefox...

@EmbodimentofIgnorance I've tweaked the snippet slightly, does that help?

@Arnauld Yeah, I had just come to the same conclusion. Fortunately Date.UTC is the same length as new Date!

@Neil November 30 1988 gives 0 myuxet axet now

C# (Visual C# Interactive Compiler), 247 bytes
n=>$"{(n=n.AddDays(4049)).Year-2e3} {((k=n.DayOfYear-1)<365?s.Substring(k/28*3,3):"myuxet")} {(k<365?s.Substring(k%28*3,3):k<366?"axets":"teems")}";var s="diaviolisgilfuldyumelralzanpalmikfavrujserravtanlinrezjildinketlenlaxnenpinmatkunmir";int k;

Try it online!

Haskell, 387 373 372 bytes
import Data.Time.Calendar
t(a:b:c:r)=[a,b,c]:t r
t _=[]
w=t"diaviolisgilfuldyumelralzanpalmikfavrujserravtanlinrezjildinketlenlaxnenpinmatkunmir"
(%)=mod
a y=map(show y++)$[' ':m++' ':d|m<-take 13 w,d<-w]++" myuxet axet":[" myuxet teems"|y%4<1,y%400<1||y%100>0]
f d|n<-read.show$diffDays d$fromGregorian 1988 11 30=last$(a=<<[0..])!!n:[(reverse.a=<<[-1,-2..])!!(-n-1)|n<0]

Try it online!
Takes input as a Day object.
This was pretty fun to write! Basic idea is to build a list of dates and index into it for the result. Function a takes a year and outputs every date in that year in chronological order. Function f expands on a concatenating them together for successive years starting at 0. The trick is that for dates before the epoch we need to traverse backwards starting from the year -1 so we pass a values -1,-2... and reverse each list individually before concatenating them together. Finally, in function f we calculate the number of days between the epoch and our date (converting it from Integer to Int) and index into our list, taking care to fix our index if it's negative.
EDIT: golfed it down (-14)
EDIT 2: golfed down the day/month names list (-1)


text:
Composite Factor Soup
Per the fundamental theorem of arithmetic, for a given number \$n\$, it is possible to find it's prime factors, and they are unique. Let's imagine we talk only of \$n\$ that is non-prime (composite).
We can also find the factors of all the composite numbers smaller than \$n\$. For example if \$n\$ is 10, then it has factors 5 and 2. 9 has 3 and 3. 8 has 2, thrice. 6 has 3 and 2. 4 has 2 and 2. So for the number 10, all the prime factors of all the composite numbers smaller than 10 would be listed as 2,3, and 5.
Now if you put a lot of vegetables in a pot for soup, often the largest will rise to the top. So if we put all of these factors in a big pot, which one will be the largest and rise to the top? For 10 soup, that answer is 5.
"Silly", you might think, "the number \$n\$ itself will have the largest factors, larger than the factors of numbers smaller than \$n\$". But this is where you are wrong my friend!
For example, the factors of 16 are all 2, repeated four times. The factors of 15 are 5 and 3, now, I don't have to be a mathematician to tell that 15 is smaller than 16, but 5 is bigger than 2!
Your challenge is to explore how this works for bigger \$n\$. For any number given input number \$n\$, assumed natural, composite, and less than 2^32, find out which is the "largest factor" of all the prime factors of all the composite numbers less than or equal to \$n\$.
Good luck and have fun!
Smallest byte count wins.

Isn't this just the largest prime below n/2?

xnor, Could it be the largest prime below or up to and including n/2? That would fit the '10' example in the question.

xnor probably... but can it be proven?

The proof is easy. The smallest composite number given some prime $p$ is $2p$. Therefore, a larger prime than $n/2$ cannot give a composite number less or equal to $n$ (upper bound). Conversely, the largest prime less or equal to $n/2$ will give have at least one composite number less or equal to $n$, namely, $2p$ (existence)

Neim, 3 bytes
ᚺ>:

Explanation:
ᚺ   halve
 >  increment
  : previous prime

Try it online!

05AB1E, 4 bytes
;ÅPθ

Try it online or verify first \$[4,n]\$ numbers.
Explanation:
Implementation of the observation @xnor's made in his comment: largest prime \$\leq\frac{1}{2}n\$. Which I've literally implemented now (after @Arnauld reported some bugs in my initial program):
;     # Halve the (implicit) input
 ÅP   # Get a list of primes smaller than or equal to this
   à  # And only leave the largest prime
      # (which is output implicitly as result)

This doesn't work: it returns 2 instead of 3 for input 7, and fails similarly for any number that's 2 * a prime + 1. Removing the < fixes it.

@Grimy ;>ÅM was my original answer, which failed for 21 (resulting in 11 instead of 7). But it should be fixed now by using ÅP (which is $\leq$) instead of ÅM (which is $\lt$).

Yes it is. :) (According to the spec, you should only consider composite inputs in $[4,n]$ but it doesn't really matter.)

Wolfram Language (Mathematica), 19 bytes
Prime@PrimePi[#/2]&

Try it online!

Japt v1.4.5 -h, 6 bytes
z o fj

Try it

Jelly, 4 bytes
‘HÆp

Try it online!
As others have observed, the answer is the largest prime \$≤ n/2\$
Thanks to @Arnauld for correcting my order of halving/incrementing

J, 10 bytes
_4 p:-:@>:

Try it online!
Uses the xnor's observation
Explanation:
_4 p:       the next prime smaller than
        >:  the input  plus 1
     -:@    divided by 2

JavaScript (ES6), 40 bytes
After a careful analysis of (xnor's comment on) the challenge, it turns out that  42 41  40 is the answer.
n=>(g=k=>n%--k?g(k):k<2?n:g(--n))(n>>=1)

Try it online!
Commented
We look for the highest prime \$p\le\left\lfloor\dfrac{n}{2}\right\rfloor\$.
n => (          // n = input
  g = k =>      // g = recursive function looking for the highest divisor k < n of n
    n % --k ?   //   decrement k; if k is not a divisor of n:
      g(k)      //     do recursive calls until it is
    :           //   else:
      k < 2 ?   //     if k is less than 2 (i.e. n is prime):
        n       //       stop recursion and return n
      :         //     else:
        g(--n)  //       try again with n - 1
  )(n >>= 1)    // initial call to g with n = floor(n / 2)

Retina 0.8.2, 34 32 bytes
.+
$*
(.+)(?<!^\2+(..+))\1.*
$.1

Try it online! Edit: Saved 2 bytes thanks to @Grimy. Explanation:
.+
$*

Convert to unary.
(.+)

Find the largest number...
(?<!^\2+(..+))

... that is prime ...
\1.*

... and a factor of a number not greater than the input.
$.1

Convert to decimal.

-2 bytes

Factor, 37 bytes
: p ( n -- n ) 2 / primes-upto last ;

Try it online!

Ruby, 24+8 = 32 bytes
8 bytes for the -rprime flag (plus space) to import the Prime module. Prime.each(n) gets all primes up to n, then we just take the largest one. (We could take the last item since it's in order, but that costs more bytes.)
->n{Prime.each(n/2).max}

Try it online!

Husk, 7 bytes
→`↑İp≤½

Try it online!


text:
Make all the squares explode
You are given a square matrix of width \$\ge2\$, containing square numbers \$\ge1\$.
Your task is to make all square numbers 'explode' until all of them have disappeared. You must print or return the final matrix.
More specifically:

Look for the highest square \$x^2\$ in the matrix.
Look for its smallest adjacent neighbor \$n\$ (either horizontally or vertically and without wrapping around).
Replace \$x^2\$ with \$x\$ and replace \$n\$ with \$n\times x\$.

Repeat the process from step 1 until there's no square anymore in the matrix.
Example
Input matrix:
$$\begin{pmatrix}
625 & 36\\
196 & 324
\end{pmatrix}$$
The highest square \$625\$ explodes into two parts of \$\sqrt{625}=25\$ and merges with its smallest neighbor \$36\$, which becomes \$36\times 25=900\$:
$$\begin{pmatrix}
25 & 900\\
196 & 324
\end{pmatrix}$$
The highest square \$900\$ explodes and merges with its smallest neighbor \$25\$:
$$\begin{pmatrix}
750 & 30\\
196 & 324
\end{pmatrix}$$
The highest square \$324\$ explodes and merges with its smallest neighbor \$30\$:
$$\begin{pmatrix}
750 & 540\\
196 & 18
\end{pmatrix}$$
The only remaining square \$196\$ explodes and merges with its smallest neighbor \$18\$:
$$\begin{pmatrix}
750 & 540\\
14 & 252
\end{pmatrix}$$
There's no square anymore, so we're done.
Rules

The input matrix is guaranteed to have the following properties:

at each step, the highest square will always be unique
at each step, the smallest neighbor of the highest square will always be unique
the sequence will not repeat forever

The initial matrix may contain \$1\$'s, but you do not have to worry about making \$1\$ explode, as it will never be the highest or the only remaining square.
I/O can be processed in any reasonable format
This is code-golf

Test cases
Input : [[16,9],[4,25]]
Output: [[24,6],[20,5]]

Input : [[9,4],[1,25]]
Output: [[3,12],[5,5]]

Input : [[625,36],[196,324]]
Output: [[750,540],[14,252]]

Input : [[1,9,49],[1,4,1],[36,25,1]]
Output: [[3,6,7],[6,2,7],[6,5,5]]

Input : [[81,4,64],[16,361,64],[169,289,400]]
Output: [[3,5472,8],[624,323,1280],[13,17,20]]

Input : [[36,100,1],[49,144,256],[25,49,81]]
Output: [[6,80,2],[42,120,192],[175,21,189]]

Input : [[256,169,9,225],[36,121,144,81],[9,121,9,36],[400,361,100,9]]
Output: [[384,13,135,15],[24,1573,108,54],[180,11,108,6],[380,209,10,90]]

Input : [[9,361,784,144,484],[121,441,625,49,25],[256,100,36,81,529],[49,4,64,324,16],[25,1,841,196,9]]
Output: [[171,19,700,4032,22],[11,210,525,7,550],[176,60,6,63,23],[140,112,1152,162,368],[5,29,29,14,126]]

You must print or return the final matrix. Can I modify the input matrix instead?

@EmbodimentofIgnorance Yes, that's perfectly fine.

Values on the corner (diagonal)  are consider neighbors?

@LuisfelipeDejesusMunoz No, only horizontal and vertical, as specified.

Can the output be padded with (several rows and columns of) 0s?

Per the usual I/O rules, I’ve assumed a flat list of integers is fine for input and output (though processed as though it were a square matrix). Is that correct?

@RobinRyder Because $0$ can't appear in the payload data, I'd say that's acceptable.

@NickKennedy Yes, that's OK.

R, 301 287 277 274 222 217 195 186 178 174 bytes
Nothing particularly creative, including the zero buffering of the peripheral elements of the entry matrix, an earlier version later improved by Robin:
function(x){w=which.max
if(any(s<-!x^.5%%1)){
y=cbind(NA,rbind(NA,x,NA),NA)
z=y[i]=y[i<-w(y*y%in%x[s])]^.5
m=i+c(r<--c(1,nrow(y)),-r)
y[j]=y[j<-m[w(-y[m])]]*z
x=p(y[r,r])}
x}

Try it on-line
Using a sequence of numbers as its entry, and hence removing the call to a function, Nick Kennedy earlier managed a 186 bytes version of the algorithm as follows (with -10 bytes by Robin):
w=which.max;`~`=cbind;x=scan();while(any(s<-!x^.5%%1)){y=NA~t(NA~matrix(x,n<-length(x)^.5)~NA)~NA;i=w(y*y%in%x[s]);=i+c(r<--c(1,n+2),-r);y[j]=y[j<-m[w(-y[m])]]*(y[i]=y[i]^.5);x=y[r,r]};x

avoiding the definition of a (recursive) function, plus other nice gains.
Try it on-line

Your byte count is off. In any case, here’s a heavily golfed version at 196 bytes:  https://tio.run/##FU5basMwELyK@mHYTawQJXZIKu8BegahEtd5WHG0kNhgiVJf3ZVhZ2AeDPue55HG1jXtxtdBn6czNT@OLzpQ39QMqFP4vELNEfpKfoTvTZllCvE3EnT0xTecBugmXw9vFyDkXMnnle9DCwFTF6cunXY0QlzFzHEWTG9Re3LrBqTKJTDxeoe5yhl1NA9LiSrpzQgyGm/R2hVE4xbf2WUy/RbNq5L7T04DL/unw7w/CLXdCiWKk1BFIXblIWFRRzX/Aw

thanks for asking. In general, if someone posts a shorter version in a comment to your answer, you’re welcome to use it/adapt your answer on that basis. It would then be polite to add somewhere in the accompanying text 'Thanks to @ for saving  bytes!' or similar. If I’d ended up somewhere dramatically different to your answer but had taken inspiration from yours, I might instead have posted a separate answer acknowledging you. But here, most of what I’ve done are minor tweaks - the fundamental method remains yours.

Ruby, 140 135 bytes
Takes a flat list as input, outputs a flat list.
->m{i=1;(i=m.index m.reject{|e|e**0.5%1>0}.max
m[i+[1,-1,l=m.size**0.5,-l].min_by{|j|i+j>=0&&m[i+j]||m.max}]*=m[i]**=0.5if i)while i;m}

Try it online!
Explanation:
->m{                                # Anonymous lambda
    i=1;                            # Initialize i for the while loop
        (                           # Start while loop

i=m.index                           # Get index at...
    m.reject{|e|          }         # Get all elements of m, except the ones with...
                e**0.5%1>0          # a square root with a fractional component
                           .max     # Get the largest of these

m[i+                                # Get item at...
    [1,-1,l=m.size**0.5,-l]         # Get possible neighbors (up, down, left, right)
        .min_by{|j|i+j>=0&&m[i+j]|| # Find the one with the minimum value at neighbor
                            m.max}  # If out of range, return matrix max so
                                    #   neighbor isn't chosen
    ]
    *=m[i]**=0.5                    # Max square becomes its square root, then multiply
                                    #   min neighbor by it

)while i                            # End while loop. Terminate when index is nil.
m}                                  # Return matrix.

MATL, 49 48 bytes
`ttX^tt1\~*X>X>XJt?wy=(tt5M1Y6Z+*tXzX<=*Jq*+w}**

Try it online! Or verify all test cases.
How it works
`           % Do...while
  tt        %   Duplicate twice. Takes a matrix as input (implicit) the first time
  X^        %   Square root of each matrix entry
  tt        %   Duplicate twice
  1\~       %   Modulo 1, negate. Gives true for integer numbers, false otherwise
  *         %   Multiply, element-wise. This changes non-integers into zero
  X>X>      %   Maximum of matrix. Gives maximum integer square root, or zero
  XJ        %   Copy into clipboard J
  t         %   Duplicate
  ?         %   If non-zero
    wy      %     Swap, duplicate from below. Moves the true-false matrix to top
    =       %     Equals, element-wise. This gives a matrix which is true at the
            %     position of the maximum that was previously identified, and
            %     false otherwise
    (       %     Write the largest integer square root into that position
    tt      %     Duplicate twice
    5M      %     Push again the matrix which is true for the position of maximum
    1Y6     %     Push matrix [0 1 0; 1 0 1; 0 1 0] (von Neumann neighbourhood)
    Z+      %     2D convolution, keeping size. Gives a matrix which is 1 for the
            %     neighbours of the value that was replaced by its square root
    *       %     Multiply. This replaces the value 1 by the actual values of
            %     the neighbours
    t       %     Duplicate
    XzX<    %     Minimum of non-zero entries
    =       %     Equals, element-wise. This gives a matrix which is true at the
            %     position of the maximum neighbour, and zero otherwise
    *       %     Multiply, element-wise. This gives a matrix which contains the
            %     maximum neighbour, and has all other entries equal to zero
    J       %     Push the maximum integer root, which was previously stored
    q       %     Subtract 1
    *       %     Multiply element-wise. This gives a matrix which contains the
            %     maximum neighbour times (maximum integer root minus 1)
    +       %     Add. This replaces the maximum neighbour by the desired value,
            %     that is, the previously found maximum integer square root
            %     times the neighbour value
    w       %     Swap
  }         %   Else. This means there was no integer square root, so no more
            %   iterations are neeeded
  **        %   Multiply element-wise twice. Right before this the top of the
            %   stack contains a zero. Below there are the latest matrix with
            %   square roots and two copies of the latest matrix of integers,
            %   one of which needs to be displayed as final result. The two
            %   multiplications leave the stack containing a matrix of zeros
            %   and the final result below
            % End (implicit). The top of the stack is consumed. It may be a
            % positive number, which is truthy, or a matrix of zeros, which is
            % falsy. If truthy a new iteration is run. If falsy the loop exits
            % Display (implicit)

Perl 6, 236 bytes
{my@k=.flat;my \n=$_;loop {my (\i,\j)=@k>>.sqrt.grep({$_+|0==$_},:kv).rotor(2).max(*[1]);last if 0>i;$/=((0,1),(0,-1),(1,0),(-1,0)).map({$!=i+n*.[0]+.[1];+$!,n>.[0]+i/n&.[1]+i%n>=0??@k[$!]!!Inf}).min(*[1]);@k[i,$0]=j,j*$1};@k.rotor(+n)}

Try it online!

213 bytes. I have some doubts that the looping mechanism is as short as it could be though... I'm also annoyed that we're being beaten by Python, so maybe a different approach is in order

Python 2, 188 bytes
M=input()
l=int(len(M)**.5)
try:
 while 1:m=M.index(max(i**.5%1or i for i in M));_,n=min((M[m+i],m+i)for i in m/l*[-l]+-~m%l*[1]+[l][:m/l<l-1]+m%l*[-1]);M[m]**=.5;M[n]*=M[m]
except:print M

Try it online!
Full program. Takes input and prints as a flat list.

JavaScript (ES6), 271 259 250 245 bytes
m=>{for(l=m.length;I=J=Q=-1;){for(i=0;i<l;i++)for(j=0;j<l;j++)!((q=m[i][j]**.5)%1)&&q>Q&&(I=i,J=j,Q=q);if(I<0)break;d=[[I-1,J],[I+1,J],[I,J-1],[I,J+1]];D=d.map(([x,y])=>(m[x]||0)[y]||1/0);[x,y]=d[D.indexOf(Math.min(...D))];m[x][y]*=Q;m[I][J]=Q}}

Thanks to Luis felipe De jesus Munoz for −14 bytes!
Explanation:
m => { // m = input matrix
  // l = side length of square matrix
  // I, J = i, j of largest square in matrix (initialized to -1 every iteration)
  // Q = square root of largest square in matrix
  for (l = m.length; (I = J = Q = -1); ) {
    // for each row,
    for (i = 0; i < l; i++)
      // for each column,
      for (j = 0; j < l; j++)
        // if sqrt of m[i][j] (assigned to q) has no decimal part,
        // (i.e. if m[i][j] is a perfect square and q is its square root,)
        !((q = m[i][j] ** 0.5) % 1) &&
          // and if this q is greater than any previously seen q this iteration,
          q > Q &&
          // assign this element to be the largest square in matrix.
          ((I = i), (J = j), (Q = q));
    // if we did not find a largest square in matrix, break loop.
    if (I < 0) break;
    // d = [i, j] pairs for each neighbor of largest square in matrix
    d = [[I - 1, J], [I + 1, J], [I, J - 1], [I, J + 1]];
    // D = value for each neighbor in d, or Infinity if value does not exist
    D = d.map(([x, y]) => (m[x] || 0)[y] || 1 / 0);
    // x = i, y = j of smallest adjacent neighbor of largest square
    [x, y] = d[D.indexOf(Math.min(...D))];
    // multiply smallest adjacent neighbor by square root of largest square
    m[x][y] *= Q;
    // set largest square to its square root
    m[I][J] = Q;
  } // repeat until no remaining squares in matrix
  // no return necessary; input matrix is modified.
};

Jelly, 70 67 bytes
’dL½$}©+Ø.,U$;N$¤%®‘¤<®Ạ$Ƈæ.®‘ịÐṂḢ;ḷ;€ị½¥×÷ƭ⁹Ḣ¤¦Ṫ}¥ƒ
×Æ²$MḢçɗ⁸Ẹ?ƊÐL

Try it online!
I’m sure this can be done much more briefly, but I found this harder than it first appeared. Explanation to follow once I’ve tried to golf it better.
A full program that takes a list of integers corresponding to the square matrix and returns a list of integers representing the final exploded matrix.l

C# (Visual C# Interactive Compiler), 220 bytes
n=>l=>{for(int g;n.Any(x=>Math.Sqrt(x)%1==0);n[n.Select((a,b)=>(x:Math.Abs(b/l-g/l)+Math.Abs(b%l-g%l)==1?a:1<<30,y:b)).OrderBy(x=>x).First().y]*=n[g])n[g=n.IndexOf(n.Max(x=>Math.Sqrt(x)%1==0?x:0))]=(int)Math.Sqrt(n[g]);}

Try it online!

Wolfram Language (Mathematica), 224 bytes
(l=#;While[(c=Length)[m=Select[Join@@l,IntegerQ[Sqrt@#]&]]>0,t=##&@@#&@@SortBy[Select[(g=#&@@Position[l,f=Max@m])+#&/@{{1,0},{0,1},{-1,0},{0,-1}},Min@#>0&&Max@#<=c@l&],l[[##]]&@@#&];l[[##&@@g]]=(n=Sqrt@f);l[[t]]=l[[t]]n];l)&

Try it online!

JavaScript (Node.js), 157 bytes
a=>g=(l,m=n=i=j=0)=>a.map((o,k)=>m>o||o**.5%1||[m=o,i=k])|m&&a.map((o,k)=>n*n<o*n|((i/l|0)-(k/l|0))**2+(i%l-k%l)**2-1||[n=o,j=k])|[a[i]=m**=.5,a[j]=m*n]|g(l)

Try it online!
-14 bytes thanks the @Arnauld who also wrote a nice test harness :)
Anonymous function that takes a 1-dimensional array as input and a length parameter specifying number if columns/rows.
Curried input is specified as f(array)(length).
// a: 1-dimensional array of values
// g: recursive function that explodes once per recursive call
// l: number of columns, user specified
// m: max square value
// n: min neighbor
// i: index of max square
// j: index of min neighbor
a=>g=(l,m=n=i=j=0)=>
  // use .map() to iterate and find largest square
  a.map((o,k)=>
    // check size of element
    m>o||
    // check if element is a square
    o**.5%1||
    // new max square found, update local variables
    [m=o,i=k])|
  // after first .map() is complete, continue iff a square is found
  // run .map() again to find smallest neighbor
  m&&a.map((o,k)=>
    // check size of element
    n*n<o*n|
    // check relative position of element
    ((i/l|0)-(k/l|0))**2+(i%l-k%l)**2-1||
    // a new smallest neighbor found, update local variables
    [n=o,j=k])|
  // update matrix in-place, largest square is reduced,
  // smallest neighbor is increased
  [a[i]=m**=.5,a[j]=m*n]|
  // make recursive call to explode again
  g(l)

Java 8, 299 297 289 279 bytes
m->{for(int l=m.length,i,j,I,J,d,M,t,x,y;;m[x][y]*=d){for(i=l*l,I=J=d=0;i-->0;)d=Math.sqrt(t=m[i/l][i%l])%1==0&t>d*d?(int)Math.sqrt(m[I=i/l][J=i%l]):d;if(d<1)break;for(M=-1>>>1,m[x=I][y=J]=d,t=4;t-->0;)try{M=m[i=I+t/2-t/3*2][j=t<1?J-1:1/t+J]<M?m[x=i][y=j]:M;}finally{continue;}}}

-18 bytes thanks to @ceilingcat.
Modifies the input-matrix instead of returning a new one to save bytes.
Try it online.
Explanation:
m->{                          // Method with integer-matrix input and no return-type
  for(int l=m.length,         //  Dimension-length `l` of the matrix
      i,j,I,J,d,M,t,x,y;      //  Temp integers
      ;                       //  Loop indefinitely:
       m[x][y]*=d){           //    After every iteration: multiply `x,y`'s value with `d`
    for(I=J=d=0,              //   (Re)set `I`, `J`, and `d` all to 0
        i=l*l;i-->0;)         //   Loop over all the cells:
      d=                      //    Set `d` to:
        Math.sqrt(t=m[i/l][i%l])%1==0?
                              //     If the current value is a perfect square
        *t>d*d?               //     And if it's larger than `d` squared:
          (int)Math.sqrt(m[I=i/l][J=i%l])
                              //      Set `I,J` to the current coordinate
                              //      And `d` to the square-root of the current value
        :d;                   //     Else: leave `d` the same
    if(d<1)                   //   If `d` is still 0 after the nested loop
                              //   (which means there are no more square-numbers)
      break;                  //    Stop the infinite loop
    for(M=-1>>>1,             //   (Re)set `M` to Integer.MAX_VALUE
        m[x=I][y=J]=d,        //   Replace the value at `I,J` with `d`
        t=4;t-->0;)           //   Loop `t` in the range (4, 0]:
      try{M=                  //    Set `M` to:
            m[i=I+t/2-t/3*2]  //     If `t` is 3:
                              //      Go to the row above
                              //     Else-if `t` is 2:
                              //      Go to the row below
                              //     Else (`t` is 0 or 1):
                              //      Stay in the current row
                              //     (and save this row in `i`)
             [j=t<1?J-1:1/t+J]//     If `t` is 0:
                              //      Go to the column left
                              //     Else-if `t` is 1:
                              //      Go to the column right
                              //     Else (`t` is 2 or 3):
                              //      Stay in the current column
                              //     (and save this column in `j`)
             <M?              //     And if the value in this cell is smaller than `M`:
                m[x=i][y=j]   //      Set `x,y` to `i,j`
                              //      And `M` to the current value in `i,j`
               :M;            //     Else: leave `M` the same
      }finally{continue;}}}   //    Catch and ignore IndexOutOfBoundsExceptions

JavaScript (Node.js), 141 bytes
f=(a,I,J,r)=>a.map((x,i)=>x.map((y,j)=>(1+J?(i-I)**2+(j-J)**2-1|r<y:y**.5%1||r>y)||(P=i,Q=j,r=y)))|1+J?f(a,a[P][Q]*=a[I][J]**=.5):r&&f(a,P,Q)

Try it online!
Take input 2D array