| Bytes | Lang | Time | Link |
|---|---|---|---|
| 223 | Python3 | 240717T022309Z | Ajax1234 |
| 099 | Java JDK | 180920T081622Z | Olivier |
| 078 | JavaScript ES6 | 180921T071723Z | Arnauld |
| 155 | Groovy | 180921T155524Z | archange |
| 098 | Python 3 | 180920T115339Z | Cameron |
| 051 | Charcoal | 180919T225416Z | Neil |
Python3, 223 bytes
import math
def f(n,b):
v={1:2}
for i in range(2,n+1):v[U]=v.get(U:=min(math.ceil(i/2),9),0)+2-(i in[12,14,16,18,19,20])
V={}
for i in b:V[i]=V.get(i,0)+1
return (len(b)<=n+1 or n==1)and all(V[i]<=v.get(i,0)for i in V)
Java (JDK), 99 bytes
s->l->{var r=s.length!=l+1-l/12*(l-10)/2-l/19;for(var z:s)r|=z>(++l>30?9:l+(2<<l/25)>>2);return!r;}
Credits
- Port of Arnauld's JavaScript answer.
However, thel+1-l/12*(l-10)/2-l/19part is a shortening in Java for(l<12?l:l>16?14:l+11>>1)+1which can't be done in JavaScript because it doesn't round to the floor integer.
Previous answer:
Java (JDK 10), 191 bytes
L->S->{int m[]=new int[9],z=0,Z=0,l=0;for(m[0]++;l++<L;z+=--m[z]<1?1:0)m[Z=~-l/2-l/19]+=l<12?2:l>17?1:1+l%2;l=0;for(int s:S){if(--s>Z)l++;Z-=--m[Z>0?Z:0]<1?1:0;}for(int i:m)l|=i;return l==0;}
- Input requirement: the spell list must be ordered from greatest spell levels to the lowest one.
Explanations
L->S->{ // Curried-lambda with 2 parameters: sorcerer-level and spell list
int m[]=new int[9], // Declare variables: m is the max level of each spell.
z=0, // z is the minimum spell level of the maximized spell list.
Z=0, // Z is the maximum spell level for the current level.
l=0; // l is first a level counter, then a reused variable
for(m[0]++;l++<L;z+=--m[z]<1?1:0) // for each level, compute the maximized known spells.
m[Z=~-l/2-l/19]+=l<12?2:l>17?1:1+l%2; //
// Now m is the row for level L in the table below.
l=0; // l now becomes an error indicator
for(int s:S){ // This loop checks if the spell-list matches the spells allowed for that level.
if(--s>Z)l++; // Spell-levels are 1-based, my array is 0-based so decrease s.
Z-=--m[Z>0?Z:0]<1?1:0; // Remove a max level if we've expleted all the spells, avoiding exception.
} //
for(int i:m)l|=i; // Make sure there are no more values in m.
return l==0; // Return true if no miscount were encountered.
}
Table 1: Maximized spell distribution for each sorcerer-level, used from Axoren's answer on the linked question.
Credits
- Saved 14 bytes thanks to Kevin Cruijssen.
JavaScript (ES6), 79 78 bytes
Takes input as (level)(array). Returns \$0\$ or \$1\$.
l=>a=>!a.some(x=>x>(j--,++l>30?9:l+(2<<l/25)>>2),j=l<12?l:l>16?14:l+11>>1)&!~j
Test code
Below is a link to some test code that takes the sorcerer level as input and returns an array of maximum spell levels, using the same logic as the above function.
How?
Reference table
Sorcerer level | # of spells | Maximum spell levels
----------------+-------------+-------------------------------
1 | 2 | 1,1
2 | 3 | 1,1,1
3 | 4 | 1,1,2,2
4 | 5 | 1,2,2,2,2
5 | 6 | 2,2,2,2,3,3
6 | 7 | 2,2,2,3,3,3,3
7 | 8 | 2,2,3,3,3,3,4,4
8 | 9 | 2,3,3,3,3,4,4,4,4
9 | 10 | 3,3,3,3,4,4,4,4,5,5
10 | 11 | 3,3,3,4,4,4,4,5,5,5,5
11 | 12 | 3,3,4,4,4,4,5,5,5,5,6,6
12 | 12 | 3,4,4,4,4,5,5,5,5,6,6,6
13 | 13 | 4,4,4,4,5,5,5,5,6,6,6,7,7
14 | 13 | 4,4,4,5,5,5,5,6,6,6,7,7,7
15 | 14 | 4,4,5,5,5,5,6,6,6,7,7,7,8,8
16 | 14 | 4,5,5,5,5,6,6,6,7,7,7,8,8,8
17 | 15 | 5,5,5,5,6,6,6,7,7,7,8,8,8,9,9
18 | 15 | 5,5,5,6,6,6,7,7,7,8,8,8,9,9,9
19 | 15 | 5,5,6,6,6,7,7,7,8,8,8,9,9,9,9
20 | 15 | 5,6,6,6,7,7,7,8,8,8,9,9,9,9,9
Number of spells
For a sorcerer of level \$L\$, the number of spells \$N_L\$ is given by:
$$N_L=\begin{cases} L+1&\text{if }L<12\\ \lfloor(L+13)/2\rfloor&\text{if }12\le L\le 16\\ 15&\text{if }L>16 \end{cases}$$
In the code, the variable \$j\$ is initialized to \$N_L-1\$ and decremented at each iteration while walking through the input array. Therefore, we expect it to be equal to \$-1\$ at the end of the process.
Maximum spell levels
Given a sorcerer level \$L\$ and a spell index \$1\le i \le N_L\$, the maximum level \$M_{L,i}\$ of the \$i\$-th spell is given by:
$$M_{L,i}=\begin{cases} \lfloor(L+i+2)/4\rfloor&\text{if }L+i<25\\ \lfloor(L+i+4)/4\rfloor&\text{if }25\le L+i\le 30\\ 9&\text{if }L+i>30 \end{cases}$$
Each value \$x\$ of the input array \$a\$ is compared with this upper bound.
Groovy, 155 bytes
def f(int[]a, int b){l=[1]
b.times{n->l[0]=++n%2?n/2+1:n/2
if(n<18&(n<12|n%2>0))l.add(l[0])
l.sort()}
for(i=0;i<a.size();)if(a[i]>l[i++])return false
true}
Generates the best possible spellbook, then checks that the spellbook passed into the method is not better.
Ungolfed, with implicit types made explicit:
boolean spellChecker(int[] a, int b) {
// l will be our best possible spellbook
List<BigDecimal> l = [1]
b.times { n ->
n++ // iterate from 1 to b, not 0 to b-1
l[0] = n % 2 != 0 ? n / 2 + 1 : n / 2 // update the lowest value to the best permitted
if (n < 18 & (n < 12 | n % 2 > 0))
l.add(l[0]) // if permitted, add another best spell
l.sort() // ensure 0th position is always worst, ready for updating next loop
}
for (int i = 0; i < a.size(); i++)
if (a[i] > l[i]) // if the submitted spell is of a higher level
return false // also rejects when l[i] is undefined. (too many spells)
return true
}
Python 3, 98 bytes
v=lambda L,S:(max(S)*2-2<L)&v(L-1,[1]+sorted(S)[:(chr(L*3)in'$*069<')-2])if L>1else(1,1)==tuple(S)
Ungolfed:
def v(L, S):
# recursion base case
if L <= 1:
return tuple(S) == (1, 1)
# if the highest level skill is not valid for the level, then return False.
if max(S)*2 - 2 < L:
return False
# hacky way to determine if the level gets a new skill
has_new_skill = chr(L*3) in '$*069<'
sorted_skills = sorted(S)
# this step removes the highest skill and adds a level 1 skill (replacement)
# if there is a new skill, then it removes the second highest skill as well
new_skills = [1] + sorted_skills[:has_new_skill - 2]
return v(L-1, new_skills)
edit: corrected solution to use correct D&D rules
Charcoal, 51 bytes
Nθ≔⁺✂⭆”)⊟⊞<⁴H”×IκIιθ⎇‹θ¹²⊕⊗θ⁺⁶⁺θ⊘⁺‹θ¹⁹θ¹0θ¬ΣES›ι§θκ
Try it online! Link is to verbose version of code. Takes spell levels in ascending order as a string. Explanation:
Nθ
Input the level.
≔⁺✂⭆”)⊟⊞<⁴H”×IκIιθ⎇‹θ¹²⊕⊗θ⁺⁶⁺θ⊘⁺‹θ¹⁹θ¹0θ
Perform run-length decoding on the string 0544443335 resulting in the string 11111222233334444555566677788899999. This string is then sliced starting at the level (1-indexed) and ending at the doubled level (if less than 12) or 6+1.5*, rounded up, except for level 19, which is rounded down. A 0 is suffixed to ensure that there are not too many spells.
¬ΣES›ι§θκ
Compare the spell levels against the substring and prints a - if none of them are excessive.
