# [Java (JDK)], <s>59</s> 48 bytes

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

    a->b->b<0|b>29|a>b+2&a>21|a>30?0:a<21|a<30&a<b+2

[Try it online!][TIO-jtqb83xy]

[Java (JDK)]: http://jdk.java.net/
[TIO-jtqb83xy]: https://tio.run/##jZhdb@JGFIbv@RVupI2gIchnxp8FU63UjRqpHxeRepPuhUNM4pQABZNtlOW3pwMhH@cZtNkoAh/7YJ/3GXvOO74p78rjm8t/Huvb@WzRBDcu7q2aetIbr6ajpp5Nez/2W/W0qRbjclQFJw@tZVM29Shw@84/n38O/vr42@kvQRE8TKsvTzsfwm647r4NRYdGh1aHkQ5jHSY6THWY6TBHGSwLdQkKE1QmKE1Qm6A4QXWC8gT1GdRnVH3SRWh0aHUY6TDWYaLDVIeZDnOUESJmmShMUJmgNEFtguIE1QnKE9RnUJ/GaDQ3o7kZzc1obkZzM5qb0dyM5mbAzYCbATcDbgbcDLgZcDPgZsDNgJsBNwNuVoOyGpTVoKwGZTUoq0FZDcoClAUoC1AWoCxAWYCyAGUBygKUBSgLUBagIk0m0mQiTSbSZCJNJtJkIpCJQCYCmQhkIpCJQCYCmQhkIpCJQCYCmQhkYo0i1ihijSLWKGKNIgaKGChioIiBIgaKGChioIiBIgaKGChioIiBItHaE6090doTrT2B9gTaE2hPoD2B9gTaE2hPoD2B9gTaE2hPoD3VYlMtNtViU4hNITaF2BRiU4hNITaF2BRiU4hNITaF2BRiM60u0@oyqMugLoO6DOoyqMugLoO6DOoyqMugLoO6DOpyLSeHnBxycsjJISeHnBxycsjJISeHnBxycsjJabHoEYUmUegShTZR6BOFRlHoFIVWUegVhWZR6BbFs4ueMfOcmWfNPG/mmTPPnXn2zPNnnkHzHBotmtALCc2Q0A0J7ZDQDwkNkdARCS2R0BMJTZHQfAjdh9B@CP2H0IAIHYjQggg9iNCECHu9sNkLu72w3Qv7vbDhCzu@sOULG6uwswpbq7C3CpursLsK26uwhwmbmLCLCduYsI8JG5mwWQi7hbBdCPuFsGEI52ThpCyclYXTsnDiE858wqnPcEIx4Z4MvULxllayJ0MvYgwzzJ4Mvc6xzLB7MvRSKGJGtCdDr5ZiZsR7MvSCKmFGsidDr7lSZqR7MvSyLGNG5mdYPXI5M/JNxrrfaj2/tDk5/eP07NdP3nsbvnHwls7y7ZUP/T5NL40gvRLdhdeevR7ndQ5vgvYmRm@G8uYO7zH3HlHvefuOZ@X9@/z9e/T9@@vde2N3K@xe493N6svgtqyn7bNmUU@v3M1RLq6WnYfTaXOyewU4eLv958VNNWqGw2BcPJbHwwv3Pwi/XgxN/rUcXhyZw3JoxG3a8Ofwp3Kw2R7Y8LAcuGOPT7dgMC7ryWpRLYuw3xrPFu3NvsnsS3Ech333PSjc99GR2@o8tAL395xzXV9dF253f7Oxy9ps7tK2qfW0nATb5GJzqP9mz2T725fUJyVB9d/cfVWX3XLUrMrJ6/F6HLRf34d@XCzK@2Vv2Syq8rb9/AB1euX0/veyGV23746Hd@fh56KYHB7enYvbuO50nk9ejMvJsno9d@Wib15g@1r1u8/eLFY8@cuxUCv64flAr/rXyV22n2QX4145n0/u21ueu@3NCHQ6wSvdLeHd4B0d9dX@s/tlU932ZqumN3d3UjNuH3zaXSr4cLkZQzcI81UTtD/Yy27gPjrd4GrWuIN/Tw@6L8OwKaDrrrwbj87rVdatp891a8@13CWaWeNGeldfe9k56L4U686yXj/@Dw "Java (JDK) – Try It Online"

Returns an `Object`, which is the `Integer` `0` for invalid games and the `Boolean`s `true` and `false` for valid ongoing games and for valid finished games respectively. Takes the score ordered (and curried), with the higher score first.

`-2 bytes` by inverting the end-of-match check.  
`-11 bytes` by currying, using bitwise operators, and some return type autoboxing trickery - thanks to @KevinCruijssen

## Ungolfed

    a->                      // Curried: Target type IntFunction<IntFunction<Object>>
        b->                  // Target type IntFunction<Object>
                             // Invalid if:
                b<0          //    Any score is negative
              | b > 29       //    Both scores above 29
              |   a > b + 2  //    Lead too big
                & a > 21     //        and leader has at least 21 points
              | a > 30       //    Anyone has 31 points
            ? 0              // If invalid, return 0 (autoboxed to Integer)
                             // If valid, return whether the game is ongoing (autoboxed to Boolean)
                             // Ongoing if:
            :   a < 21       //    Nobody has 21 points
              |   a < 30     //    Leader has fewer than 30 points
                & a < b + 2  //        and lead is small