text:
ASCII Pizza (no pineapple)
I like pizza!
Task
Given the radius of a pizza and a list of ingredients, create the corresponding ascii pizza!
Example size 4 pizza with mozzarella cheese, olives and ham:
  #####
 #@@@@M#
#H@O@@@@#
#M@@@H@@#
#@OO@@@@#
#@@H@@@@#
#M@M@@@@#
 #O@@@H#
  #####

Input
A positive integer r for the size of the pizza and a (possibly empty) list of ingredients (non-empty strings). The list of ingredients can be given in a series of convenient formats, including but not limited to:

a list of ingredients, such as ["tomato", "ham", "cheese"];
a list of the initials, such as ["t", "h", "c"];
a list of left- or right-padded ingredients, such as ["tomato", "ham   ", "cheese"] or ["tomato", "   ham", "cheese"];
a string with the initials, such as "thc".

Output specs
The pizza is built on a square of size 2r+1 characters, with the centre character having coordinates (0,0) for the purposes of this explanation. All characters in the square have integer coordinates. Then,

a position is crust # if its coordinates x,y satisfy \$r+1 > \sqrt{x^2 + y^2} \geq r\$;
a position is dough @ if its coordinates x,y satisfy \$ r > \sqrt{x^2+y^2}\$.

Then, the ingredients must be put randomly on the pizza. Each ingredient will be represented by its initial and you must place r of each ingredient randomly in the dough characters. You can assume there will be enough space in the pizza. Ingredients cannot be placed on top of eachother, so in the final pizza there must be exactly rl non-dough symbols, in groups of r, if the ingredients list has size l.
For the randomness in the distributions of ingredients on top of the pizza, it suffices that for a fixed r and ingredient list, all ingredient distributions obeying the specs have non-zero probability of occurring.
Examples
r = 1, no ingredients
###
#@#
###

r = 2, no ingredients
#####
#@@@#
#@@@#
#@@@#
#####

r = 5, no ingredients
  #######
 ##@@@@@##
##@@@@@@@##
#@@@@@@@@@#
#@@@@@@@@@#
#@@@@@@@@@#
#@@@@@@@@@#
#@@@@@@@@@#
##@@@@@@@##
 ##@@@@@##
  #######

r = 4, ingredients = ["bacon", "mozzarela", "tomato"]
  #####
 #@@b@m#
#@@@@@b@#
#@@@btb@#
#@@@@@@t#
#@@@@@@@#
#@mt@@@@#
 #t@mm@#
  #####

Reference implementation
Please include one or two of your favourite pizzas in your answer :)

This is code-golf so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it... And happy golfing!

(Off topic.) Pizza Hut is serving square pizzas ... but not as small as the cases 1 and 2 in the challenge.

@a'_' that sounds interesting!

Are you trying to out-pizza the hut?!?

I like pasta - I'll wait for your tagliatelle challenge :)

Bonus if your program is spaghetti code

@GalenIvanov still cooking that one

My favorite pizza is spam egg sausage and spam, 'cause that's not got much spam in it.

Related

How flexible is the input format? An answer for example seems to take a sigle string with the initials. Is that allowed? How about a space-right-padded char matrix like this (note the right-padding in each row)?

@LuisMendo I would say that is still fairly acceptable.

@RGS Which of the two options? Or both? Perhaps edit that into the challenge text, so it's clear to everyone

@LuisMendo both; I edited the challenge, hope it is more clear now.

@RGS Thanks. Using the initials may be an important simplification for some answers. Perhaps you should notifiy them?

@LuisMendo done as suggested! Thanks for your feedback.

APL (Dyalog Extended), 55 53 bytesSBCS
−2 thanks to rabbitgrowth.
Anonymous infix lambda. Takes r as left argument (⍺) and ingredient initials as right argument (⍵).
{i@((≢i←⍺/⍵)?≢⍸1=n)@{1=n}'@# '[n←(0⍺,⍺+1)⍸|∘.⌾⍨⍺…-⍺]}

[Try it online!][TIO-k6q7nk2n]
{…} "dfn"; left argument ⍺ (leftmost Greek letter), right argument ⍵ (rightmost Greek letter)
'@# '[…] index the string with:
  -⍺ negate r
  ⍺… generate integer range from r to -r
  ∘.⌾⍨ generate table of complex coordinates
  | magnitudes
  (…)⍸ find the ɩndices of the [a,b) ɩntervals in which the magnitudes fall:
   ⍺+1 increment r
   0⍺, prepend [0,r]
   n← store in n (1: dough; 2: crust; 3: outside pizza)
 i@(…)@{1=n} place the characters of i (to be defined) at the following subset of positions at which n is 1 (i.e. we have dough):
  1=n mask where n is 1
  ⍸ ɩndices of trues
  ≢ count them
  (…)? pick the following number of random indices from 1 to that:
   ⍺/⍵ replicate each ingredient initial letter to r copies
   i← store in i
   ≢ tally that

Please include one or two of your favourite pizzas in your answer :) ~ What's your favourite pizza @Adám?

@Lyxal I did. See the TIO link!

Nice! +1 for good choice of pizza! :P

Really nice job :D +1 for your work here! I'm just a bit sad you put pineapple in your pizza... But that is a matter of taste

@RGS Thank you. The pineapple is a pun on Py'n'APL.

@Adám ah wow, wouldn't get there alone!

Adám, I have edited the question to make input specs a bit more clear and a bit more loose. Maybe you can save some characters if the ingredient list is, say, a list of initials? Maybe check the clearer input specs. Sorry for the trouble!

What is the ⍤1 for? I tried removing it and the code still appears to run correctly.

@rabbitgrowth It was supposed to pair up the entire vector left argument with each row of the matrix right argument, but that's automatic. Thanks!

@Adám I see, thanks! You might want to remove the ⍤1 in the code you posted here as well.

@rabbitgrowth Oops.

MATL, 44 43 40 34 bytes
Q_Zvqt!YytGQ<Zc64bG<(i1GY"7MfynZr(

Inputs are: r and a string with the initials of ingredients.
Try it online with ham, onion, pepper and mushroom! Or maybe try a diet pizza.
Explanation with example
Consider inputs 3 and 'AP'.
Q     % Implicit input: r. Add 1
      % STACK: 4
_Zv   % Symmetric inverse range
      % STACK: [4 3 2 1 2 3 4]
q     % Subtract 1, element-wise
      % STACK: [3 2 1 0 1 2 3]
t!    % Duplicate, transpose
      % STACK: [3 2 1 0 1 2 3], [3; 2; 1; 0; 1; 2; 3]
Yy    % Hypotenuse, element-wise with broadcast
      % STACK: [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6056;
                3.1623    2.2361    1.4142    1.0000    1.4142    2.2361    3.1623;
                3.0000    2.0000    1.0000         0    1.0000    2.0000    3.0000;
                3.1623    2.2361    1.4142    1.0000    1.4142    2.2361    3.1623;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6056;
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426]
t     % Duplicate.
      % STACK: [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426],
               [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426]
GQ<   % Less than r plus 1? Element-wise
      % STACK: [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426],
               [0 1 1 1 1 1 0;
                1 1 1 1 1 1 1;
                1 1 1 1 1 1 1;
                1 1 1 1 1 1 1;
                1 1 1 1 1 1 1;
                1 1 1 1 1 1 1;
                0 1 1 1 1 1 0]
Zc    % Replace 0 by space and 1 by '#'
      % STACK: [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426],
               [' ##### ';
                '#######';
                '#######';
                '#######';
                '#######';
                '#######';
                ' ##### ' ]
64    % Push 64 (ASCII for '@')
      % STACK: [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426],
               [' ##### ';
                '#######';
                '#######';
                '#######';
                '#######';
                '#######';
                ' ##### ' ],
               64
b     % Bubble up
      % STACK: [' ##### ';
                '#######';
                '#######';
                '#######';
                '#######';
                '#######';
                ' ##### ' ],
               64,
               [4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426;
                3.6056    2.8284    2.2361    2.0000    2.2361    2.8284    3.6065;
                                                ···
                4.2426    3.6056    3.1623    3.0000    3.1623    3.6056    4.2426]
G<    % Less than r? Element-wise
      % STACK: [' ##### ';
                '#######';
                '#######';
                '#######';
                '#######';
                '#######';
                ' ##### ' ],
               64,
               [0 0 0 0 0 0 0;
                0 1 1 1 1 1 0;
                0 1 1 1 1 1 0;
                0 1 1 1 1 1 0;
                0 1 1 1 1 1 0;
                0 1 1 1 1 1 0;
                0 0 0 0 0 0 0]
(     % Write value 64 (that is, '@') into char matrix at positions indexed by mask
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### ']
i     % Input: string
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### '],
               'AP'
1GY"  % Push first input (r) again. Repeat each letter that many times
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### '],
               'AAAPPP'
7Mf   % Push 0-1 mask again. Linear index (column-major order) of non-zero entries
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### '],
               'AP',
               [9; 10; 11; ...; 41]
yn    % Duplicate from below. Number of elements
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### '],
               'AAAPPP',
               [9; 10; 11; ...; 41]
               6
Zr    % Random sample without replacement (example result shown)
      % STACK: [' ##### ';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                '#@@@@@#';
                ' ##### '],
               'AAAPPP',
               [13; 18; 11; 24; 30; 25]
(     % Write 'AAAPPP' into char matrix at positions given by the linear indices
      % STACK: [' ##### '
                '#@@@P@#';
                '#@@P@@#';
                '#AAP@@#';
                '#@@@@@#';
                '#A@@@@#';
                ' ##### ']
      % Implicit display

+1 for crossed out 44 still being 44

I like your diet pizza! Would +1 but really can't do it twice :'(

05AB1E, 42 41 40 38 34 bytes
ÝRûãnOtï¹.S…# 1sèƶDþ.rI¹и'@Þ«‡¹·>ô

Output as a character-matrix.
-2 bytes because the specs changed (character-list input instead of ingredients-list).
-4 bytes thanks to @Grimmy.
Try it online or verify all test cases. (The footer J» is to pretty-print the result. Feel free to remove it to see the actual character-matrix result.)
Explanation:
Ý              # Push a list in the range [0, (implicit) input-integer]
 R             # Reverse it to range [input, 0]
  û            # Palindromize this list (i.e. [3,2,1,0] → [3,2,1,0,1,2,3])
   ã           # Take the cartesian product with itself, to get a list of all coordinates
n              # Square both the x and y of each coordinate
 O             # Take the sum of each
  t            # And then the square-root of that
   ï           # Truncate it to an integer
    ¹.S        # And compare each to the first input
               # (-1 if larger than the input; 0 if equals; -1 if smaller)
       …# 1    # Push string "# 1"
           sè  # And index the list into this string, where the -1 is the trailing character
ƶ              # Multiply the 1s by their 1-based index
 Dþ            # Duplicate the list, and only leave the integers (the indices)
   .r          # And randomly shuffle those
     I         # Push the second input-list of ingredient-characters
      ¹и       # Repeat this list the first input amount of times
        '@Þ   '# Push an infinite list of "@"
           «   # Append it to the repeated ingredient-characters
            ‡  # Transliterate the shuffled indices to this list
¹·<            # Push the first input again; double it; and decrease it by 1
               # (alternative: `Dgt` - Duplicate; length; square-root)
   ô           # Split the list into parts of that size
               # (after which the resulting character-matrix is output implicitly)

+1 really nice submission, even though you put pineapple in your pizza!

@RGS I knew someone would comment about the pineapple. xD I know loads of people think Pizza Hawaii shouldn't exist, but I personally like it. ;p Although Pizza Funghi (Mushrooms) without the pineapple is fine as well.

pineapple doesn't belong on pizza :(

Kevin, I have edited the question to make input specs a bit more clear and a bit more loose. Maybe you can save some characters if the ingredient list is, say, a list of initials? Maybe check the clearer input specs. Sorry for the trouble!

Seems like you're off by one. For r=2, you output the pizza specified for r=1, and so on.

-4 bytes with better radius code (and -2 by dropping €н since that's now allowed). Your ingredient code is better than what I had. If only we had Jelly's ẹ (all indices of b in a), that would save 5 bytes for my approach.

@Grimmy Thanks! And yeah, I miss the "all indices of b in a" in quite a lot of challenges tbh.

JavaScript (ES7),  177 175  172 bytes
Takes input as (r)(list), where list is filled with initials. Returns an array of characters.
r=>a=>a.map(i=>(g=i=>(s[p=Math.random()*r**3|0]!='@'||(s[p]=i,--n))&&g(i))(i,n=R),s=[...(g=x=>y+r?` #@
`[x+r?((d=x*x--+y*y)<r*r)+(d<R*R):(--y,x=R,3)]+g(x):'')(y=R=r++)])&&s

Try it online!
Commented
r => a =>                     // r = radius, a[] = list of ingredients
  a.map(i =>                  // for each ingredient i in a[]:
    ( g = i => (              //   g is a recursive function taking i
        s[                    //     test s at
          p = Math.random()   //     a random position p in [0 .. r**3 - 1]
              * r**3 | 0      //
        ] != '@' ||           //     abort if it doesn't contain '@'
        (s[p] = i, --n)       //     otherwise, put the ingredient there and decrement n
      ) && g(i)               //     do a recursive call if the above result is truthy
    )(i, n = R),              //   initial call to g with i and n = R
    s = [...                  //   build the base pizza s[]
      ( g = x =>              //   g is another recursive function taking x
        y + r ?               //     if y is not equal to -r:
          ` #@\n`[            //       pick the relevant character:
            x + r ?           //         if x is not equal to -r:
              (               //
                (d = x * x--  //           d = x² + y²; decrement x
                   + y * y)   //
                < r * r       //           add 1 if it's less than r² (-> '#')
              ) +             //
              (d < R * R)     //           add 1 if it's less than R² (-> '@')
            :                 //         else:
              (y--, x = R, 3) //           decrement y, set x = R, append a linefeed
          ] +                 //
          g(x)                //       recursive call
        :                     //     else:
          ''                  //       stop recursion
      )(y = R = r++)          //   initial call to g with x = y = R = r; increment r
    ]                         //
  ) && s                      // end of map(); return s[]

Nice job on compressing all the maths you needed!! +1

Arnauld, I have edited the question to make input specs a bit more clear and a bit more loose. Maybe you can save some characters if the ingredient list is, say, a list of initials? Maybe check the clearer input specs. Sorry for the trouble!

Python 3.8 (pre-release), 186 177 176 bytes
from random import*
def f(r,i=[],s=''):i=['@',*next(zip(*i),[])];t=range(-r,R:=r+1);print([s:=s+[' #'[(d:=x*x+y*y)<R*R],choice(i)][d<r*r]+'\n'*(x==r)for y in t for x in t][-1])

Try it online!

Looking nice! +1 for you cool submission

I just have one problem, you seem to be crowding your pizza with ingredients! Each ingredient should show up r times :)

Gábor, I have edited the question to make input specs a bit more clear and a bit more loose. Maybe you can save some characters if the ingredient list is, say, a list of initials? Maybe check the clearer input specs. Sorry for the trouble!

You are right, it actually works with just a string or padded strings even but I'm still working on the number of ingredients to put on the pizza (I like a lot of toppings for now :) )

Ok, ping me when you have the number of toppings fixed! :D

Charcoal, 51 48 bytes
Ｅ⊕θ⭆Ｅ⊕θ₂⁺×ιι×λλ⎇›θλ@§ #›⊕θλ‖Ｏ↑←ＦηＦθ§≔ＫＡ‽⌕ＡＫＡ@§ι⁰

Try it online! Link is to verbose version of code. Now supports full topping names by using a less convenient input format, but could save 2 bytes by switching back to initials. Explanation:
Ｅ⊕θ⭆Ｅ⊕θ₂⁺×ιι×λλ⎇›θλ@§ #›⊕θλ

Draw the bottom right hand quarter of the pizza base.
‖Ｏ↑←

Reflect to complete the pizza base.
ＦηＦθ

Loop through each topping repeatedly.
§≔ＫＡ‽⌕ＡＫＡ@§ι⁰

Find a random dough character and overwrite it with the first letter of the topping.

Cool submission! +1 The bit about drawing the bottom right quarter of the pizza looks really long, in comparison to the topic placement, for e.g. I thought charcoal would be shorter here! :O

@RGS I don't have a Euclidean distance primitive, and SquareRoot(Sum(Power([i, l], 2))) still takes 8 bytes.

ah I understand, that helps explaining it

Neil, I have edited the question to make input specs a bit more clear and a bit more loose. Maybe you can save some characters if the ingredient list is, say, a list of initials? Maybe check the clearer input specs. Sorry for the trouble!

@RGS Actually I think it was my original mistake of using a list of initials that triggered the discussion. I did this because Charcoal doesn't have a convenient list input format. As it happens, if I use the inconvenient list input format, that saves me 2 bytes, which I can then spend on full ingredient names. (Or I could just use the inconvenient format with initials, and just claim the 2 byte saving...)

Perl 5 -al, 153 bytes
@;=map{//;join"",map{($d=sqrt($_**2+$'**2))<$r?++$n&&1:$d>$r+1?$":"#"}@c}@c=-($r=<>)..$r;@F=((@F)x$r,("@")x($n-@F*$r));say s/1/splice@F,rand@F,1/gre for@

Try it online!
Takes the initials of the ingredients (space separated) on the first line of input and the radius on the second.


text:
String permutations
Print the biggest-size subset of strings in the input that are all permutations of each other. If there are ties, any one will do. If no strings are permutations of each other (for example, only one string was given or the strings contain distinct characters), this is just one of the strings. If no strings were passed in , do not output anything or output an empty list.
Test cases:
Input => Output
["ABCDE", "EDBCA", "XYZ", "ZYX", "ZXY"] => ["XYZ", "ZYX", "ZXY"]
["A"] => ["A"]

Is that an example of just input or are the outputs also in that same line? Can you include clear examples of expected output, with at least two test cases?

To make this a challenge suitable for CGCC is not enough to just translate the old Russian SO question.

This needs an objective winning criterion, such as "smallest number of bytes wins"

@close voters: please don’t close code-golf questions for not having an objective primary winning criterion. If it’s code-golf, the winning criterion is “fewest bytes of source code wins”.

I've voted to reopen, presuming that the only problem was that the winning criterion was inadvertently omitted -- although it's clear because of the code-golf tag.  (If there's some other issue, please post it, of course.)

I think a lot of the confusion about the spec came was due to a literal translation from Russian using terms that don't mean the same thing in a technical sense. I tried to edit to clarify a bit.

Are the characters in each string guaranteed to be distinct or can there be duplicates?

05AB1E, 6 bytes
.¡{}éθ

Try it online!
.¡ }      # group the input strings by:
  {       #  sort (all permutations of each other will be identical when sorted)
    é     # sort the groups by length
     θ    # output the last (longest) group

T-SQL, 267 bytes
SQL queries was totally made to solve this type of question
SELECT top 1WITH TIES x FROM(SELECT(SELECT a FROM(SELECT
top 999substring(x,number+1,1)a,*FROM
@,spt_values WHERE type='P'and number<len(x)ORDER BY a)c
WHERE x=t.x for xml path(''),type).value('.','char(9)')v,x FROM @ t)z
ORDER BY-count(*)over(PARTITION BY v),-len(x)

Try it online

What the fuck I'm actually intimidated now

Japt -h, 6 5 bytes
üñ ñl

Try it
üñ ñl     :Implicit input of array
ü         :Sort & group by
 ñ        :  Sorted strings
   ñ      :Sort by
    l     :  Length
          :Implicit output of last element

Perl 6, 36 bytes
{max .classify(~*.comb.sort){*}||''}

Try it online!
Output an empty string for an empty input. If we could output something else, for example -Inf, then this could be:
Perl 6, 31 bytes
*.classify(~*.comb.sort){*}.max

Try it online!

Python 2, 79 77 bytes
lambda A,S=sorted:A and max([[y for y in A if S(x)==S(y)]for x in A],key=len)

Try it online!
2 bytes thx to wilkben.
The A and... is only required to deal with the empty input.

77 bytes

J, 19 bytes
0({>\:#&>)/:~&></.]

Try it online!
-2 bytes thanks to FrownyFrog
Similar approach to Grimmy's answer.

Bring { into the () and you don't need [:

Very nice, thank you @FrownyFrog

Clojure, 54 bytes
#(some val(sort-by(comp count val)>(group-by sort %)))

Returns nil for empty input.
Try it online!

source: Stack Exchange

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

sort: votes


text:
Egg, sausage, bacon and spam (lovely spam!)
You are given four integers: \$e,s,b\in\{0,1\}\$ and \$S\in \{0,1,2,4\}\$, where \$e,s,b,S\$ stand for egg, sausage, bacon and spam respectively.
Your task is to figure out whether the corresponding ingredients match a valid entry in the following menu:
 [e]gg | [s]ausage | [b]acon | [S]pam
-------+-----------+---------+--------
   1   |     0     |    1    |   0
   1   |     1     |    1    |   0
   1   |     0     |    0    |   1
   1   |     0     |    1    |   1
   1   |     1     |    1    |   1
   0   |     1     |    1    |   2
   1   |     0     |    1    |   4
   1   |     0     |    0    |   4
   1   |     1     |    0    |   2

This is a subset of the menu described in the famous Monty Python's sketch, where dishes based on other ingredients are omitted.
Rules

You can take \$(e,s,b,S)\$ in any order and any convenient format as long as they are clearly separated into 4 distinct values as described above (e.g. claiming that your code takes a single bitmask with all values packed in there is not allowed).
Examples: [1,0,1,4], "1014", or 4 distinct arguments
Each value is guaranteed to be valid (i.e. you don't have to support \$e=2\$ or \$S=3\$).
You may return (or print) either:

a truthy value for matching and a falsy value for not-matching
a falsy value for matching and a truthy value for not-matching
2 distinct, consistent values of your choice (please specify them in your answer)

This is code-golf

Test cases (all of them)
Format: [e, s, b, S] --> matching
[ 0, 0, 0, 0 ] --> false
[ 0, 0, 0, 1 ] --> false
[ 0, 0, 0, 2 ] --> false
[ 0, 0, 0, 4 ] --> false
[ 0, 0, 1, 0 ] --> false
[ 0, 0, 1, 1 ] --> false
[ 0, 0, 1, 2 ] --> false
[ 0, 0, 1, 4 ] --> false
[ 0, 1, 0, 0 ] --> false
[ 0, 1, 0, 1 ] --> false
[ 0, 1, 0, 2 ] --> false
[ 0, 1, 0, 4 ] --> false
[ 0, 1, 1, 0 ] --> false
[ 0, 1, 1, 1 ] --> false
[ 0, 1, 1, 2 ] --> true
[ 0, 1, 1, 4 ] --> false
[ 1, 0, 0, 0 ] --> false
[ 1, 0, 0, 1 ] --> true
[ 1, 0, 0, 2 ] --> false
[ 1, 0, 0, 4 ] --> true
[ 1, 0, 1, 0 ] --> true
[ 1, 0, 1, 1 ] --> true
[ 1, 0, 1, 2 ] --> false
[ 1, 0, 1, 4 ] --> true
[ 1, 1, 0, 0 ] --> false
[ 1, 1, 0, 1 ] --> false
[ 1, 1, 0, 2 ] --> true
[ 1, 1, 0, 4 ] --> false
[ 1, 1, 1, 0 ] --> true
[ 1, 1, 1, 1 ] --> true
[ 1, 1, 1, 2 ] --> false
[ 1, 1, 1, 4 ] --> false

Spam spam spam spam. Lovely spam! Wonderful spam!

Can we take input as a string like "4101", or does that fail the "clearly separated" rule?

@Grimmy I assume that it stands for "Sesb", which is fine.

The new title is much better

Bloody vikings...

May we take a decimal representation of the four values (e.g. [ 0, 1, 1, 2 ] as 112)?

@JonathanAllan I'd say no because that's not really 4 distinct values anymore (whereas a string is OK because it's made of 4 distinct characters).

Python, 32 bytes
"001111020114001410120110".count

Try it online!
Takes input in 'sbeS' order as a single string, like '1102'. Simply checks whether the string appears as a substring of the hardcoded string, using the object method to avoid needing to write out a costly lambda to define a function.
The desired strings are squished together as much as possible via overlapping. For example, the part "001111020114 checks for 0011, 0111, 1111, 1110, and 1102. The fact that 2 and 4 can only appear as the counts of spam, which is listed last, lets us append strings directly to their right without false positives. I played with the order of the inputs to try to overlap more, but there might be a better outcome.
I suspect this approach can be beaten with a modulo chain or similar using number inputs.

-1 Byte

How did you compute the overlaps? Did you do this by hand? :o

@wilkben A nice idea! Post an answer and collect your bounty!

@RGS Kind of. I wrote code to count and list the overlaps for each permutation. But I was too lazy to code up the graph algorithm to split them into paths, so I did a couple of the promising-looking ones by hand.

@xnor I added an answer but I'm unable to edit the post you linked to claim the bounty.

Correct suspicion about a modulo chain or similar - I found a 29.

I know the post is old, but I just wanted to mention that b"\0.....\0.....".hex().count works for 29. I do suspect switching up the order of the variables to eliminate the \0 and/or brute-forcing for a shorter overlap sequence can bring this down to at least 27.

Python 3, 31 bytes
oct(0x20a00924204c00c048).count

Try it online!
Based on @xnor's answer

Congrats! I've posted a bounty and will wait the week before awarding it to draw more visibility to your answer. And if you're interested in more, I have plenty of answers to be beaten.

Python 2,  29 28  25 bytes
-3 bytes thanks to dingledooper! (Suffixing a string as the hash input)
lambda s:hash(s+'?pB{')%3

An unnamed function accepting a string of digit characters, egg+bacon+spam+sausage (e.g. '0040') which yields a falsey value (0) if on the menu or a truthy value (1 or 2) if not.
Try it online!
This was found by dingledooper using this code (Try it online, limited to printables, which finds the above).

28 byter...
lambda*i:hash(i)/442%89%22%5

An unnamed function accepting four integers, sausage, bacon, spam, egg which yields a falsey value (0) if on the menu or a truthy value (1, 2, 3, or 4) if not.
Try it online!

Another 28:
lambda*i:hash(i)/8883%55%8-2

Try it here! (accepts egg, spam, bacon, sausage)

29 byters...
lambda*i:hash(i)/676%86%9%6-2

Try it here! (accepts egg, spam, sausage, bacon)
Or one which returns True if on the menu or False otherwise:
lambda*i:hash(i)/64%31%14%8<2

Try it here! (accepts spam, sausage, egg, bacon)

A nice idea and well-executed. I'm curious how you found these chains. I'll post your bounty after wilkben's, since I can only have one on this question.

I wonder, since the challenge allows input to be taken as a decimal number like 1102, whether this could be used for a mod chain on the number directly that saves on writing hash(). I expected because theses number are less well-distributed, they'll be harder separate with a mod chain, but it does give 6 more bytes to work with.

I found chains by reducing the two sets in nested for loops continue-ing on intersection, only showing progressively shorter or equal length code, along with the sets (I spotted a {0, 1} along the way to give the <2 solution). I'm not sure we can take an integer due to "as long as they are clearly separated into 4 distinct values" and that 0112 is not 112 in Python. If we could then one trick might be something like lambda n:a**n/b%c%d.

...the exponentiation trick might lead to much shorter solutions with the hash too but the numbers are too big to make a naive search possible - maybe there is some maths that could be used to aid us there?

(EDIT ^) $a^b\mod c=((a\mod c)^b)\mod c$ and $a^{d+e}=a^d\times a^e$ I guess...

If you input a string, you can obtain this 27-byte solution lambda s:hash(s+'gE.P')%3%2. The order is egg, bacon, sausage, spam.

@dingledooper I think you should post that find yourself! Happy to put it here if you don't want to though.

I've gotten it down to 25 bytes: lambda s:hash(s+'?pB{')%3. It returns a Falsey value if on the menu, as in your 28 (order is egg, bacon, spam, sausage). While I don't quite feel like posting, it would be nice to have this method included in your post. And if it interests you, here's the brute force program which found it.

Great stuff @dingledooper! I've added it to this post.

05AB1E, 11 bytes
•ʒº-ép•bsCè

Try it online!
Inputs as a string "Sesb". Outputs 0 for matching and 1 for non-matching.
•ʒº-ép•      # compressed integer 269454360636
       b     # convert to binary: 11111010111100101110110100000000111100
        sC   # convert the input from binary: 8S + 4e + 2s + b
             # (this doesn't error out on digits > 1)
          è  # use this value to index in the above bitstring

Really nice solution :D +1

I don't know 05AB1E at all, but from the description, it sounds like something like 1101 would match even though it's not on the menu. How does the solution prevent that?

@MichaelMior 1101 is on the menu. As explained in my answer, I take input as "Sesb", so 1101 stands for spam, eggs, and bacon, which is the fourth entry in the menu.

Whoops, my mistake :) Does this mean there aren't any substrings which are not on the menu which appear when the menu is given in this order?

@MichaelMior What do you mean by substrings? My answer doesn't have anything to do with substrings. Are you thinking of xnor's answer?

A port of xnor's answer would be 13 bytes.

x86-16 machine code, 30 bytes
D0 E3       SHL  BL, 1              ; e << 1
0A FB       OR   BH, BL             ; BH = e << 1 | s
D0 E7       SHL  BH, 1              ; es << 1
0A C7       OR   AL, BH             ; AL = e << 2 | s << 1 | b
D0 E0 03    SHL  AL, 3              ; AL =<< 3 (80186+ only)
0A C4       OR   AL, AH             ; AL = spam table value
B1 09       MOV  CL, 9              ; search 9 entries
BF 013B     MOV  DI, OFFSET SPAM    ; in SPAM table
F2/ AE      REPNZ SCASB             ; search table - ZF if found, NZ if not
C3          RET                     ; return to caller
SPAM        DB   28H, 38H, 21H, 29H, 39H, 1AH, 2CH, 24H, 32H    ; SPAM table

Input as BL = e, BH = s, AL = b, AH = S.  Output ZF if valid entry, NZ if not valid
Encodes the input values into a 6-bit binary value (00esbSSS), and compares against the table of known valid results.
Here's output from a little test program for PC DOS that takes input from command line:

Note: Due to the use of SHL AL, imm8, this won't work on an 8088-based PC/XT. It would be +1 byte to do MOV CL, 3 / SHL AL, CL.

PHP, 61 59 56 34 32 30 27 bytes
<?=74958>>33-$argn%95%34&1;

Try it online!
Each input (ordered esbS) is read as a decimal value and the modulus buckets them into a smaller range (i.e. a hashing function), which are then looked up in the "bit table" of the constant.
The hashing function has clashing values, but these all coincide when values are either truthy or falsy.

GolfScript, 24 bytes 21 bytes
This refinement of the solution is thanks to Grimmy, who took my formatting and used stronger stack manipulation to save a bunch of whitespace and variable assignment.
The following is the code (for the first time, newlines are necessary).
'\;*
>>
@^*

;>'n/\=~

Grimmy's solution at the bottom takes in a string of a list of arrays and applies the following operation to all of them, even though it's not strictly necessary. Golfscript can take input as a header, which is where my TIO references. Grimmy's is much cleaner to see all the outputs.
Input is a stack-dump of four elements: e, s, b, S
For the following explanation, I'm going to use N as a "newline" indicator so you can understand how this works in my formatting.
'\;*N>>N@^*NN;>'n/\=~ #Do as instructed
'              '      #String notation
'\;*N          '      #[Index 0] Pop s, then multiply e and b
'    >>N       '      #[Index 1] A trickier operation, will explain at bottom.
'       @^*N   '      #[Index 2] s*(e xor b)
'           N  '      #[Index 3] Can never be called.
'            ;>'      #[Index 4] Ensure e=1, s=0.
'              'n/    #Split the string on newlines (stack is e s b S "x/y/z")
                  \   #Swap the top two elements of the stack (e s b "x/y/z" S)
                   =  #Find the (top element)th element of (second element)
                    ~ #Then evaluate it.

So, why do these operations work?
m=0
 [e]gg | [s]ausage | [b]acon | spa[m]
-------+-----------+---------+--------
   1   |     0     |    1    |   0
   1   |     1     |    1    |   0
As long as e=1 and b=1, s can be anything. So if m=0, our output can be e*b

We do this in the program with {\;*}

This removes s from the array, then multiplies e and b together. If they're both 1, yay! If not, then we get a 0.

m=1

 [e]gg | [s]ausage | [b]acon | spa[m]
-------+-----------+---------+--------
   1   |     0     |    0    |   1
   1   |     0     |    1    |   1
   1   |     1     |    1    |   1

3/4 binary options. As long as we have e=1, and we DON'T have s=1, b=0, then we're good.
e*NOT(s*NOT(b))
or
e*(NOT(s) + b)

So, why does {>>} work?

It starts by checking that s>b. This should NEVER be true. So we have 0.
Then we check if e>0, which is true if e=1 and the above worked. If the above *didn't* work, then e>1 will never be true.

m=2
 [e]gg | [s]ausage | [b]acon | spa[m]
-------+-----------+---------+--------
   0   |     1     |    1    |   2
   1   |     1     |    0    |   2
As long as s=1, then we have an xor situation!
s*(e xor b)

{@^*} pulls the e to the top of the stack, then xors it with b.
Then the * multiplies that result with s.

m=4
 [e]gg | [s]ausage | [b]acon | spa[m]
-------+-----------+---------+--------
   1   |     0     |    0    |   4
   1   |     0     |    1    |   4
As long as e=1 and s=0, we don't care about b.
e*NOT(s)

We just do this with {;>}, which removes b from the equations, and makes sure e>s, which can only be the case is e is 1 and s is 0.

There we go! With brainpower combined, feast your eyes upon this beautiful creation!
Try the 21-byter online!
Try the old 24-byter online!
Try all examples online on the old solution (26 bytes)! (Courtesy Grimmy)

It's funny because I thought about doing it in this way, and I thought about the string-array-splicing thing, but for some reason I never thought about doing both! I'll edit that in :)

Down to 23 bytes.

21 bytes by using header-input. This is a very clever solution! using line-break comma-notation. I do try to avoid using newlines in Golfscript as a rule since it messes with my explanation block, but I can probably find an equivalent.

What IO rule allows Golfscript to take hard coded input? I'm pretty sure there isn't one

@JoKing There is.

@Grimmy I don't think this is a function though? I'm not that familiar with Golfscript, but given that the only thing in the header is the input, and the code doesn't seem to be called from the footer, it looks just like a snippet that relies on the input being on the stack

The entire program is a single-execution function. It gets called automatically on program compilation and execution. The top comment on that post literally says
"+1, this is the de facto standard for CJam and GolfScript"
All that the "input" tab on TIO does is stick it on the stack anyways, as a string. Golfscript doesn't "take in parameters", so this is how it's done.

Python, 49 44 bytes
lambda S,e,s,b:269454360636>>8*S+4*e+2*s+b&1

You can verify all test cases. Outputs 0 for a valid recipe and 1 otherwise.
Hats off to @Arnauld for shaving me 5 bytes :)
Borrows Grimmy's approach so be sure to upvote that one as well!

@Arnauld really nice, this essentially slices the end of the binary repr of this integer and then gets the least significant bit with &1. Right?

Yes, that's correct.

I've ended with the same answer as you! Mine does the opposite: 1 for valid and 0 otherwise. :-)

Python 3, 52 \$\cdots\$ 48 44 bytes
lambda e,s,b,S:206163194016>>8*S+e*4+s*2+b&1

Try it online!
Ouputs Truthy for true and Falsy otherwise.

Nice golfing going here!!

@RGS Great minds think alike! :D

Jelly, 13 11 bytes
“BƑṗ©N’Bị@Ḅ

You can try all the test cases!
Thank you, @Nick, for saving me 2 bytes. I'm currently tied with the shortest 05AB1E answer :)

Here’s your 11. You could also have moved the first link in place of the ¢ and put a ¤ for 12 bytes.

@NickKennedy thanks for the tip! I see you have encoded a different integer. How did you get it?

I converted to binary with B left rotated the binary digits 1 place with ṙ1 converted back from binary with Ḅ and then converted to a base-250 integer with ḃØ⁵ịOJ.

C (clang), 49 bytes
f(e,s,b,S){return 206163194016>>8*S+e*4+s*2+b&1;}

Try it online!
Ouputs 1 for true and O otherwise.

Ruby, 51 41 36 bytes
->*x{"J36:;>'-."[""<<x.join.oct%77]}

Try it online!
Returns nil (falsy) or a string (truthy).

Japt, 17 bytes
"~ "øUn5 d

Try it
"~ "øUn5 d     Program taking U, the string in "esbS" form
"~ "           String with values 130,155,126,131,156,32,134,129,152
              ø          Does it contain
               Un5       The input converted from Base-5 string to a number
                   d     And converted to a char?

Looks like some special characters are missing from your code.

@Grimmy the unprintable characters don't show up

Then please give an explanation of your code, since it's illegible otherwise.

@Mathgeek Just did

Does Japt's code page really include various unprintable characters or are you using a different one?

@JoKing Japt uses Latin-1, so 0x00 - 0x1F and 0x7F - 0x9F are all unprintables

APL+WIN, 23 bytes
×+/'é¢~â£ ≠ü⌹'=⎕av[5⊥⎕]

Index origin = 0
Prompts for a vector 4 integers and returns 1 for true zero for false.
Explanation:
Converts input vector from base 5 to an integer used to index into APL+WIN's atomic character vector (extended ASCII) and checks if it is in the menu which has similarly been converted to characters.

05AB1E, 18 bytes
•ÿŸ»¢•bŽ9“«S4äøJIå

Input as a concatenated string of \$e||s||b||S\$. If this is not allowed, a single byte has to be added for an explicit Join.
Pretty straight-forward approach, so will golf it down from here.
Try it online or verify all test cases.
Explanation:
•ÿŸ»¢•              # Push compressed integer 4221990791
      b             # Convert it to binary: 11111011101001100111011110000111
       Ž9“          # Push compressed integer 2442
          «         # Merge them together: 111110111010011001110111100001112442
           S        # Convert it to a list of digits
            4ä      # Split it into 4 equal-sized parts
              ø     # Zip/transpose; swapping rows and columns, to create quartets
               J    # Join those together
                Iå  # And check if the input-string is in this list
                    # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •ÿŸ»¢• is 4221990791 and Ž9“ is 2442.

Charcoal, 15 bytes
№%')-/36AE§γ↨θ²

Try it online! Link is to verbose version of code. Takes input ingredients as a list in reverse order and outputs a Charcoal boolean i.e. - for matching and nothing for non-matching. Explanation:
             θ  Input list
            ↨ ² Convert from "base 2"
          §γ    Index into printable ASCII
№%')-/36AE      Is the result contained in the given literal?
                Implicitly print.

One of my rare answers that don't use any characters with unusual widths meaning that the explanation lines up nicely for once.

cQuents, 38 bytes
?112,1001,Z+3,Z+6,Z+1,Z+3,1102,Z+8,Z+1

Try it online!
Builds a list of all of the possible inputs (in integer form) and returns True if they are in the list.

Excel, 67 bytes
=CHOOSE(D1+1,A1*C1,AND(A1,B1<=C1),AND(B1,A1+C1=1),,AND(A1,NOT(B1)))

Follows similar logic to that used by @Mathgeek

Jelly, 9 bytes
“ṚE⁾’,3ḥỊ

A monadic Link accepting a list of integers, [egg, sausage, bacon, spam], which yields a truthy value (1) if on the menu or a falsey value (0) if not.
Try it online! Or see the test-suite.
There may well be an 8 or 7 out there using a similar method, it's just a mater of finding them!
How?
“ṚE⁾’,3ḥỊ - Link: list of integers
“ṚE⁾’     - base 250 number = 11455143
      3   - three
     ,    - pair = [11455143, 3]
       ḥ  - Jelly's hash: use 11455143 as a salt and [1,2,3] as a domain
        Ị - insignificant? (effectively "equals one?")

Another 9 which takes [egg, sausage, bacon, spam] and yields 2 when on-menu or 1 when not:
“Ḋẏƭ¢’,2ḥ

RUST, 98 Bytes
fn f(e:u8,s:u8,b:u8,x:u8)->bool{match x|s<<3|e<<4|b<<5{17|20|26|42|48|49|52|56|57=>true,_=>false}}

Try it here

JavaScript (V8), 35 34 30 bytes
(e,s,b,S)=>s<S?5/S-s&e+b*s:e&b

Try it online!
I wrote a random expression generator and left it running for a few hours to generate the expression following the =>. In this answer I am only posting unedited outputs from the generator.

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


text:
Finding Radical Ideals
Sandbox
Finding radicals of arbitrary ideals in rings is hard! However, it's a doable task in polynomial rings, since they are Noetherian (all ideals are finitely generated)
Background
A quick introduction to radical ideals
A ring is a set, paired with two binary operations + and * such that 0 is a additive identity, 1 is a multiplicative identity, addition is commutative, every element has an additive inverse, and multiplication distributes over addition. For a more proper introduction, see Wikipedia. In this challenge, we'll be dealing with rings of polynomials over the complex numbers (for example, C[x,y,z]), so multiplication will also be commutative.
An ideal is a non-empty set closed under addition that contains additive inverses for all elements, and such that for any r in the ring and i in the ideal, r*i is in the ideal.
Given some polynomials p1,...,pn, the ideal generated by the polynomials is the set of all polynomials p such that there exists polynomials q1,...,qn such that p = p1q1+p2q2+...+pnqn.
In other words, the ideal generated by a set of polynomials is the smallest ideal containing the set.
Given ideal I of R, the radical ideal of I, or root I, √I, is the ideal of elements r in R such that there is some natural n, r^n is in I.
code-golf challenge:
Given an ideal generated by polynomials in any number of variables in the complex numbers, you need to return a set of polynomials that generate the radical ideal.
Important Notes:

While the polynomials all will belong to the space of complex coefficients, I'll only give you inputs of polynomials with integer coefficients.

Variables will always be single letters.

The output must be algebraically independent (there is no non-zero linear combination of the polynomials that sums to 0). The input will be algebraically independent.

Obviously, the output is non-unique.

Hints
A less algebraic way of thinking about radical ideals is: given that the input polynomials all evaluate to 0, what is the set of all polynomials we know that evaluate to 0. That set is the radical ideal.
Another nice characterization of the radical ideal is the intersection of all prime ideals containing the original generators.
There are no good known ways to find radicals in infinite fields, like the complex numbers. However, there are several algorithms that have reasonable average case times (many of which are listed here)
Singular has all of these algorithms implemented, if you want to experiment before building your own.
Of course, this is code golf, so inefficient solutions are permitted.
Input/Output
I/O should be pretty flexible. Possible forms of input/output:
Ideal: (x^2y-z^3, 2xy^2-2w^3, xy-zw)

I/O 0: "x^2y-z^3, 2xy^2-2w^3, xy-zw"

I/O 1: "x2y-z3,2xy2-2w3,xy-zw"

I/O 2: ["x2y-z3","2xy2-2w3","xy-zw"]

I/O 3: [[[1,2,1,0,0],[-1,0,0,3,0]],[[2,1,2,0,0],[-2,0,0,0,3]],[[1,1,1,0,0],[-1,0,0,1,1]]]

If there's some other more convenient I/O, let me know.
Test Cases
As I said earlier, these are not the only valid outputs for these inputs.

x^3 → x

2x^4y^2z^3 → xyz

xy-z^2, x-y, y-z+1 → x-y, x+z

x^2, xz^2-x, y-z → x, y-z

y^2+z, yz → y, z

x^2+y^2-1, w^2+z^2-1, xw+yz, xz-yw-1 → y+w, x-z, y^2+z^2-1

xy, (x-y)z → xy, yz, xz

xy, x-yz → x, yz

x^2y-z^3, 2xy^2-2w^3, xy-zw → z^2-xw, yz-w^2, xy-zw

Explained Examples
Upon request in the comments, I'll work a few examples out:

Example 1: 2x^4y^2z^3 → xyz

Note that (xyz)^4 = x^4y^4z^4, while 0.5y^2z(2x^4y^2z^3)=x^4y^4z^4, so this tells us that xyz is in the radical of 2x^4y^2z^3. Now, consider some polynomial p with a term that doesn't have x as a factor. Then, p^n will also have such a term, so it can't be in the ideal generated by 2x^4y^2z^3. So, every polynomial in the radical ideal has x as a divisor, and by symmetry, has y and z as divisors, so has xyz as a divisor.

Example 2: x^2, xz^2-x, y-z → x, y-z

Note that x^2 is in the ideal, so x is in the radical ideal. So, x*(z^2-1)=xz^2-x will be in the radical ideal since it is a multiple of x. Clearly, x and y-z are independent, and since they are terms of degree 1, they generate the radical ideal.

@Downvoter any suggestions?

Some of your test cases seem dubious. For example, how is $x$ in the radical of the ideal generated by $40xy+40x+40y$?

@ChristianSievers You are right, that one is incorrect. It's listed in my textbook, that's kinda funny. I checked the rest on Singular as well, but the rest work.

I'm not very used to it, so it is hard to see for me when there is more than one generator, but is $x$ really in the radical of $\langle xy,x-yz\rangle$ ?

@ChristianSievers If x isn't 0, then y is 0, implying that x-0*z=0

Okay, I see it now: $x^2=x(x-yz)+z(xy)$. So if you checked with Singular, I guess it's fine. Maybe some more simple examples would be helpful, like input $xy^2$.

I'll add some simpler cases in a bit.

@ChristianSievers I added a few more cases. What do you think now?

Enough test cases, but I guess people would like some explained examples. I like the addition of the alternative characterisation.

@ChristianSievers I'll add one in a bit

@ChristianSievers Thoughts?

@DonThousand In your definition of ideal, I think you omitted the requirement that the set has to be non-empty.

@MitchellSpector Indeed. Good catch

What is meant by "an ideal generated by polynomials"? (specifically, "generated")

@user41805 I'll add that in (It's now in the background)

You can use \$ as the MathJax delimiter, FYI


text:
Game of Game of Life
Game of Game of Life
Conway's Game of Life is a 0-player game.  But that's okay!  We can make it a multi-player game.
This game is played on the smallest square grid that will accommodate a 6x6 square for each player (12x12 for 2-4 players, 18x18 for 5-9 players, etc).  This grid is actually a torus, so it wraps in both directions. The rules of Life are:

If a cell has exactly 3 neighbours, it comes to life (or remains alive) in the next generation.
If a cell has exactly 2 neighbours, it does not change in the next generation.
If it does not have exactly 2 or 3 neighbours, it dies in the next generation.

A cell's neighbours are those cells adjacent to it orthogonally or diagonally; each cell has 8 neighbours.
In this game, there are only a few differences from the standard Game of Life:

Each player has a different colour of life, with dead cells being white and neutral living cells being black.
When a cell becomes alive, it takes on the colour of its most common neighbour, or black (no player) if there are three different colours.  Cells do not change colour as long as they are alive.
Each generation, each bot can cause one nearby cell to come alive in their colour or one of their own cells to die.  This happens before a generation is processed; a cell that is killed may come back to life and a cell brought to life may die in the subsequent generation.

Winning the game
The game lasts 1000 generations, or until there is only one colour of living cells remaining.  If all coloured cells die on the same generation, the game is a draw, and no bot receives points.  Each bot scores points equal to the percentage of living coloured cells it has at that time (out of the total number of coloured cells).  10000 games will be run, and the winner is the bot with the highest average score.  Ties are broken with a 1v1 cage match.
Starting conditions
Each bot will start with the following layout of living cells:
......
......
..##..
..##..
......
......

These will be randomly arranged into the square playing area.  Each 6x6 area without a bot will have the same configuration, but with black living cells.
Bot parameters
Your bot will be written in Javascript, and will not have an average call time of over 50ms (bots that do may be disqualified, but bots may use performance.now() to police their own time).  It will accept as parameters:
grid - The grid on which the game is played.  This should not be modified.
botId - The bot's ID, corresponding to the colour on the grid.
lastMoves - An array of each bot's most recent move, as it's (usually) possible but computationally intensive to get this information otherwise.

Your bot will return an array with two elements, x and y.  This is the cell that your bot wishes to play.  It must be within 2 cells of one of your living cells.  If the selected cell is alive and not one of your cells, it does nothing unless the bot whose colour it is removes it on the same generation, in which case it causes it to be your colour.  If it is alive and one of your cells, that cell is killed before the next generation.  If it is a dead cell, it comes alive before the next generation (it comes alive as your bot's colour unless some other bot also picks it, in which case it comes alive black).
A play too far away from one of your cells is a pass.  Alternately, [-1,-1] is an explicit pass. A play off of the board in any other way is illegal and grounds for disqualification.
On the grid, -1 is black (neutral living), 0 is white (dead), and all other numbers are the id of the bot whose life is in that cell.
Other Restrictions

You may make a maximum of 3 bots.
If your bots uses random numbers you can use Math.random.
Your bot may, if it wishes, store data on this.  It will be cleared between games.
You may not make a bot which targets a single, prechosen bot.  Your bot may target the tactics of a class of bots.
Cooperation is legal between bots, but communication is not - you can cooperate with a strategy, but not attempt to make a specific sequence of moves which identifies your bot.  For example, identifying a bot based on specific starting sequence is not allowed, but knowing "target bot prefers moving up and left, all else equal" is okay.  IDs are randomized and bots will not know in advance what other bots' IDs are.

Controller
This isn't quite complete, but it's a good start.  I plan to keep track of scores, add a box so it's easy to test a new bot, etc.  Of course, some of that is hard to test without real competitors, but I'll get around to it.
It seems that I made x the major axis and y the minor one, so if your bot is going a different way than you expect, that might be why.  Sorry.
Code Run it here
Example bot
It seems traditional to include a bad bot in the competition to get things started.  This bot is bad.  It chooses uniformly at random from cells in the grid and tries to move there.  I haven't yet had it survive 1000 generations.
function randomMovesBot(grid, botId, lastMoves){
    return [Math.floor(Math.random() * grid.length), Math.floor(Math.random() * grid.length)];
}

Winner
Two weeks after the last new submission (or a significant change to a bot), I'll close this by running 10000 games (number subject to possible revision).  I'll leave the controller up afterward if someone wants to make a new submission, but official standings won't change.
Chat

Hm, I don't understand how to advance to the next turn… I just see this (Chrome on Mac).

@Lynn The game stops when there's only one player alive - you'll need to define your own bot to get it to keep going. Either clone the repo and edit directly or create a bot function (in the console) and then push the function into the bots array.

You said we can use 'Math.random'. I assume you mean we can use whatever built-in implementation specific to our language?

@Spitemaster You should specify that x is the major index and y the minor index of the grid; this is the opposite of the usual convention.

@ouflak The controller is in Javascript, and your bot will be written in Javascript (as stated), so no, you can use Math.random.  I specifically stated that because there are ways to seed Math.random, and I want to leave that option open so that I can potentially have reproducible results.

@user1502040 Honestly, I didn't even think about that.  It's a square grid and it wraps so the directions are indistinguishable.  But I'll make a note of it.

Glad to see this finally posted!

@Spitemaster Contradiction - you want to have reproducible results but allow entries to police their run time with performance.now().

@Alion Fair point.  I'm not super concerned about either time or reproducibility - I don't think anyone is going to write a bot that goes over 50ms call time and if nobody does, we can have reproducibility.  If someone does, we can't, but that's not a big deal.

Can you switch off neutral cells? My guess is "no", but the sentence that is closest to covering this case then goes on to refer to "the bot whose color it is".

How do neutral cells affect the color of a born cell? For example, what does 1 red + 2 neutral (black) do?

@Alion You cannot kill living neutral cells. Red+Black+Black=Black

@Spitemaster In nextGeneration the condition if (k == l) continue; is incorrect; it skips the main diagonal. You should check if k and l are both 0 instead.

@user1502040 dur.  I'll have that fixed soon.

May I suggest creating a dedicated chat room for this KotH? I always love to talk about strategies with other contestants in challenges such as this one.

@Alion Yep, created.  https://chat.stackexchange.com/rooms/104667/game-of-game-of-life

I'm getting flashbacks to the last time we did a KOTH Game of Life, but thankfully, the restriction of only spawning one square, within a certain distance from your existing clusters, means that this challenge is not a dupe

Also, you should disallow bots that modify the grid directly. I know it should go without saying, but there are technically no rules in place (yet) that prevent me from making a bot that modifies grid directly....

@ValueInk I did say the grid should not be modified... I guess someone might not read that as a restriction, but I think it's clear enough. I'll adjust the controller to pass in a copy if necessary.

Do-nothing
function rgs_do_nothing(grid, id, last_moves) {
    return [-1, -1];
}

As of the time of posting, this wins against all other bots in the competition fairly consistently.
This bot is funny because in the branch of numerical analysis where I did some research, sometimes we have partial differential equations with these do-nothing boundary conditions and for a method I implemented, it literally amounted to doing nothing to handle the boundary conditions... My best type of work is when it is legit to do nothing :')

(⩺ ͟ʖ⩹) How does this consistently win against the random moves bot? +1 from me.

@Lyxal I dunno. For the times I hit "run game" it always won against the random bot.

Bad news: when I fixed the problem mentioned by @user1502040 (missing the main diagonal), randomMovesBot now beats rgs_do_nothing a full 28% of the time.

Nice arguments!

planBbot
I took planBot as a blue print. With simple enhancements/changes:
Version 1.1

improved move selection: never delete own colour cells
improved scoring
improved time management: used a PD-Controller to stay at 50ms
changed policy: dropped endgame mode
result of playing 100 games:

Name            Score
BestNowBot        0
planBbot v1.1   100
planBot           0
randomMovesBot    0
rgs_do_nothing    0

Version 1.0

simple time management:
Try to stay within 50 ms per move on average while using as much time as possible for lookaheads.
some performance tweaks:
Undone caching of results. (Identical board states are too unlikely.)
scoring: The idea: Stay sparse and don't feed the opponent.
endgame aware: If planBbot survived until generation 990 it starts to look deep ahead to generation 1000.
result of playing 100 games:

Name            Score
BestNowBot        0.64
planBbot v1.0    85.40
planBot          13.94
randomMovesBot    0
rgs_do_nothing    0

// version 1.1
function planBbot(grid, botId, lastMoves) {
    let t0=performance.now();
    let best_cell = [-1, -1];
    let max_score = -10000000;
    let size = grid.length;
    let possible_moves = new Set();
    let dist = 1
    for (let x = 0; x < size; x++) {
        for (let y = 0; y < size; y++) {
            if (grid[x][y] == botId) {
                for (let dx = -dist; dx <= dist; dx++) {
                    for (let dy = -dist; dy <= dist; dy++) {
                        let x1 = (size + x + dx) % size;
                        let y1 = (size + y + dy) % size;
                        if (grid[x1][y1] == 0) {
                            possible_moves.add([x1, y1]);
                        }
                    }
                }
            }
        }
    }
    if (possible_moves.size == 0) {
        return best_cell;
    }

    let new_grid = Array(size).fill(0).map(() => new Array(size).fill(0));
    if (typeof this.A == "undefined" || typeof this.A.dtime == "undefined") {
        this.A={iters:4, dtime:49, count:0, e0:0};
        this.A.lookahead=function(old_grid, new_grid){
            let iscore = 0;
            let oscore = 0;
            let neighbours = [];
            for (let x = 0; x < size; x++) {
                for (let y = 0; y < size; y++) {
                    neighbours.length = 0;
                    for (let dx = -1; dx <= 1; dx++) {
                        for (let dy = -1; dy <= 1; dy++) {
                            if ((dx == 0) && (dy == 0)) {
                                continue;
                            }
                            let cell = old_grid[(size + x + dx) % size][(size + y + dy) % size];
                            if (cell != 0) {
                                neighbours.push(cell);
                            }
                        }
                    }

                    let next=old_grid[x][y];
                    switch(neighbours.length) {
                    case 2: break;
                    case 3: if (next == 0) {
                            if (neighbours[0] == neighbours[1] || neighbours[0] == neighbours[2]) {
                                next = neighbours[0];
                            } else if (neighbours[1] == neighbours[2]) {
                                next = neighbours[1];
                            } else {
                                next = -1;
                            }
                        }
                        break;
                    default: next = 0;
                    }

                    new_grid[x][y] = next;
                    if (next == botId) {
                        iscore++;
                    } else if (next != 0) {
                        oscore++;
                    }
                }
            }
            if (oscore==0) {
                return 100000
            }
            return (iscore)-4*(oscore);
        }
    }

    let me=this.A;
    me.count++;
    let e=49-me.dtime;
    me.iters+=0.05*e+0.0005*(e-me.e0);
    me.e0=e;
    let iters=0.3*size*size*Math.max(me.iters, 2)/possible_moves.size;
    iters=Math.min(Math.max(iters+0.5, 3), 7);
    for (cell of possible_moves) {
        let old_grid = grid.map(x => x.slice());
        old_grid[cell[0]][cell[1]] = botId - old_grid[cell[0]][cell[1]];
        let score = 0;
        for (let i = 0; i < iters; i++) {
            score += me.lookahead(old_grid, new_grid);
            let tmp = new_grid;
            new_grid = old_grid;
            old_grid = tmp;
        }

        if (score >= max_score) {
            max_score = score;
            best_cell = cell;
        }
    }
    me.dtime=performance.now() - t0;
    return best_cell;
}

Best Now Bot
function BestNowBot(grid, botId, lastMoves){
    let wrap = coord => coord < 0 ? coord + grid.length : coord >= grid.length ? coord - grid.length : coord;
    let adj_life = (x, y) => {
        let sum = 0, sum_mine = 0;
        for (let i = -1; i <= 1; i++){
            for (let j = -1; j <= 1; j++){
                if (!i && !j) continue;
                if (grid[wrap(x+i)][wrap(y+j)]) sum++;
                if (grid[wrap(x+i)][wrap(y+j)] == botId) sum_mine++;
            }
        }
        return [sum, sum_mine];
    }
    let my_cells = [];
    for (let i = 0; i < grid.length; i++){
        for (let j = 0; j < grid.length; j++){
            if (grid[i][j] == botId){
                my_cells.push([i, j]);
            }
        }
    }
    let legal_moves = my_cells.slice();
    my_cells.forEach(cell => {
        for (let i = -2; i <= 2; i++){
            for (let j = -2; j <= 2; j++){
                let x = wrap(cell[0] + i),
                    y = wrap(cell[1] + j);
                if (grid[x][y] == 0 && !legal_moves.some(m => m[0] == x && m[1] == y)){
                    legal_moves.push([x, y]);
                }
            }
        }
    });
    // Calculate results of each move.
    legal_moves.forEach(move => {
        let move_score = 0;
        if (grid[move[0]][move[1]] == botId) move_score--;
        for (let i = -1; i <= 1; i++){
            for (let j = -1; j <= 1; j++){
                let x = wrap(move[0] + i),
                    y = wrap(move[1] + j);
                let [adj, adj_mine] = adj_life(x, y);
                if (grid[x][y] == botId && adj == 3){
                    move_score--;
                } else if (grid[x][y] == 0 && adj == 2 && adj_mine > 0){
                    move_score++;
                }
            }
        }
        move.push(move_score);
    });
    let best = Math.max(...legal_moves.map(m => m[2]));
    let good_moves = legal_moves.filter(m => m[2] == best);
    return good_moves[Math.floor(Math.random() * good_moves.length)].slice(0, 2);
}

BestNowBot looks at all the available options and determines which of them are positive for it, and then selects randomly from them.  Feel free to use BestNowBot as a basis for an answer - I figure it's kind of a baseline for an effective bot.
At time of posting, wins ~99% of games.

function advance(hash_grid, old_grid, new_grid){
    let hash = 0;
    let size = old_grid.length;
    let neighbours = [];
    for (let x = 0; x < size; x++) {
        for (let y = 0; y < size; y++) {
            neighbours.length = 0;
            for (let dx = -1; dx <= 1; dx++) {
                for (let dy = -1; dy <= 1; dy++) {
                    if ((dx == 0) && (dy == 0)) {
                        continue;
                    }
                    let cell = old_grid[(size + x + dx) % size][(size + y + dy) % size];
                    if (cell != 0) {
                        neighbours.push(cell);
                    }
                }
            }
            if (neighbours.length < 2 || neighbours.length > 3) {
                new_grid[x][y] = 0;
            } else if (neighbours.length == 3 && old_grid[x][y] == 0) {
                if (neighbours[0] == neighbours[1] || neighbours[0] == neighbours[2]) {
                    new_grid[x][y] = neighbours[0];
                } else if (neighbours[1] == neighbours[2]) {
                    new_grid[x][y] = neighbours[1];
                } else {
                    new_grid[x][y] = -1;
                }
            } else {
                new_grid[x][y] = old_grid[x][y];
            }
            hash += hash_grid[x][y] * new_grid[x][y];
        }
    }
    return hash;
}

function planBot(grid, botId, lastMoves) {
    let size = grid.length;
    let possible_moves = new Set();
    let count = 0;
    for (let x = 0; x < size; x++) {
        for (let y = 0; y < size; y++) {
            if (grid[x][y] == botId) {
                count++;
                for (let dx = -1; dx <= 1; dx++) {
                    for (let dy = -1; dy <= 1; dy++) {
                        let x1 = (size + x + dx) % size;
                        let y1 = (size + y + dy) % size;
                        if ((grid[x1][y1] == 0) || (grid[x1][y1] == botId)) {
                            possible_moves.add([x1, y1]);
                        }
                    }
                }
            }
        }
    }
    let possible_move_array = Array.from(possible_moves);
    if (possible_move_array.length == 0) {
        return [0,0];
    }
    let neighbor_scores = function(n) {
        if ((n >= 2) && (n <= 3)) {
            return 0;
        }
        return -1;
    }
    let best_cell = [0, 0];
    let max_score = -10000;
    let memo = new Map();
    let hash_grid = Array(size).fill(0).map(() => new Array(size).fill(0).map(() => Math.random()));
    let new_grid = Array(size).fill(0).map(() => new Array(size).fill(0));
    let iters = 4;
    for (cell of possible_move_array) {
        let old_grid = grid.map(x => x.slice());
        old_grid[cell[0]][cell[1]] = botId - old_grid[cell[0]][cell[1]];
        let hashes = []
        let score = 0;
        let hit = false;
        for (let i = 0; i < iters; i++) {
            let hash = advance(hash_grid, old_grid, new_grid);
            hashes.push(hash);
            if (memo.has(hash)) {
                score = memo[hash];
                hit = true;
                break;
            }
            let tmp = new_grid;
            new_grid = old_grid;
            old_grid = tmp;
        }
        if (!hit) {
            for (let x = 0; x < size; x++) {
                for (let y = 0; y < size; y++) {
                    if (old_grid[x][y] == botId) {
                        score++;
                    } else if (old_grid[x][y] > 0) {
                        score -= 1e-7;
                    }
                }
            }
        }
        for (hash of hashes) {
            memo.set(hash, score);
        }
        score += 1e-9 * Math.random();
        if (score >= max_score) {
            max_score = score;
            best_cell = cell;
        }
    }
    return best_cell;
}

Rolls ahead a few steps for each potential move and picks the move which resulted in the greatest area for itself, breaking ties by total opponent area. It also caches the results to avoid simulating identical board states.

I've improved the time tracking on the controller.  You're going to have time troubles with more opponents - 75+ms on my computer against 4 opponents.


text:
The Sorting Hat
Context
At Hogwarts School of Witchcraft and Wizardry, students are sorted into 4 houses, Gryffindor, Ravenclaw, Slytherin and Hufflepuff. This sorting is done by a magical hat, called the Sorting Hat.
Task
Your task is to code a sorting hat. In other words, you should create some deterministic rule that, given the name of a person, outputs one of the four available houses. (See the output section for a restriction on the rule)
Input
Input will be a string (representing the student name) in the ascii range [32, 126], the printable characters.
This is not necessarily an English name. The input may be "@_??" and your code should still assign a house.
Output
For a fixed string (any string of printable ASCII characters), your code should always output the same house, thus your code should be deterministic. The output has to uniquely identify the houses, in any of the following ways:

returning the full house name, e.g. "Gryffindor" (capitalization doesn't matter)
returning the house initial, e.g. "G" (capitalization doesn't matter)
returning the house index, e.g. 0 (you may use any house ordering as long as the indexing is done with 0, 1, 2, 3 or 1, 2, 3, 4 and as long as you specify it in your answer.)

What is more, there are 12 cases that should be as follows:

the inputs harry, hermione and ron should return gryffindor;
the inputs luna, cho and penelope should return ravenclaw;
the inputs draco, crab and goyle should return slytherin;
the inputs cedric, ernie and hannah should return hufflepuff;

You can either get these 12 inputs as stated, or the 12 inputs where the first letter is upper case (e.g. Harry).
You should also prove that there are other English names in this list that get mapped into each house.
Be sure to include the house that your code assigns to your own codegolf.SE nickname, plus the house rgs or RGS gets assigned to. Bonus imaginary internet points if I get assigned to Ravenclaw!!!
As of now, these answers qualify for the bonus imaginary internet points:
G B Ruby answer, ovs Python answer, Kevin Cruijssen Whitespace answer, Jonathan Allan Jelly answer, Nick Kennedy Jelly answer, Kaddath PHP answer, Noodle9 C answer, 640KB x86-16 answer, Guillermo Phillips PHP answer, Jonathan Alan Python 2 answer, Bob Jarvis - Reinstate Monica Clojure answer, Mitchell Spector Bash answer.
Test cases
"Harry" -> "Gryffindor"
"Hermione" -> "Gryffindor"
"Ron" -> "Gryffindor"
"Luna" -> "Ravenclaw"
"Cho" -> "Ravenclaw"
"Penelope" -> "Ravenclaw"
"Draco" -> "Slytherin"
"Crab" -> "Slytherin"
"Goyle" -> "Slytherin"
"Cedric" -> "Hufflepuff"
"Hannah" -> "Hufflepuff"
"Ernie" -> "Hufflepuff"

This is code-golf so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it... And happy golfing!

Can we use different indices for the houses? (would this be allowed: https://tio.run/##HY6xDsIwDER3vsJLlFbqAiqgVmJmh5XFTV0SKXUiU4Z@fcCZ3tPdDZf3zSc@leX2KhHXaUbg0ePHN9yaoTeXwfRnc7yavixJgHElCAzWo8huu7@QrCExqUtiRfwyKp1PikxMMeW6mAVdDZ3gpHynPdbG0SzBqZFwqJFHZvRqj/vTjgeALIG3eqKDpVG25Qc)

@ovs I will allow it and edit the challenge accordingly.

Crab should really be Crabbe, although potentially a bit late for the answers already written

@NickA geez, you are absolutely right! ahaha sorry for that one! And I call myself a Harry Potter fan :/ Well, I don't want to edit the question now because it might ruin some of the answers...

if this is purely deterministic should it have the random tag?

The idea was that you could pick a random function from strings to the set {0,1,2,3}. Do you think it is not appropriate? What would you suggest?

@NickA Technically it should be vincent. Also goyle should be gregory.

@Magma I think calling him "crab" is worse than calling him "crabbe" :)

@Noodle9 nice catch! Fixed it

"as long as the indexing is done with 0, 1, 2, 3" - can we please use 1-indexing? Also how about allowing any four consistent, distinct values? Lastly if all the listed names provide satisfactory outputs and we show four names from the linked name list map to the houses, can other names be assigned produce different output (not one of the four houses)?

@JonathanAllan 1 indexing is fine but it might be a bit late for me to allow any four distinct values. Also, it is not admissible that the sorting hat doesn't work for some strings in the ascii range of printable characters, even if it works for many strings.

Thanks, could you clarify indexing and "You should also prove that there are other English names" bits in the question (the latter implies we may have other strings which map elsewhere IMO)

@JonathanAllan My interpretation of that rule is that there needs to be some (not necessarily uniform) distribution across the houses and not just return Gryffindor for everything that isn't a special input. The statement is just to prove that your program actually does that

@JonathanAllan thanks for your feedback! I tried making the challenge more clear, but my intention was exactly as Cruncher said :)

What will Draco18s no longer trusts SE think...

Python 2, 30 bytes
Input is lower case name, output is 1 for Gryffindor, 0 for Ravenclaw, 2 for Slytherin and 3 for Hufflepuff.
lambda n:hash(n)%94%69%45%17%4

Try it online!
RGS is in Ravenclaw.

Python 2, 34 bytes
Takes names in lower case and outputs upper case house initials.
lambda n:'HSHHSRRG'[hash(n)%189%8]

Try it online!

Python 2, 34 bytes
Input with first letter in upper case, output is the house indices.
lambda n:~hash(n)%74%64%27%16%11%4

Try it online!
Rgs gets assigned to Ravenclaw, Ovs to Gryffindor.

Really nice job and you got the imaginary points! Also, I replied to your comment about the house indices.

What am I missing? Why doesn't lambda n:hash(n)%4 work? It's deterministic and always returns a number between 0 and 3

@Cruncher this wouldn't put the right people together in the same house (e.g. Harry, Hermione and Ron should all be assigned to the same house)

@ovs Knew I had to have been missing something! Guess I didn't read the whole spec lol

@ovs So how did you find those mods? Somewhat experimentally?

@Cruncher I have written a program that, given disjoint sets of integers, find s modulo operation, such that the resulting sets are still disjoint and the resulting numbers are in a small range. I still have to try out different number of modulo operation and different ranges for these numbers. And there are different ways of generating the initial integers from the name, e.g. hash(n), int(n,36), ~hash(n) ..., all will lead to different results.

JavaScript (Node.js), 35 bytes
Expects the names in title case. Returns \$0\$ for Gryffindor, \$1\$ for Hufflepuff, \$2\$ for Slytherin or \$3\$ for Ravenclaw.
s=>(([a]=Buffer(s))[3]*9|a*553)%9&3

Try it online!

JavaScript (ES6), 40 bytes
Returns the house initial in upper case.
s=>"SSHGRHGR"[parseInt(s,28)*51%78%10&7]

Try it online!
How?
The base formula that maps our 12 wizard students to the relevant houses is:
"SSHGRHGRS?"[parseInt(s, 28) * 51 % 78 % 10]

We first parse the input as Base-28. Valid input strings in this base must consist of an optional leading unary operator (+ or -), followed by a sequence of characters matching [0-9A-Ra-r]+. If the whole string is invalid, it is parsed as \$NaN\$. Otherwise, the parsing stops just before the first invalid character.
Example:
parseInt("harry", 28) == parseInt("harr", 28) // -> 381807

There are, obviously, countless ways of building the hash formula and the corresponding lookup table \$t\$.
Among all brute-forced formulas, this one was chosen because:

\$t[8]=t[0]\$ and we don't care about the value of \$t[9]\$, which means that we can apply a final modulo \$8\$ to get 8 entries.
This modulo \$8\$ can be turned into a bitwise AND with \$7\$, which also guarantees that the index will be forced into \$[0..7]\$ even if the input string is parsed as \$NaN\$ or a negative value.

34 bytes Including bonus.

@GB You may want to post it as a separate answer. But I think this requires 3 extra bytes to support all inputs.

This is interesting, I know some of the Javascript quirks, but I didn't expect the modulo operation to return a negative int.

@GB Taking the sign of the divisor is needed more common. But quite a few languages use the sign of the dividend. There's a table on Wikipedia summarizing that.

@Arnauld Thanks for making your answer even more complete with the explanation.

Jelly,  11  8 bytes
Updated 8-byter so that the bonus is fulfilled for both 'rgs' and 'RGS' :)
“EwS’,4ḥ

A monadic Link accepting a list of characters which yields:
4: Gryffindor
2: Ravenclaw
1: Slytherin
3: Hufflepuff

Try it online!
Or see a test-suite showing the 3 given names belonging to each house, that an extra name exists in the linked name-list for each house and that both 'rgs' and 'RGS' are in 2, Ravenclaw.
Places 'Jonathan Allan' in Ravenclaw.
How?
“¢Ʋ⁹’,4ḥ - Link: list of characters
“EwS’    - base 250 number = 4405084
      4  - 4
     ,   - pair
       ḥ - hash using:
             4405084 as a salt, and
             implicit range(4) = [1,2,3,4] as the domain

11-byter:
OP%⁽MJ%23%4

A monadic Link accepting a list of characters which yields:
3: Gryffindor
2: Ravenclaw
1: Slytherin
0: Hufflepuff

(Bonus fulfilled for 'rgs')
Try it online!
Or see a test-suite showing the 3 given names belonging to each house, that an extra name exists in the linked name-list for each house and that 'rgs' is in 2, Ravenclaw.
Places 'Jonathan Allan' in Slytherin.
How?
OP%⁽MJ%23%4 - Link: list of characters  e.g. 'rgs'
O           - ordinals                       [114,103,115]
 P          - product      114 * 103 * 115 = 1350330
   ⁽MJ      - 20325                          20325
  %         - modulo       1350330 % 20325 = 8880
       23   - 23                             23
      %     - modulo             8880 % 23 = 2
          4 - 4                              4
         %  - modulo                 2 % 4 = 2

Here is a Python script which will print viable i j {G} {R} {S} {H} results for code like OP%i%j%4 for which each of i and j are small enough to write within three bytes. The first result happens to place 'rgs' in Ravenclaw.
from functools import reduce

a,b,c,d = (['harry', 'hermione', 'ron'], ['luna', 'cho', 'penelope'], ['draco', 'crab', 'goyle'], ['cedric', 'ernie', 'hannah'])
pa,pb,pc,pd = ([reduce(lambda x,y:x*y, map(ord,n)) for n in v] for v in (a,b,c,d))
for j in range(5, 32251):
    for i in range(j, 32251):
        i+=1
        A=set(v%i%j%4 for v in pa)
        B=set(v%i%j%4 for v in pb)
        if A&B: continue
        C=set(v%i%j%4 for v in pc)
        if A&C or B&C: continue
        D=set(v%i%j%4 for v in pd)
        if A&D or B&D or C&D: continue
        print(i, j, A, B, C, D)
        break

Good job! +1 And thanks for sharing your Python script!

@RGS found one satisfying the bonus for both variants of your moniker given :)

Great job! And you taught me a new word! Had no idea what moniker was :)

While this is an amazing answer, doesn't the output domain of 1-4 break the explicit rule about indexing? you may use any house ordering as long as the indexing is done with 0, 1, 2, 3 and as long as you specify it in your answer.

@Cruncher 1-indexing is allowed by default, although that text does appear to override that so I've asked OP (I actually would think it best to allow any 4 consistent, distinct values).

@Cruncher - 1-indexing has been allowed.

Ruby, 30 31 bytes
->x{"HSSRGRHHGRR"[x.sum%91%11]}

Try it online!
Returns initial of house. RGS is on Ravenclaw

Great work! +1 for this nice ruby submission.

05AB1E, 14 12 bytes
•Sâ;»•4вs1öè

Outputs 0123 instead of GRSH.
-2 bytes thanks to @Grimmy (unfortunately it no longer got the internet bonus for outputting Ravenclaw for RGS).
Try it online.
Explanation:
•Sâ;»•        # Push compressed integer 478937616
      4в      # Convert it to base-4 as list: [1,3,0,2,0,3,0,0,0,0,2,0,1,0,0]
        s1ö   # Take the input, and convert it from base-1 to a base-10 integer
              # which will essentially sum the indices of the characters in the string "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzǝʒαβγδεζηθвимнт\nΓΔΘιΣΩ≠∊∍∞₁₂₃₄₅₆ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~Ƶ€Λ‚ƒ„…†‡ˆ‰Š‹ŒĆŽƶĀ‘’“”–—˜™š›œćžŸā¡¢£¤¥¦§¨©ª«¬λ®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
           è  # And use that to (modular) index into the earlier created list
              # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •Sâ;»• is 478937616 and •Sâ;»•4в is [1,3,0,2,0,3,0,0,0,0,2,0,1,0,0].

My name is RGS, which is close to RGB... But I'm being assigned to Gryffindor. GB edited his answer, so maybe check it again! He now gets the bonus imaginary points

Great port! +1 Now I want it in Java :D

12 bytes (no bonus, unfortunately)

@Grimmy Thanks! I know 1ö could be used as an alternative for SO (digit sum), but didn't really knew how it works. Now I do by looking at the Python code of the legacy version. :)

x86-16 machine code, IBM PC DOS, 37 32 30 bytes
Binary:
00000000: 92be 8200 ad8a e0ac b3be f7f3 92d4 08bb  ................
00000010: 1601 d7cd 29c3 4853 5252 4753 5252       ....).HSRRGSRR

Build HAT.COM from above using xxd -r.
Unassembled listing:
92          XCHG AX, DX             ; DX = 0
BE 0082     MOV  SI, 82H            ; SI to input string (char*s)
AD          LODSW                   ; AL = s[0], SI = SI + 2
8A E0       MOV  AH, AL             ; AH = s[0]
AC          LODSB                   ; AL = s[2]
B3 BE       MOV  BL, 190            ; divisor = 190
F7 F3       DIV  BX                 ; DX = AX % 190
92          XCHG AX, DX             ; AX = DX
D4 08       AAM  8                  ; AL = AL % 8
BB 011D     MOV  BX, OFFSET S       ; BX = output string table
D7          XLAT                    ; AL = [BX][AL]
CD 29       INT  29H                ; DOS fast console output
C3          RET                     ; return to DOS
S           DB "HSRRGSRR"           ; house char table

A standalone PC DOS executable.  Input via command line, output to console is the house initial {"G","R","S","H"}.
All credit goes to @Noodle9, as this is really just a port of that answer.  I promise to try harder next time.
I/O:

Even though it is a port, really nice job! +1

@RGS, well Noodle9 says you can be in Ravenclaw, so it's okay by me too.

Really good job! Hehe :D

Python 2, 24 bytes
lambda n:hash(n)/64779%4

3: Gryffindor
0: Ravenclaw
2: Slytherin
1: Hufflepuff

Bonus fulfilled for 'rgs' while 'Jonathan Allan' is placed in Slytherin.
Try it online!

Good job working on this one! +1 and congratulations for the bonus imaginary internet points!

@Belly Buster I'm glad the authors of both Python answers got assigned to Slytherin :-D

PHP, 36 33 31 29 bytes
<?=467921>>crc32($argn)%20&3;

Try it online!
I'm in danger of turning into a one trick pony.
2=Gryffindor, 1=Ravenclaw, 0=Slytherin, 3=Hufflepuff
I'm in Ravenclaw along with @RGS!

Cool submission! +1 If I understand correctly, I am in Ravenclaw?

You are indeed. Output formatting's not obvious, but needs must, sorry about that.

don't worry! I just wanted to confirm it before linking to your answer in my challenge :) good job on getting the bonus imaginary internet points!

Gryffindor.....

Python 2, 25 bytes
lambda n:hash(n)%814329%4

Try it online!
Firstly, forgive me for mostly ripping off ovs's answer but this is my first ever golf "putt", so I'm taking it for posting practice!
2: Gryffindor
3: Ravenclaw
1: Slytherin
0: Hufflepuff
RGS -> Slytherin and Belly Buster -> Slytherin!

Good job on your "golf putt"! +1 for the nice solution

+1, nicely done; sorry to have pipped your score

Python 3.8, 18 bytes
Sharing because it's an amusing solution!
If invoked with the following environment variable PYTHONHASHSEED=895984 (apparently this does not have to be counted towards byte length),
lambda s:hash(s)%4

Try it online!
given lowercase input,

0 => Gryffindor
1 => Hufflepuff
2 => Ravenclaw
3 => Slytherin

RGS (and rgs) goes to Ravenclaw, chinatsu goes to Gryffindor.
In the range [0, 895984] there are 3 good seeds, 139840, 330811, and 895984. Only the latter places RGS in Ravenclaw.

I like this solution :D thanks for this

W d, 19 18 bytes
Port of G B's answer. (RGS is also on Ravenclaw.)
BTW, my name can't be entered in the W interpreter, so I do not belong in any house.

I forgot that the operator overloading exists, so -1 byte due to the order-free indexing.

r#↔X┌3ÇMQyΘf○ºÞΘ☺¬

Uncompressed:
CJ91m11m"HSSRGR HGRR"[

Explanation
C                      % Convert the input to a list of characters
 J                     % Reduce the list by addition
  91m                  % Modulus by 91
     11m"HSSRGR HGRR"[ % Cyclic indexing into the string

I'm assuming there is no TIO link? Also, GBs answer has a problem, so yours might have it as well

My answer is fixed (I can't count to 11, it seems)

C (clang), 50 \$\cdots\$ 47 42 bytes
Added a byte to fix a bug kindly pointed out by RGS.
Saved 2 bytes thanks to S.S. Anne!!!
Saved 5 bytes thanks to ceilingcat!!!

#define f(s)"HSRRGSRR"[(*s<<8|s[2])%190%8]

Try it online!
Inputs a capitalised name string and returns G, H, S, or R.
RGS is in Ravenclaw!!!

Thanks for your submission +1 :) it is just a pity that I can't be in Ravenclaw, but that is ok :)

@RGS The Hat hears your preference for Ravenclaw and puts you in Ravenclaw! :D

Why'd you have to post an answer before I could?

@S.S.Anne Because it's the Sorting Hat!!! :)))

47 bytes abuses bitwise ops and wide strings.

Whitespace, 295 bytes
[S S S N
_Push_0][N
S S T   T   N
_Create_Label_LOOP][S N
S _Dupe][S N
S _Dupe][T  N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve_input][S N
S _Dupe_input][S S S T  S T S N
_Push_10][T S S T   _Subtract][N
T   S T S N
_If_0_Jump_to_Label_DONE][T S S S _Add][N
S N
T   T   N
_Jump_to_Label_LOOP][N
S S T   S N
_Create_Label_DONE][S N
N
_Discard][S S S T   S T T   S T T   N
_Push_91][T S T T   _Modulo][S S S T    S T T   N
_Push_11][T S T T   _Modulo][S N
S _Dupe][N
T   S S S N
_If_0_Jump_to_Label_HUFFELPUFF][S S S T N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S T N
_If_0_Jump_to_Label_SLYTHERIN][S S S T  N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S T N
_If_0_Jump_to_Label_SLYTHERIN][S S S T  N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S N
_If_0_Jump_to_Label_RAVENCLAW][S S S T  N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S S N
_If_0_Jump_to_Label_GRYFFINDOR][S S S T N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S N
_If_0_Jump_to_Label_RAVENCLAW][S S S T  N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S N
_If_0_Jump_to_Label_RAVENCLAW][S S S T  N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S S S N
_If_0_Jump_to_Label_HUFFELPUFF][S S S T N
_Push_1][T  S S T   _Subtract][S N
S _Dupe][N
T   S S N
_If_0_Jump_to_Label_GRYFFINDOR][N
S S N
_Create_Label_RAVENCLAW][S S S T    N
_Push_1][T  N
S T _Print_as_integer][N
N
N
_Exit_Program][N
S S S N
_Create_Label_GRYFFINDOR][T N
S T _Print_as_integer][N
N
N
_Exit_Program][N
S S T   N
_Create_Label_SLYTHERIN][S S S T    S N
_Push_2][T  N
S T _Print_as_integer][N
N
N
_Exit_Program][N
S S S S N
_Create_Label_HUFFELPUFF][S S S T   T   N
_Push_3][T  N
S T _Print_as_integer]

Letters S (space), T (tab), and N (new-line) added as highlighting only.
[..._some_action] added as explanation only.
Port of @GB's Ruby answer.
Since Whitespace inputs one character at a time, the input should contain a trailing newline (\n) so it knows when to stop reading characters and the input is done.
Try it online (with raw spaces, tabs and new-lines only).
Explanation in pseudo-code:
Integer sum = 0
Start LOOP:
  Integer c = STDIN as character
  If(c == '\n'):
    Jump to Label DONE
  sum = sum + c
  Go to next iteration of LOOP

Label DONE:
  sum = sum modulo-91
  sum = sum modulo-11
  If(sum == 0): Jump to Label HUFFELPUFF
  If(sum-1 == 0): Jump to Label SLYTHERIN
  If(sum-2 == 0): Jump to Label SLYTHERIN
  If(sum-3 == 0): Jump to Label RAVENCLAW
  If(sum-4 == 0): Jump to Label GRYFFINDOR
  If(sum-5 == 0): Jump to Label RAVENCLAW
  If(sum-6 == 0): Jump to Label RAVENCLAW
  If(sum-7 == 0): Jump to Label HUFFELPUFF
  If(sum-8 == 0): Jump to Label GRYFFINDOR
  Label RAVENCLAW:
    Integer n = 1
    Print n as integer to STDOUT
    Exit program
  Label GRYFFINDOR:
    Print top (sum-4 or sum-8) as integer to STDOUT
    Exit program
  Label SLYTHERIN:
    Integer n = 2
    Print n as integer to STDOUT
    Exit program
  Label HUFFELPUFF:
    Integer n = 3
    Print n as integer to STDOUT

+1 for this really interesting submission! and you get bonus imaginary internet points!

Zsh, 66 bytes
case $1 in ?ra*|g*)<<<S;;[lp]*|cho)<<<R;;h?r*|r*)<<<G;;*)<<<H;esac

Try it online!
No hash functions available, so we make do with pattern matching in
a single case statement:
case $1 in
    ?ra*|g*)    <<< S ;;
    [lp]*|cho) <<< R ;;
    h?r*|r*)   <<< G ;;
    *)         <<< H     # last branch doesn't need ;;
esac

Cool submission! +1 for your work :D

Retina 0.8.2, 36 bytes
\B(u|h|p|ra|oy|nn|edr|rni)
$.&$*
3`1

Try it online! Link includes test suite. Outputs the house index. Neil and rgs both map to index 0. Explanation:
\B(u|h|p|ra|oy|nn|edr|rni)
$.&$*

Replace each of the scoring letters with 1s. The \B means that the first letter never counts as a scoring letter, allowing it to be upper or lower case.
3`1

Count the number of scoring letters, up to 3.

Thanks for your submission! Regex for the win, isn't it? Too bad I don't get bonus imaginary internet points... But I can't imagine how you could get them without spending bytes. +1

PHP, 43 bytes
<?='RSHGGGHSHRSGRRSGHHRS'[crc32($argn)%20];

Try it online!
I wanted to do something else than a port.. better but maybe I can do better, when I have time. And this time with bonus points! I'm Griffindor without my capital ;) (Hacks not to be Hufflepuff)
Takes input with Capital letter and returns house initial letter (works with any string input actually, but the result will change)
EDIT: changed a not meaningful G to a S for equal representation between G and S
EDIT 2: saved 10 bytes with a longer string, and ran for the double extra points!! Houses are equally reprensented for meaningless values.

Cool submission! It's just too bad you can't get the bonus imaginary internet points... +1

@RGS much better version, and you got your house with both names, capital or not ;)

Indeed! Good job on this one! :D

APL (Dyalog Unicode), 23 24 bytesSBCS
'GSGHSSRRH'⊃⍨9|15|19|⍋⊥⍒

Try it online!
Some number digging magic using three functions unique to APL:

Grade up ⍋X: Indices to reorder the array X into ascending order
Mixed base X⊥Y: Convert array Y from base X to integer
Grade down ⍒X: Indices to reorder the array X into descending order

Interestingly, modulo 15 doesn't guarantee successful indexing into a length-10 list, yet both rgs and bubbler fit into the list nicely. I missed the input range, so I added 9| in the modulo chain to fix it at the cost of 1 byte. rgs goes to Slytherin; I go to Hufflepuff.

Thanks for your submission! Unfortunately your code doesn't work for the input string  john, so it doesn't meet the requirements! The sorting hat should assign a house to any string in the ascii range specified :/

@RGS Sorry, I missed the input range. Luckily it is fixable at the cost of 1 byte.

Thanks for taking the time to fix it! +1 for your submission!

If this is mod 9 then you can remove the trailing H.

@S.S.Anne No, the code assumes ⎕IO←0 (I should have mentioned that), and all characters from indexes 0 to 8 (inclusive) are used.

Jelly, 16 bytes
OḄ%19ị“®5ƭ{~’ḃ4¤

Try it online!
A monadic link taking a string or list of strings and returning a 1-indexed number corresponding to Gryffindor, Ravenclaw, Slytherin, Hufflepuff.
"rgs" gets sorted into Ravenclaw.

Good job! ANd you got some bonus imaginary internet points as well! +1

Ruby, 28 bytes
->n{296887>>n.sum%20%11*2&3}

Try it online!
Returns 2310 instead of GRSH. RGS is on 1=S, I am on 2=G.

Thanks for your submission. I'm upvoting it even though I am not on Ravenclaw :)

Clojure - 186 bytes
Since everyone else seems to have settled on somewhat similar algorithms I boldly went where no one wanted to go before (that I noticed)!
Takes the string, converts it to individual characters, sums up the character values. Has precomputed special cases for the desired assignments. For all other names takes the character sum, mod 4, to get a number in [0..3]. 0 = Gryffindor, 1 = Ravenclaw, 2 = Slytherin, 3 = Hufflepuff.
Golfed version
(defn s[m](let[n(apply + (map int (into [] (clojure.string/upper-case m))))p {390 0,599 0,239 0,1973 0,304 1,218 1,600 1,361 2,280 2,384 2,426 3,430 3,371 3,236 1}](or (p n) (mod n 4))))
Ungolfed version
Adds precomputed values for other versions of the character's names (e.g. accepts "Harry", "Harry Potter", and "Potter" for The Boy Who Lived, and so on), and also returns the full house name instead of a number:
(defn sorting-hat [name]
  (let [ n          (apply + (map int (into [] (clojure.string/upper-case name))))
         houses     [ "Gryffindor" "Ravenclaw" "Slytherin" "Hufflepuff" ]
         name-map   { 390 0, 900 0, 478 0, 599 0, 1149 0,  518 0, 239 0, 809 0, 1018 0, 538 0, 1973 0,
                      304 1, 943 1, 218 1, 603 1,  600 1, 1378 1,
                      361 2, 849 2, 456 2, 280 2,  415 2,  982 2, 384 2, 959 2,
                      426 3, 991 3, 430 3, 906 3,  371 3, 1057 3, 236 1 }
         house      (name-map n)                                                              ; house derived from special cases
         house2     (mod n 4)]
    (houses (or house house2))))

Test harness:
(doseq [ person  ["Harry"  "Hermione" "Ron"
                  "Luna"   "Cho"      "Penelope"
                  "Draco"  "Crab"     "Goyle"
                  "Cedric" "Hannah"   "Ernie"
                  "RGS"                            ; poster's codegolf nickname
                  "Bob Jarvis - Reinstate Monica"  ; my codegolf nickname
                  "Ackerley" "Ealasaid" "Icarus" "Mabel" "Qing" "Ulbrecht" "Yardley"] ]  ; other names
  (println person " -> "(s person)))

Test results (using golfed version):
Harry  ->  0
Hermione  ->  0
Ron  ->  0
Luna  ->  1
Cho  ->  1
Penelope  ->  1
Draco  ->  2
Crab  ->  2
Goyle  ->  2
Cedric  ->  3
Hannah  ->  3
Ernie  ->  3
RGS  ->  1
Bob Jarvis - Reinstate Monica  ->  0
Ackerley  ->  0
Ealasaid  ->  0
Icarus  ->  3
Mabel  ->  1
Qing  ->  3
Ulbrecht  ->  1
Yardley  ->  2

Note that OP is assigned to Ravenclaw. I'm in Gryffindor.
Try It Online! (golfed version)

Cool answer +1! But maybe going where no one went means you end up spending some more bytes, no?

I (nearly) always use Clojure for puzzles/golfing. I know that with Clojure I won't win any prizes for brevity, so my goal is to go for beauty, grace, and style. And learning things - such as finding out as part of this solution that the or macro in Clojure functions more-or-less the same as COALESCE in SQL - is just an added bonus :-)

Bash, 78 bytes (& bonus imaginary Internet points!)
sortinghat:
o()(printf %d "'${s:$1}")
s=$1
h=HSSGGRSHRHSRGGHHR
echo ${h:(`o`-`o -1`)%13:1}

Try it online!
Input is passed as an argument in all lower-case, and output (G, R, S, or H) is on stdout.

Test program:
for x in %GRYFFINDOR-TEST harry hermione ron %RAVENCLAW-TEST luna cho penelope rgs %SLYTHERIN-TEST draco crab goyle %HUFFLEPUFF-TEST cedric ernie hannah %OTHER-SAMPLE-NAMES minerva newton myrtle salazar
  do
    if test "${x:0:1}" = '%'
      then
        echo "${x:1}"
      else
        printf "%12s " "$x"
        ./sortinghat "$x"
    fi
  done

Output of test program:
GRYFFINDOR-TEST
      harry  G
   hermione  G
        ron  G
RAVENCLAW-TEST
       luna  R
        cho  R
   penelope  R
        rgs  R
SLYTHERIN-TEST
      draco  S
       crab  S
      goyle  S
HUFFLEPUFF-TEST
     cedric  H
      ernie  H
     hannah  H
OTHER-SAMPLE-NAMES
    minerva  G
     newton  H
     myrtle  R
    salazar  S

The extra sample names are all in OP's list of names, and I think they're even sorted into the right houses (according to the HP books)!  (I get sorted into Gryffindor if you put my name in all lower-case like the others.)

Really nice job on this one! +1 And congratz for the bonus imaginary internet points :D

Clojure - 124 bytes
Solution
(defn f[n](if-let[k({:harry 3 :hermione 3 :cho 0 :crab 1 :ernie 2}(keyword(clojure.string/lower-case n)))]k(mod(count n)4)))
Gryffindor 3
Rawenclaw 0
Slytherin 1
Hufflepuff 2
Explanation
The algorithm takes the modulo 4 length of the name and assigns a house based on that. Exceptions are made for the special cases for the few names that would not get to the predetermined house in this way (Harry, Hermione, Cho, Crab, Ernie).
Test
(deftest a-test
  (testing "known-cases"
    (is (= 3 (f "Harry")))
    (is (= 3 (f "Hermione")))
    (is (= 3 (f "Ron")))

    (is (= 0 (f "Luna")))
    (is (= 0 (f "Cho")))
    (is (= 0 (f "Penelope")))

    (is (= 1 (f "Draco")))
    (is (= 1 (f "Crab")))
    (is (= 1 (f "Goyle")))

    (is (= 2 (f "Cedric")))
    (is (= 2 (f "Hannah")))
    (is (= 2 (f "Ernie")))

    )
  (testing "other-names"
    (is (= 0 (f "Ackerley")))
    (is (= 1 (f "Acton")))
    (is (= 2 (f "Africa")))
    (is (= 3 (f "Addison")))

    (is (= 3 (f "Attilio")))
    (is (= 3 (f "RGS")))
    )
  )

authors: Bob Jarvis - Слава Україні