#JavaScript (ES6), <s>&nbsp;55 53&nbsp;</s> 48 bytes

<sup>_Thanks to @KevinCruijssen for noticing that I was not fully assuming \$a\le b\$ (saving 5 bytes)_</sup>

Takes input as `(a)(b)` with \$a\le b\$. Returns \$0\$ (valid), \$1\$ (ended) or \$2\$ (invalid).

<!-- language-all: lang-javascript -->

    a=>b=>a<0|a>29|b>30|b>21&b-a>2?2:b>20&b-a>1|b>29

[Try it online!](https://tio.run/##dZFNDsIgEEb3nmJWFhY1MHRhja1noX8GQ2hjjYlJ714HdKGCCyaZ92WGR7jou57bq5luuRu7fh2qVVd1U9X6KBZdY7k0tRJUUG6bnMAJD9SI0EjPy7Ud3TzafmfHM8t61/VdxjefcGAgOEPJf7HEJCbEUMV4z5kSMS7f@Itnd21NB2y@GWvBOJisfvCkGMQ7g69I@tJJ@v55BkZixgW1WCX3AwCyjHVyghQlLgHKfASpyPvSFCYiDAtVakoJ/qpxVISFRfw3Unj5UPn6BA "JavaScript (Node.js) – Try It Online")