Name of Frankenstein's Monster

Python 2, 227 220 214 bytes

lambda y,c:[[choice([["wretch",m,"creature","demon",d,F,"it"],["vile insect",a+m,F,"wretched "+d,a+d]][c>9]),"Frankenstein's "+m][y>1818],0][y<1818]
from random import*
m,d,F,a='monster','devil','fiend',"abhorred "

Try it online!


Perl 5, 172 bytes

171 bytes code + 1 for -p.

@a=<><10?($}=wretch,$M=monster,creature,demon,$D=devil,fiend,it):("vile insect",($A="abhorred ").$M,fiend,"$}ed $D",$A.$D);$_=($a[rand@a],"frankenstein's $M",0)[$_<=>1818]

Try it online!

Explanation

Pretty standard, only slightly unsual thing is using the 'spaceship operator' (<=>) with 1818 to return -1, 0, or 1, if the input $_ is less than, equal to, or greater than 1818 to return the last, first, or second index of the source data. Also, I like the fish operator!


C# (Visual C# Compiler), 225 209 bytes

y=>c=>y<1818?"":y>1818?"frankenstein's monster":"wretch,monster,creature,demon,devil,it,fiend,vile insect,abhorred monster,wretched devil,abhorred devil".Split(',')[new System.Random().Next(c>9?6:0,c>9?11:7)];

Try it online!

-16 thanks to Kevin Cruijssen

Not particularly concise, but I would expect C# to take more space to declare and use any repeated strings the way the Python answer does than to just repeat them. The included test runner has a Thread.Sleep(1) inside the enumeration of test cases because default seeding for Random() uses the current time and the actual function runs fast enough to end up with the same seed on subsequent runs without a delay.

Calls to the func use currying syntax, f(year)(chapter) (or whatever name the function is stored in instead of f)