@johnmorrisdotca/kyogijo-stadiums 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/NOTICE.md +182 -2
  3. package/README.md +106 -19
  4. package/dist/annotate.js +1 -1
  5. package/dist/arenas-entry.d.ts +4 -0
  6. package/dist/arenas-entry.js +3 -0
  7. package/dist/arenas.d.ts +125 -0
  8. package/dist/arenas.data.d.ts +2 -0
  9. package/dist/arenas.data.js +3763 -0
  10. package/dist/arenas.js +72 -0
  11. package/dist/athletics/describe.d.ts +8 -0
  12. package/dist/athletics/describe.js +41 -0
  13. package/dist/athletics/events.d.ts +17 -0
  14. package/dist/athletics/events.js +48 -0
  15. package/dist/athletics/facilities.d.ts +80 -0
  16. package/dist/athletics/facilities.js +176 -0
  17. package/dist/athletics/infield.d.ts +79 -0
  18. package/dist/athletics/infield.js +166 -0
  19. package/dist/athletics/layout.d.ts +13 -0
  20. package/dist/athletics/layout.js +98 -0
  21. package/dist/athletics/oval.d.ts +57 -0
  22. package/dist/athletics/oval.js +116 -0
  23. package/dist/athletics/plan.d.ts +97 -0
  24. package/dist/athletics/plan.js +355 -0
  25. package/dist/athletics/races.d.ts +102 -0
  26. package/dist/athletics/races.js +355 -0
  27. package/dist/athletics/steeplechase.d.ts +72 -0
  28. package/dist/athletics/steeplechase.js +196 -0
  29. package/dist/athletics/stencil.d.ts +13 -0
  30. package/dist/athletics/stencil.js +85 -0
  31. package/dist/athletics/track.d.ts +54 -0
  32. package/dist/athletics/track.js +105 -0
  33. package/dist/athletics/types.d.ts +77 -0
  34. package/dist/athletics/types.js +1 -0
  35. package/dist/athletics-entry.d.ts +17 -0
  36. package/dist/athletics-entry.js +11 -0
  37. package/dist/athletics.style.d.ts +16 -0
  38. package/dist/athletics.style.js +51 -0
  39. package/dist/atlas-entry.d.ts +6 -2
  40. package/dist/atlas-entry.js +4 -2
  41. package/dist/atlas.d.ts +117 -23
  42. package/dist/atlas.js +197 -12
  43. package/dist/background.js +2 -1
  44. package/dist/budo/describe.d.ts +13 -0
  45. package/dist/budo/describe.js +120 -0
  46. package/dist/budo/dojo.api.d.ts +64 -0
  47. package/dist/budo/dojo.api.js +46 -0
  48. package/dist/budo/dojo.d.ts +72 -0
  49. package/dist/budo/dojo.js +300 -0
  50. package/dist/budo/judo.d.ts +61 -0
  51. package/dist/budo/judo.js +109 -0
  52. package/dist/budo/karate.d.ts +29 -0
  53. package/dist/budo/karate.js +80 -0
  54. package/dist/budo/kendo.d.ts +18 -0
  55. package/dist/budo/kendo.js +44 -0
  56. package/dist/budo/kimarite.d.ts +19 -0
  57. package/dist/budo/kimarite.js +33 -0
  58. package/dist/budo/kit.d.ts +16 -0
  59. package/dist/budo/kit.js +24 -0
  60. package/dist/budo/kyudo.d.ts +28 -0
  61. package/dist/budo/kyudo.js +66 -0
  62. package/dist/budo/looks.d.ts +28 -0
  63. package/dist/budo/looks.js +58 -0
  64. package/dist/budo/parts.d.ts +32 -0
  65. package/dist/budo/parts.js +10 -0
  66. package/dist/budo/plan.d.ts +64 -0
  67. package/dist/budo/plan.js +139 -0
  68. package/dist/budo/room.d.ts +133 -0
  69. package/dist/budo/room.js +111 -0
  70. package/dist/budo/sumo.d.ts +31 -0
  71. package/dist/budo/sumo.js +71 -0
  72. package/dist/budo/tatami.d.ts +55 -0
  73. package/dist/budo/tatami.js +156 -0
  74. package/dist/budo/types.d.ts +192 -0
  75. package/dist/budo/types.js +2 -0
  76. package/dist/budo-entry.d.ts +22 -0
  77. package/dist/budo-entry.js +13 -0
  78. package/dist/budo.board.d.ts +28 -0
  79. package/dist/budo.board.js +81 -0
  80. package/dist/budo.score.d.ts +18 -0
  81. package/dist/budo.score.js +52 -0
  82. package/dist/budo.style.d.ts +6 -0
  83. package/dist/budo.style.js +67 -0
  84. package/dist/charts-entry.d.ts +6 -1
  85. package/dist/charts-entry.js +3 -0
  86. package/dist/charts.athletics.d.ts +183 -0
  87. package/dist/charts.athletics.js +455 -0
  88. package/dist/charts.baseball.js +1 -1
  89. package/dist/charts.curling.heat.d.ts +24 -0
  90. package/dist/charts.curling.heat.js +116 -0
  91. package/dist/charts.curling.js +14 -3
  92. package/dist/charts.js +4 -4
  93. package/dist/charts.pool.d.ts +67 -0
  94. package/dist/charts.pool.js +76 -0
  95. package/dist/charts.skating.d.ts +204 -0
  96. package/dist/charts.skating.js +426 -0
  97. package/dist/charts.soccer.js +3 -3
  98. package/dist/charts.types.d.ts +63 -1
  99. package/dist/colour.d.ts +4 -4
  100. package/dist/colour.js +4 -4
  101. package/dist/court.d.ts +85 -2
  102. package/dist/court.js +102 -7
  103. package/dist/court.more.d.ts +46 -0
  104. package/dist/court.more.js +219 -0
  105. package/dist/courts.style.d.ts +14 -2
  106. package/dist/courts.style.js +51 -4
  107. package/dist/crowd.d.ts +164 -0
  108. package/dist/crowd.draw.d.ts +17 -0
  109. package/dist/crowd.draw.js +204 -0
  110. package/dist/crowd.js +480 -0
  111. package/dist/crowd.park.d.ts +19 -0
  112. package/dist/crowd.park.js +153 -0
  113. package/dist/curling.stats.d.ts +271 -0
  114. package/dist/curling.stats.js +301 -0
  115. package/dist/draw.d.ts +16 -0
  116. package/dist/draw.js +462 -54
  117. package/dist/element-entry.d.ts +3 -1
  118. package/dist/element-entry.js +2 -1
  119. package/dist/element.d.ts +13 -2
  120. package/dist/element.js +79 -4
  121. package/dist/emblems-source.d.ts +50 -0
  122. package/dist/emblems-source.js +56 -0
  123. package/dist/eras.d.ts +3 -1
  124. package/dist/eras.js +8 -3
  125. package/dist/features.js +204 -0
  126. package/dist/field.data.d.ts +16 -0
  127. package/dist/field.data.js +50 -0
  128. package/dist/fields.kit.d.ts +2 -2
  129. package/dist/fields.types.d.ts +24 -4
  130. package/dist/formations.js +18 -7
  131. package/dist/formations.sports.d.ts +8 -0
  132. package/dist/formations.sports.js +251 -0
  133. package/dist/frames.providers.js +71 -8
  134. package/dist/geojson.js +3 -0
  135. package/dist/geometry-entry.d.ts +2 -1
  136. package/dist/geometry-entry.js +2 -1
  137. package/dist/geometry.d.ts +20 -0
  138. package/dist/geometry.js +78 -1
  139. package/dist/grounds.d.ts +4 -0
  140. package/dist/grounds.data.js +12 -0
  141. package/dist/halls.d.ts +65 -0
  142. package/dist/halls.js +122 -0
  143. package/dist/hardwood.d.ts +31 -0
  144. package/dist/hardwood.js +157 -0
  145. package/dist/heat.js +21 -13
  146. package/dist/heat.types.d.ts +5 -0
  147. package/dist/heat.zones.d.ts +4 -2
  148. package/dist/heat.zones.js +207 -7
  149. package/dist/homeside.js +24 -0
  150. package/dist/index.d.ts +30 -4
  151. package/dist/index.js +18 -2
  152. package/dist/layers-entry.d.ts +2 -1
  153. package/dist/layers-entry.js +1 -0
  154. package/dist/layers.d.ts +2 -1
  155. package/dist/layers.env.d.ts +12 -1
  156. package/dist/layers.env.js +36 -4
  157. package/dist/layers.js +32 -13
  158. package/dist/layers.types.d.ts +9 -2
  159. package/dist/leagues/athletics.d.ts +63 -0
  160. package/dist/leagues/athletics.js +87 -0
  161. package/dist/leagues/budo.d.ts +196 -0
  162. package/dist/leagues/budo.js +105 -0
  163. package/dist/leagues/courts.d.ts +269 -4
  164. package/dist/leagues/courts.js +155 -1
  165. package/dist/leagues/hockey.js +41 -19
  166. package/dist/leagues/skating.d.ts +145 -0
  167. package/dist/leagues/skating.js +73 -0
  168. package/dist/leagues/sources.js +41 -0
  169. package/dist/leagues/types.d.ts +1 -1
  170. package/dist/leagues-entry.d.ts +4 -2
  171. package/dist/leagues-entry.js +2 -1
  172. package/dist/leagues.d.ts +17 -4
  173. package/dist/leagues.js +246 -5
  174. package/dist/lineup.codes.d.ts +23 -0
  175. package/dist/lineup.codes.js +122 -0
  176. package/dist/logo.d.ts +25 -0
  177. package/dist/logo.js +47 -0
  178. package/dist/look.d.ts +3 -3
  179. package/dist/look.js +39 -6
  180. package/dist/outline.d.ts +1 -1
  181. package/dist/outline.js +46 -4
  182. package/dist/pageant.d.ts +120 -0
  183. package/dist/pageant.draw.d.ts +21 -0
  184. package/dist/pageant.draw.js +171 -0
  185. package/dist/pageant.js +211 -0
  186. package/dist/pageant.style.d.ts +8 -0
  187. package/dist/pageant.style.js +42 -0
  188. package/dist/png.d.ts +8 -1
  189. package/dist/png.js +21 -1
  190. package/dist/pointer-entry.d.ts +2 -0
  191. package/dist/pointer-entry.js +2 -0
  192. package/dist/pointer.d.ts +113 -0
  193. package/dist/pointer.js +151 -0
  194. package/dist/pool.d.ts +176 -0
  195. package/dist/pool.figures.d.ts +306 -0
  196. package/dist/pool.figures.js +148 -0
  197. package/dist/pool.js +304 -0
  198. package/dist/pool.kit.d.ts +48 -0
  199. package/dist/pool.kit.js +141 -0
  200. package/dist/pool.labels.d.ts +20 -0
  201. package/dist/pool.labels.js +258 -0
  202. package/dist/pool.race.d.ts +65 -0
  203. package/dist/pool.race.js +140 -0
  204. package/dist/pool.replay.d.ts +46 -0
  205. package/dist/pool.replay.js +127 -0
  206. package/dist/pool.section.d.ts +13 -0
  207. package/dist/pool.section.js +83 -0
  208. package/dist/pool.style.d.ts +20 -0
  209. package/dist/pool.style.js +169 -0
  210. package/dist/pool.types.d.ts +145 -0
  211. package/dist/pool.types.js +3 -0
  212. package/dist/pool.words.d.ts +13 -0
  213. package/dist/pool.words.js +101 -0
  214. package/dist/ranges.names.js +53 -3
  215. package/dist/replay-entry.d.ts +3 -0
  216. package/dist/replay-entry.js +2 -0
  217. package/dist/restyle.js +1 -1
  218. package/dist/road.draw.js +3 -2
  219. package/dist/road.js +2 -1
  220. package/dist/road.types.d.ts +3 -0
  221. package/dist/rules.d.ts +138 -0
  222. package/dist/rules.js +511 -0
  223. package/dist/rules.types.d.ts +4 -0
  224. package/dist/rules.types.js +64 -0
  225. package/dist/score.d.ts +3 -0
  226. package/dist/score.js +93 -6
  227. package/dist/sheet.d.ts +3 -0
  228. package/dist/sheet.js +7 -3
  229. package/dist/situation.d.ts +135 -0
  230. package/dist/situation.draw.d.ts +34 -0
  231. package/dist/situation.draw.js +202 -0
  232. package/dist/situation.js +337 -0
  233. package/dist/situation.style.d.ts +2 -0
  234. package/dist/situation.style.js +45 -0
  235. package/dist/situation.types.d.ts +77 -0
  236. package/dist/situation.types.js +3 -0
  237. package/dist/situation.widgets.d.ts +39 -0
  238. package/dist/situation.widgets.js +129 -0
  239. package/dist/skating/describe.d.ts +7 -0
  240. package/dist/skating/describe.js +44 -0
  241. package/dist/skating/events.d.ts +24 -0
  242. package/dist/skating/events.js +47 -0
  243. package/dist/skating/figure.d.ts +24 -0
  244. package/dist/skating/figure.js +37 -0
  245. package/dist/skating/long.d.ts +54 -0
  246. package/dist/skating/long.js +111 -0
  247. package/dist/skating/parts.d.ts +43 -0
  248. package/dist/skating/parts.js +40 -0
  249. package/dist/skating/plan.d.ts +55 -0
  250. package/dist/skating/plan.js +197 -0
  251. package/dist/skating/short.d.ts +47 -0
  252. package/dist/skating/short.js +89 -0
  253. package/dist/skating/track.d.ts +66 -0
  254. package/dist/skating/track.js +94 -0
  255. package/dist/skating/types.d.ts +57 -0
  256. package/dist/skating/types.js +3 -0
  257. package/dist/skating-entry.d.ts +17 -0
  258. package/dist/skating-entry.js +11 -0
  259. package/dist/skating.style.d.ts +4 -0
  260. package/dist/skating.style.js +24 -0
  261. package/dist/strings.d.ts +470 -0
  262. package/dist/strings.js +674 -13
  263. package/dist/style.d.ts +2 -0
  264. package/dist/style.js +19 -2
  265. package/dist/surfaces/artistic.d.ts +9 -0
  266. package/dist/surfaces/artistic.js +94 -0
  267. package/dist/surfaces/athletics.d.ts +16 -0
  268. package/dist/surfaces/athletics.js +132 -0
  269. package/dist/surfaces/baseball.js +17 -0
  270. package/dist/surfaces/basketball.floor.d.ts +27 -0
  271. package/dist/surfaces/basketball.floor.js +83 -0
  272. package/dist/surfaces/basketball.gear.d.ts +27 -0
  273. package/dist/surfaces/basketball.gear.js +90 -0
  274. package/dist/surfaces/basketball.js +44 -22
  275. package/dist/surfaces/budo.d.ts +6 -0
  276. package/dist/surfaces/budo.js +104 -0
  277. package/dist/surfaces/curling.d.ts +16 -0
  278. package/dist/surfaces/curling.fold.d.ts +67 -0
  279. package/dist/surfaces/curling.fold.js +107 -0
  280. package/dist/surfaces/curling.js +37 -3
  281. package/dist/surfaces/dive.d.ts +9 -0
  282. package/dist/surfaces/dive.js +128 -0
  283. package/dist/surfaces/field.d.ts +7 -2
  284. package/dist/surfaces/field.js +15 -9
  285. package/dist/surfaces/football.js +7 -0
  286. package/dist/surfaces/hockey.js +4 -2
  287. package/dist/surfaces/net.d.ts +2 -1
  288. package/dist/surfaces/net.js +160 -15
  289. package/dist/surfaces/polo.d.ts +12 -0
  290. package/dist/surfaces/polo.js +159 -0
  291. package/dist/surfaces/pool.d.ts +27 -0
  292. package/dist/surfaces/pool.js +198 -0
  293. package/dist/surfaces/skating.d.ts +6 -0
  294. package/dist/surfaces/skating.js +62 -0
  295. package/dist/surfaces/soccer.js +2 -1
  296. package/dist/surfaces/surface.d.ts +76 -0
  297. package/dist/surfaces/venue.d.ts +15 -0
  298. package/dist/surfaces/venue.js +95 -0
  299. package/dist/target-entry.d.ts +2 -0
  300. package/dist/target-entry.js +2 -0
  301. package/dist/target.d.ts +200 -0
  302. package/dist/target.js +525 -0
  303. package/dist/team.common.d.ts +1 -1
  304. package/dist/team.common.js +3 -3
  305. package/dist/team.formation.d.ts +3 -1
  306. package/dist/team.formation.js +3 -3
  307. package/dist/team.layers.d.ts +2 -2
  308. package/dist/team.layers.js +4 -1
  309. package/dist/team.lineup.d.ts +27 -0
  310. package/dist/team.lineup.js +207 -0
  311. package/dist/team.network.js +6 -5
  312. package/dist/team.shape.js +5 -5
  313. package/dist/team.types.d.ts +40 -1
  314. package/dist/tenants.d.ts +77 -0
  315. package/dist/tenants.data.d.ts +8 -0
  316. package/dist/tenants.data.js +1793 -0
  317. package/dist/tenants.js +46 -0
  318. package/dist/turn-entry.d.ts +12 -0
  319. package/dist/turn-entry.js +7 -0
  320. package/dist/turn.camera.d.ts +116 -0
  321. package/dist/turn.camera.js +184 -0
  322. package/dist/turn.dom.d.ts +40 -0
  323. package/dist/turn.dom.js +353 -0
  324. package/dist/turn.kit.d.ts +86 -0
  325. package/dist/turn.kit.js +110 -0
  326. package/dist/turn.markup.d.ts +48 -0
  327. package/dist/turn.markup.js +108 -0
  328. package/dist/turn.model.d.ts +78 -0
  329. package/dist/turn.model.js +91 -0
  330. package/dist/turn.style.d.ts +5 -0
  331. package/dist/turn.style.js +56 -0
  332. package/dist/types.d.ts +221 -20
  333. package/dist/units.d.ts +1 -1
  334. package/dist/units.js +22 -1
  335. package/dist/uprights.board.d.ts +17 -0
  336. package/dist/uprights.board.js +59 -0
  337. package/dist/uprights.budo.d.ts +17 -0
  338. package/dist/uprights.budo.js +87 -0
  339. package/dist/uprights.d.ts +37 -0
  340. package/dist/uprights.fields.d.ts +32 -0
  341. package/dist/uprights.fields.js +172 -0
  342. package/dist/uprights.goal.d.ts +49 -0
  343. package/dist/uprights.goal.js +69 -0
  344. package/dist/uprights.js +169 -0
  345. package/dist/uprights.more.d.ts +7 -0
  346. package/dist/uprights.more.js +183 -0
  347. package/dist/uprights.net.d.ts +12 -0
  348. package/dist/uprights.net.js +109 -0
  349. package/dist/uprights.netkit.d.ts +28 -0
  350. package/dist/uprights.netkit.js +67 -0
  351. package/dist/uprights.pools.d.ts +8 -0
  352. package/dist/uprights.pools.js +190 -0
  353. package/dist/uprights.rinks.d.ts +27 -0
  354. package/dist/uprights.rinks.js +106 -0
  355. package/dist/uprights.track.d.ts +50 -0
  356. package/dist/uprights.track.js +246 -0
  357. package/dist/version.d.ts +1 -1
  358. package/dist/version.js +1 -1
  359. package/dist/zones-entry.d.ts +2 -0
  360. package/dist/zones-entry.js +2 -0
  361. package/package.json +56 -3
package/dist/rules.js ADDED
@@ -0,0 +1,511 @@
1
+ // The rulebook as code: where a point on a surface lies in the sport's own terms. `zoneAt(sport, point, options)` answers with the zone (the offensive zone,
2
+ // the frontcourt, the attacking third, the infield, the red zone), the finer area in it (the crease, the paint, the six-yard box, the warning track,
3
+ // between the hashes) and every other area that holds, with the id of each. The geometry is the package's own: a rink's blue lines and creases from
4
+ // `rinkOf`, a court's keys and arcs from `courtOf`, a pitch's boxes from `soccerSpec`, a ballpark's fence from `fenceFor`, a field's end zones and hashes
5
+ // from `footballIn`. Nothing is drawn here, and no hand-made polygon stands in for a rule: where a rule has no figure of its own (the slot, the
6
+ // half-spaces) the package's zone sets (heat.zones.ts) are used, and a test holds the two to the same answer. A sport with no rules of its own here answers
7
+ // in the zone sets of its sport (`ZONE_SETS`).
8
+ //
9
+ // A point is a pair `[x, y]` or `{ x, y }` in the frame of `options.frame` (a provider's, or the drawing's own in `units`, feet by default). The team is
10
+ // taken to attack the right end of the surface as it is drawn wide; `attacking: "left"` says the numbers are of a team that attacks the left, and they are
11
+ // turned a half turn first, as the data layers do.
12
+ import { chooseLeague, courtOf, diamondOf, fieldOf, rinkOf } from "./leagues.js";
13
+ import { footballIn, rulesFor } from "./eras.js";
14
+ import { FEET_PER_METRE, MLB, NBA, fenceAt, footballLength } from "./geometry.js";
15
+ import { NBA_COURT } from "./leagues/basketball.js";
16
+ import { NHL_RINK } from "./leagues/hockey.js";
17
+ import { diamondFence } from "./leagues/baseball.js";
18
+ import { frameByName, toSurface } from "./frames.js";
19
+ import "./frames.providers.js";
20
+ import "./surfaces/soccer-providers.js";
21
+ import { buildZoneSet, infieldReach, ZONE_SETS, ZONE_SET_IDS } from "./heat.zones.js";
22
+ import { feetFence, lengthUnit } from "./common.js";
23
+ import { fenceFor, parkById, parkWallsIn, PARKS } from "./parks.js";
24
+ import { frameSizeOf, outlineOf } from "./outline.js";
25
+ import { soccerSpec } from "./surfaces/soccer-spec.js";
26
+ import { KYOGIJO_STRINGS } from "./strings.js";
27
+ import { FEET_PER, isUnit } from "./units.js";
28
+ export { RULE_IDS } from "./rules.types.js";
29
+ const PICK = ["league", "year", "pitch", "park", "fence", "units", "sheet", "net", "field", "pool", "athletics", "skating"];
30
+ const cache = new Map();
31
+ const num = (value) => typeof value === "number" && Number.isFinite(value);
32
+ function placeOf(point) {
33
+ const xy = Array.isArray(point) ? point : [point.x, point.y];
34
+ const [x, y] = xy;
35
+ if (!num(x) || !num(y))
36
+ throw new TypeError("a point is [x, y] or { x, y }, two finite numbers");
37
+ return [x, y];
38
+ }
39
+ // ----- hockey
40
+ function rinkFigures(o, league) {
41
+ if (league?.family === "hockey")
42
+ return rinkOf(league, o.year);
43
+ const era = rulesFor("nhl", o.year).rules;
44
+ return { ...NHL_RINK, goalLine: era.goalLine, blueLine: era.blueLine, trapezoid: era.trapezoid };
45
+ }
46
+ function hockeyJudge(o, league) {
47
+ const rink = rinkFigures(o, league);
48
+ const { length: L, width: W, goalLine: g, blueLine: blue } = rink;
49
+ const mid = W / 2;
50
+ const post = rink.net.width / 2;
51
+ const dots = g + rink.endSpotFromGoalLine;
52
+ const inner = rink.spotOffset - rink.circleRadius;
53
+ const top = dots + rink.circleRadius;
54
+ return (x, y) => {
55
+ const flags = [];
56
+ const zone = x < blue ? "defensive-zone" : x > L - blue ? "offensive-zone" : "neutral-zone";
57
+ const local = x > L / 2 ? L - x : x;
58
+ const dy = Math.abs(y - mid);
59
+ const u = local - g;
60
+ let sub;
61
+ if (u >= 0 && dy <= rink.crease.halfWidth && Math.hypot(u, dy) <= rink.crease.radius) {
62
+ flags.push("crease");
63
+ sub = "crease";
64
+ }
65
+ if (u < 0) {
66
+ flags.push("behind-goal-line");
67
+ const t = rink.trapezoid;
68
+ if (t !== null && local >= 0 && dy <= t.atGoalLine / 2 + ((g - local) / g) * ((t.atBoards - t.atGoalLine) / 2))
69
+ flags.push("trapezoid");
70
+ sub = sub ?? "behind-goal-line";
71
+ }
72
+ // The slot, as the package's zone set defines it (heat.zones.ts, "nhl-slot"): the inner slot from the goal line out to the dots between the posts and the circles' inner edges, the outer slot from the dots to the circles' tops.
73
+ if (local >= g && local < dots && dy <= post + ((local - g) / (dots - g)) * (inner - post)) {
74
+ flags.push("inner-slot", "slot");
75
+ sub = sub ?? "inner-slot";
76
+ }
77
+ else if (local >= dots && local <= top && dy <= inner) {
78
+ flags.push("outer-slot", "slot");
79
+ sub = sub ?? "outer-slot";
80
+ }
81
+ if (Math.hypot(local - dots, dy - rink.spotOffset) <= rink.circleRadius) {
82
+ flags.push("faceoff-circle");
83
+ sub = sub ?? "faceoff-circle";
84
+ }
85
+ else if (Math.hypot(x - L / 2, y - mid) <= rink.circleRadius) {
86
+ flags.push("centre-circle");
87
+ sub = sub ?? "centre-circle";
88
+ }
89
+ return { zone, subzone: sub, flags };
90
+ };
91
+ }
92
+ // ----- basketball
93
+ /** The court's figures in a season, with the NBA's own history laid over the NBA's court. */
94
+ function courtFigures(o, league) {
95
+ if (league?.family === "basketball")
96
+ return courtOf(league, o.year);
97
+ const era = rulesFor("nba", o.year).rules;
98
+ const three = era.threePoint === null ? null : { radius: era.threePoint.radius, sideInset: NBA_COURT.threePoint?.sideInset ?? NBA.threePoint.sideInset };
99
+ return { ...NBA_COURT, laneWidth: era.keyWidth, threePoint: three, restricted: era.restrictedArea ? NBA_COURT.restricted : null };
100
+ }
101
+ /** The three-point line: the straight lines' inset from the sidelines and where the arc meets them, from the baseline. `null` for a court with no line. */
102
+ function threeLine(court) {
103
+ if (court.threePoint === null)
104
+ return null;
105
+ const { radius, sideInset } = court.threePoint;
106
+ const half = court.width / 2 - sideInset;
107
+ return { radius, inset: sideInset, join: court.basket + Math.sqrt(Math.max(0, radius * radius - half * half)) };
108
+ }
109
+ function basketJudge(o, league) {
110
+ const court = courtFigures(o, league);
111
+ const { length: L, width: W } = court;
112
+ const mid = W / 2;
113
+ const three = threeLine(court);
114
+ return (x, y) => {
115
+ const flags = [];
116
+ const front = x > L / 2;
117
+ const zone = front ? "frontcourt" : "backcourt";
118
+ // The basket the team attacks is at the right end: a point is measured from it wherever it lies on the court.
119
+ const local = L - x;
120
+ const dy = y - mid;
121
+ const dist = Math.hypot(local - court.basket, dy);
122
+ let isThree = false;
123
+ let corner = false;
124
+ if (three !== null) {
125
+ if (local <= three.join) {
126
+ isThree = Math.abs(dy) > mid - three.inset;
127
+ corner = isThree;
128
+ }
129
+ else
130
+ isThree = dist > three.radius;
131
+ }
132
+ let sub;
133
+ if (front) {
134
+ // The lane may be wider at the baseline than at the free-throw line (a trapezoid): half its width at this distance from the baseline.
135
+ const end = court.laneEndWidth ?? court.laneWidth;
136
+ const half = (court.freeThrowLine <= 0 ? court.laneWidth : end + ((court.laneWidth - end) * Math.min(Math.max(local, 0), court.freeThrowLine)) / court.freeThrowLine) / 2;
137
+ if (court.restricted !== null && dist <= court.restricted)
138
+ sub = "restricted-area";
139
+ else if (local <= court.freeThrowLine && Math.abs(dy) <= half)
140
+ sub = "paint";
141
+ else if (isThree)
142
+ sub = corner ? (dy < 0 ? "corner-three-left" : "corner-three-right") : "above-the-break";
143
+ else
144
+ sub = "mid-range";
145
+ if (court.restricted !== null && dist <= court.restricted)
146
+ flags.push("restricted-area");
147
+ if (local <= court.freeThrowLine && Math.abs(dy) <= half)
148
+ flags.push("paint");
149
+ }
150
+ if (isThree)
151
+ flags.push("three-point");
152
+ if (front && sub !== undefined && !flags.includes(sub))
153
+ flags.push(sub);
154
+ return { zone, subzone: sub, flags };
155
+ };
156
+ }
157
+ // ----- soccer
158
+ function soccerJudge(o, outline) {
159
+ const spec = soccerSpec(o.pitch, o.units === undefined ? "m" : lengthUnit(o));
160
+ const L = outline.box.w;
161
+ const W = outline.box.h;
162
+ const mid = W / 2;
163
+ const k = FEET_PER_METRE;
164
+ const pd = spec.penaltyDepth * k;
165
+ const pw = spec.penaltyWidth * k;
166
+ const gd = spec.goalAreaDepth * k;
167
+ const gw = (spec.goalAreaWidth > 0 ? spec.goalAreaWidth : spec.goalWidth) * k;
168
+ const spot = spec.spot * k;
169
+ const arc = spec.arcRadius * k;
170
+ const lanes = [(W - pw) / 2, (W - gw) / 2, (W + gw) / 2, (W + pw) / 2];
171
+ const names = ["wing-left", "half-space-left", "central-corridor", "half-space-right", "wing-right"];
172
+ return (x, y) => {
173
+ const flags = [];
174
+ const zone = x < L / 3 ? "defensive-third" : x > (2 * L) / 3 ? "attacking-third" : "middle-third";
175
+ const attacked = x > L / 2;
176
+ const local = attacked ? L - x : x;
177
+ const dy = Math.abs(y - mid);
178
+ const own = attacked ? "" : "own-";
179
+ const inArea = spec.area === "semicircle" ? Math.hypot(local, y - mid) <= pd : local <= pd && dy <= pw / 2;
180
+ let sub;
181
+ if (gd > 0 && spec.goalAreaWidth > 0 && local <= gd && dy <= gw / 2) {
182
+ flags.push(`${own}six-yard-box`);
183
+ sub = `${own}six-yard-box`;
184
+ }
185
+ if (inArea) {
186
+ flags.push(`${own}penalty-area`);
187
+ sub = sub ?? `${own}penalty-area`;
188
+ }
189
+ else if (spot > 0 && arc > 0 && local <= spot + arc && Math.hypot(local - spot, y - mid) <= arc) {
190
+ // The D: the part of the penalty mark's circle outside the penalty area.
191
+ flags.push(`${own}penalty-arc`);
192
+ sub = sub ?? `${own}penalty-arc`;
193
+ }
194
+ // Left and right are the attacker's: facing the right end, left is the top of the drawing.
195
+ const lane = lanes.filter((edge) => y >= edge).length;
196
+ flags.push(names[lane]);
197
+ sub = sub ?? names[lane];
198
+ return { zone, subzone: sub, flags };
199
+ };
200
+ }
201
+ // ----- baseball
202
+ /** The wall height at a bearing: the stretch of the park's fence that covers it in the season, in feet, or `null` where the park's data holds none. */
203
+ export function wallHeightAt(park, angle, year) {
204
+ const found = parkWallsIn(park, year).filter((wall) => angle >= wall.from && angle <= wall.to);
205
+ if (found.length === 0)
206
+ return null;
207
+ // Where stretches overlap (a short wall inside a long one), the narrower stretch is the more particular.
208
+ found.sort((a, b) => a.to - a.from - (b.to - b.from));
209
+ return found[0].height_ft;
210
+ }
211
+ function baseJudge(o, league) {
212
+ const generic = league?.family === "baseball" ? diamondFence(diamondOf(league, o.year)) : undefined;
213
+ const points = fenceFor(parkById(o.park), feetFence(o.fence, lengthUnit(o)), o.year, generic);
214
+ const track = parkById(o.park)?.track_ft ?? MLB.warningTrack;
215
+ return (x, y) => {
216
+ const flags = [];
217
+ // The foul lines are the fair territory's edges, and a ball on one is fair: fair is out from home plate between them.
218
+ const fair = y < 0 && Math.abs(x) <= -y;
219
+ if (!fair)
220
+ return { zone: "foul-territory", flags: ["foul-territory"] };
221
+ flags.push("fair-territory");
222
+ const angle = (Math.atan2(x, -y) * 180) / Math.PI;
223
+ const r = Math.hypot(x, y);
224
+ const fence = fenceAt(points, angle);
225
+ const sector = angle < -15 ? 0 : angle > 15 ? 2 : 1;
226
+ if (r > fence)
227
+ return { zone: "over-the-wall", subzone: ["left-field", "centre-field", "right-field"][sector], flags: ["fair-territory", "over-the-wall"] };
228
+ if (r <= infieldReach(angle)) {
229
+ const side = ["third-base-side", "middle-infield", "first-base-side"][sector];
230
+ flags.push("infield", side);
231
+ return { zone: "infield", subzone: side, flags };
232
+ }
233
+ const field = ["left-field", "centre-field", "right-field"][sector];
234
+ flags.push("outfield", field);
235
+ let sub = field;
236
+ if (r >= fence - track) {
237
+ flags.push("warning-track");
238
+ sub = "warning-track";
239
+ }
240
+ return { zone: "outfield", subzone: sub, flags };
241
+ };
242
+ }
243
+ // ----- football
244
+ function footballJudge(o, sport, league) {
245
+ const spec = league?.family === "football" ? fieldOf(league, o.year) : footballIn(sport, o.year);
246
+ const L = footballLength(spec);
247
+ const ez = spec.endZone;
248
+ const W = spec.width;
249
+ const red = 60;
250
+ return (x, y) => {
251
+ const flags = [];
252
+ let zone;
253
+ if (x < ez)
254
+ zone = "own-end-zone";
255
+ else if (x > L - ez)
256
+ zone = "opponent-end-zone";
257
+ else if (x >= L - ez - red)
258
+ zone = "red-zone";
259
+ else
260
+ zone = x < L / 2 ? "own-half" : "opponent-half";
261
+ flags.push(zone);
262
+ if (zone.endsWith("end-zone"))
263
+ flags.push("end-zone");
264
+ if (zone === "red-zone")
265
+ flags.push("red-zone");
266
+ let sub;
267
+ if (y >= spec.hash && y <= W - spec.hash)
268
+ sub = "between-the-hashes";
269
+ // Facing the right end, the offence's left is the top of the drawing.
270
+ else
271
+ sub = y < spec.hash ? "outside-hashes-left" : "outside-hashes-right";
272
+ flags.push(sub);
273
+ return { zone, subzone: sub, flags };
274
+ };
275
+ }
276
+ // ----- the package's own zone sets, for every other sport
277
+ function contextFor(o, outline, language) {
278
+ return { o, outline, direction: "right", end: "both", los: undefined, bats: undefined, words: KYOGIJO_STRINGS[language].layers.zones };
279
+ }
280
+ function setsFor(sport, o, outline, language) {
281
+ const out = [];
282
+ for (const id of ZONE_SET_IDS) {
283
+ if (!ZONE_SETS[id].sports.includes(sport))
284
+ continue;
285
+ // The sets a sport has two ends for are built for both; a set the sport's options cannot make (a pool set for a pool with none) is left out.
286
+ try {
287
+ out.push(buildZoneSet(id, contextFor(o, outline, language)));
288
+ }
289
+ catch {
290
+ // A set that cannot be made for these options has no say.
291
+ }
292
+ }
293
+ return out;
294
+ }
295
+ function setsJudge(sets) {
296
+ return (x, y) => {
297
+ const found = [];
298
+ for (const set of sets()) {
299
+ const i = set.which(x, y);
300
+ if (i >= 0)
301
+ found.push({ id: set.zones[i].id, name: set.zones[i].name });
302
+ }
303
+ return { zone: found[0]?.id, subzone: found[1]?.id, flags: found.map((f) => f.id), names: Object.fromEntries(found.map((f) => [f.id, f.name])) };
304
+ };
305
+ }
306
+ function ruled(sport, options) {
307
+ const language = options.language === "ja" ? "ja" : "en";
308
+ const surface = { sport };
309
+ for (const key of PICK)
310
+ if (options[key] !== undefined)
311
+ surface[key] = options[key];
312
+ const key = JSON.stringify([surface, language]);
313
+ const hit = cache.get(key);
314
+ if (hit !== undefined)
315
+ return hit;
316
+ const o = surface;
317
+ const { sport: drawn, league } = chooseLeague(o);
318
+ const outline = outlineOf({ ...o, sport: drawn });
319
+ let sets;
320
+ const lazy = () => (sets ?? (sets = setsFor(drawn, { ...o, sport: drawn }, outline, language)));
321
+ let judge;
322
+ switch (drawn) {
323
+ case "nhl":
324
+ judge = hockeyJudge(o, league);
325
+ break;
326
+ case "nba":
327
+ judge = basketJudge(o, league);
328
+ break;
329
+ case "soccer":
330
+ judge = soccerJudge(o, outline);
331
+ break;
332
+ case "mlb":
333
+ judge = baseJudge(o, league);
334
+ break;
335
+ case "nfl":
336
+ case "cfl":
337
+ case "ifaf":
338
+ judge = footballJudge(o, drawn, league);
339
+ break;
340
+ default:
341
+ judge = setsJudge(lazy);
342
+ }
343
+ const made = { sport: drawn, league: typeof options.league === "string" ? options.league : undefined, o: { ...o, sport: drawn }, outline, judge, language, sets: lazy };
344
+ if (cache.size > 200)
345
+ cache.clear();
346
+ cache.set(key, made);
347
+ return made;
348
+ }
349
+ /** The point on the surface, in feet in the drawing's wide frame with the team attacking the right. */
350
+ function onSurface(r, point, options) {
351
+ const [px, py] = placeOf(point);
352
+ const unit = options.units !== undefined && isUnit(options.units) ? options.units : "ft";
353
+ if (options.frame === undefined) {
354
+ const k = FEET_PER[unit];
355
+ const p = [px * k, py * k];
356
+ return options.attacking === "left" ? [r.outline.box.x * 2 + r.outline.box.w - p[0], r.outline.box.y * 2 + r.outline.box.h - p[1]] : p;
357
+ }
358
+ const frame = typeof options.frame === "string" ? frameByName(options.frame) : options.frame;
359
+ const size = options.size ?? frameSizeOf(r.o, r.outline.box);
360
+ const sized = size === undefined ? undefined : { length: size.length, width: size.width, unit: "ft" };
361
+ const [x, y] = toSurface([[px, py]], { from: frame, size: sized ?? options.size, attacking: options.attacking })[0];
362
+ return [x, y];
363
+ }
364
+ /** The leagues whose rule book words some zones another way than the NBA's: FIBA's, which the Japan Basketball Association follows. */
365
+ const FIBA_WORDS = new Set(["fiba"]);
366
+ const nameOf = (id, language, own, league) => {
367
+ if (own?.[id] !== undefined)
368
+ return own[id];
369
+ const words = KYOGIJO_STRINGS[language];
370
+ if (league !== undefined && FIBA_WORDS.has(league) && words.rulesFiba[id] !== undefined)
371
+ return words.rulesFiba[id];
372
+ return words.rules[id] ?? id;
373
+ };
374
+ /**
375
+ * Where a point lies by the rules of a sport: the zone, the area in it and every other area that holds, each by id and name. Hockey answers in the
376
+ * offensive, neutral and defensive zones with the crease, the trapezoid, the slot, the face-off circles and behind the goal line; basketball in the
377
+ * frontcourt and backcourt with the restricted area, the paint, the mid-range, the corner threes and the arc; soccer in thirds with the six-yard box,
378
+ * the penalty area, the D, the half-spaces and the wings; baseball in the infield, the outfield, foul territory, the warning track and over the
379
+ * wall by the park's own fence; football in the end zones, the halves, the red zone and between the hashes. Every other sport answers in its zone sets.
380
+ * @example
381
+ * ```ts
382
+ * import { zoneAt } from "@johnmorrisdotca/kyogijo-stadiums/zones";
383
+ * // The NHL API's (69, 22) is the face-off dot in the right end zone: the offensive zone, inside a face-off circle.
384
+ * const dot = zoneAt("nhl", [69, 22], { frame: "nhl-api" });
385
+ * console.log(dot.zone, dot.subzone, dot.zones.includes("faceoff-circle"));
386
+ * // offensive-zone faceoff-circle true
387
+ * ```
388
+ */
389
+ export function zoneAt(sport, point, options = {}) {
390
+ const r = ruled(sport, options);
391
+ return answer(r, onSurface(r, point, options));
392
+ }
393
+ /** `zoneAt` for a place already on the surface: feet in the drawing's wide frame, the team attacking the right. What a drawing's click is asked with (pointer.ts). */
394
+ export function zoneAtSurface(sport, at, options = {}) {
395
+ return answer(ruled(sport, options), [at[0], at[1]]);
396
+ }
397
+ function answer(r, at) {
398
+ const inBounds = r.outline.contains(at[0], at[1]);
399
+ const open = r.sport === "mlb" || inBounds;
400
+ const v = open ? r.judge(at[0], at[1]) : { flags: [] };
401
+ const zones = [...new Set([...(v.zone === undefined ? [] : [v.zone]), ...(v.subzone === undefined ? [] : [v.subzone]), ...v.flags])];
402
+ const sets = {};
403
+ if (open) {
404
+ for (const set of r.sets()) {
405
+ const i = set.which(at[0], at[1]);
406
+ if (i >= 0)
407
+ sets[set.id] = set.zones[i].id;
408
+ }
409
+ }
410
+ const names = {};
411
+ for (const id of zones)
412
+ names[id] = nameOf(id, r.language, v.names, r.league);
413
+ return { sport: r.sport, at, inBounds, zone: v.zone, subzone: v.subzone, zones, sets, names };
414
+ }
415
+ /**
416
+ * A function from a place on the surface (feet, the drawing's wide frame, the team attacking the right) to the id of the finest zone it lies in: what a data
417
+ * layer's marks carry as `data-zone`. Built once for the options of a drawing; `undefined` where the sport has no zone there.
418
+ */
419
+ export function zoneResolver(sport, options = {}) {
420
+ const r = ruled(sport, options);
421
+ return (x, y) => {
422
+ if (r.sport !== "mlb" && !r.outline.contains(x, y))
423
+ return undefined;
424
+ const v = r.judge(x, y);
425
+ return v.subzone ?? v.zone;
426
+ };
427
+ }
428
+ /**
429
+ * The name of a zone id in a language: the rules engine's own ids have words in both; any other id (a zone set's) comes back as it is. A court of `league: "fiba"` has the words of FIBA's rule book, which the
430
+ * Japan Basketball Association follows: the restricted area is the no-charge semicircle (ノーチャージセミサークル); in the NBA and the leagues that follow its words it is the restricted area (リストリクテッドエリア).
431
+ */
432
+ export const zoneName = (id, language = "en", league) => nameOf(id, language === "ja" ? "ja" : "en", undefined, league);
433
+ const holds = (sport, id) => (point, options = {}) => zoneAt(sport, point, options).zones.includes(id);
434
+ /** True when a shot from the place would count three: beyond the three-point line (the arc, or past the straight lines at the sidelines), at the basket the team attacks. */
435
+ export const isThreePointer = holds("nba", "three-point");
436
+ /** True when the place is in the paint (the free-throw lane, the key), outside the restricted area. */
437
+ export const inPaint = (point, options = {}) => {
438
+ const a = zoneAt("nba", point, options);
439
+ return a.zones.includes("paint");
440
+ };
441
+ /** True when the place is in the restricted area under the basket. */
442
+ export const inRestrictedArea = holds("nba", "restricted-area");
443
+ /** True when the place is in the slot (the package's definition: the inner and outer slot in front of the net, between the face-off circles), at either end. */
444
+ export const inSlot = holds("nhl", "slot");
445
+ /** True when the place is in a goal crease. */
446
+ export const inCrease = holds("nhl", "crease");
447
+ /** True when the place is in a penalty area, at the end the team attacks or the one it defends. */
448
+ export const inPenaltyArea = (point, options = {}) => {
449
+ const a = zoneAt("soccer", point, options);
450
+ return a.zones.includes("penalty-area") || a.zones.includes("own-penalty-area");
451
+ };
452
+ /** True when the place is in a goal area (the six-yard box), at either end. */
453
+ export const inSixYardBox = (point, options = {}) => {
454
+ const a = zoneAt("soccer", point, options);
455
+ return a.zones.includes("six-yard-box") || a.zones.includes("own-six-yard-box");
456
+ };
457
+ /** True when the place is in the red zone: inside the opponent's 20-yard line. */
458
+ export const inRedZone = holds("nfl", "red-zone");
459
+ /** True when the place is between the hash marks. */
460
+ export const betweenHashes = holds("nfl", "between-the-hashes");
461
+ /** True when the place is in fair territory: between the foul lines, which are fair themselves. */
462
+ export const isFair = holds("mlb", "fair-territory");
463
+ /** True when the place, in fair territory, lies beyond the park's fence: where a ball came down over the wall. `park` is a key of `PARKS`. */
464
+ export const overWall = (point, options = {}) => zoneAt("mlb", point, options).zones.includes("over-the-wall");
465
+ /** True when the place is on the warning track. */
466
+ export const onWarningTrack = holds("mlb", "warning-track");
467
+ /**
468
+ * The ballparks whose wall heights the package holds nowhere in their fence: of the 94 parks, the 35 whose article gives heights have them for some stretch,
469
+ * and for the rest the height is not known here, so a decision that needs it is undecided (`homeRun: undefined`), never guessed.
470
+ */
471
+ export const PARKS_WITHOUT_WALL_HEIGHTS = Object.freeze(Object.values(PARKS).filter((park) => (park.walls ?? []).length === 0).map((park) => park.id));
472
+ /**
473
+ * Whether a ball is a home run, from the park's own fence: the fence's distance at the bearing and, when the height of the ball is given, the wall's height there
474
+ * (`wall` data of the park: the stretches of fence with their heights). A ball in fair territory that came down beyond the fence is a home run; one that was
475
+ * lower than the wall where it crossed struck the wall and is in play. Where the park holds no height for the bearing the answer to a question that needs it
476
+ * is `homeRun: undefined`, and `wallData` says whether the park has any heights at all. `park` is a key of `PARKS` (or a park); the place is in the frame of `options.frame`
477
+ * (`retrosheet` and `mlbam` are the usual) or the drawing's own.
478
+ * @example
479
+ * ```ts
480
+ * import { homeRun } from "@johnmorrisdotca/kyogijo-stadiums/zones";
481
+ * // Fenway Park's Green Monster is 37 feet 2 inches high, 310 feet down the line in left.
482
+ * console.log(homeRun("fenway-park", [-250, 250], { frame: "retrosheet", height: 30 }).reason, homeRun("fenway-park", [-250, 250], { frame: "retrosheet", height: 40 }).reason);
483
+ * // struck-wall cleared
484
+ * ```
485
+ */
486
+ export function homeRun(park, point, options = {}) {
487
+ const found = typeof park === "string" ? parkById(park) : park;
488
+ if (found === undefined)
489
+ throw new RangeError(`Unknown park "${String(park)}": use a key of PARKS`);
490
+ const o = { ...options, park: found.id };
491
+ const r = ruled("mlb", o);
492
+ const [x, y] = onSurface(r, point, o);
493
+ const fair = y < 0 && Math.abs(x) <= -y;
494
+ const angle = y < 0 ? (Math.atan2(x, -y) * 180) / Math.PI : 0;
495
+ const distance = Math.hypot(x, y);
496
+ const fence = fenceAt(fenceFor(found, feetFence(o.fence, lengthUnit(o)), o.year), Math.max(-45, Math.min(45, angle)));
497
+ const wall = fair ? wallHeightAt(found, angle, o.year) : null;
498
+ const wallData = (found.walls ?? []).length > 0;
499
+ const base = { fair, distance, fence, angle, wall, wallData };
500
+ if (!fair)
501
+ return { homeRun: false, reason: "foul", ...base };
502
+ if (distance <= fence)
503
+ return { homeRun: false, reason: "short", ...base };
504
+ if (options.height === undefined || !num(options.height))
505
+ return { homeRun: true, reason: "over", ...base };
506
+ if (wall === null)
507
+ return { homeRun: undefined, reason: "unknown-wall", ...base };
508
+ return options.height > wall ? { homeRun: true, reason: "cleared", ...base } : { homeRun: false, reason: "struck-wall", ...base };
509
+ }
510
+ /** `homeRun` as a yes or no: `true` for a home run, `false` for foul, in play or the wall struck, `undefined` where the park's wall height is missing and the decision needs it. */
511
+ export const isHomeRun = (park, point, options = {}) => homeRun(park, point, options).homeRun;
@@ -0,0 +1,4 @@
1
+ /** The zones and areas that `zoneAt` names from a sport's rulebook, as ids. A zone set of the package's (`ZONE_SETS`) has ids of its own, which `zoneAt` passes on as they are. */
2
+ export declare const RULE_IDS: readonly ["defensive-zone", "neutral-zone", "offensive-zone", "crease", "trapezoid", "behind-goal-line", "inner-slot", "outer-slot", "slot", "faceoff-circle", "centre-circle", "frontcourt", "backcourt", "restricted-area", "paint", "mid-range", "corner-three-left", "corner-three-right", "above-the-break", "three-point", "defensive-third", "middle-third", "attacking-third", "six-yard-box", "own-six-yard-box", "penalty-area", "own-penalty-area", "penalty-arc", "own-penalty-arc", "wing-left", "half-space-left", "central-corridor", "half-space-right", "wing-right", "infield", "outfield", "fair-territory", "foul-territory", "over-the-wall", "warning-track", "left-field", "centre-field", "right-field", "third-base-side", "middle-infield", "first-base-side", "own-end-zone", "own-half", "opponent-half", "red-zone", "opponent-end-zone", "end-zone", "between-the-hashes", "outside-hashes-left", "outside-hashes-right"];
3
+ /** The id of a zone the rules engine names itself. */
4
+ export type RuleId = (typeof RULE_IDS)[number];
@@ -0,0 +1,64 @@
1
+ // The names of the zones the rules engine (rules.ts) answers with. They are the same in every language; the words are in strings.ts (`rules`).
2
+ /** The zones and areas that `zoneAt` names from a sport's rulebook, as ids. A zone set of the package's (`ZONE_SETS`) has ids of its own, which `zoneAt` passes on as they are. */
3
+ export const RULE_IDS = [
4
+ // Hockey
5
+ "defensive-zone",
6
+ "neutral-zone",
7
+ "offensive-zone",
8
+ "crease",
9
+ "trapezoid",
10
+ "behind-goal-line",
11
+ "inner-slot",
12
+ "outer-slot",
13
+ "slot",
14
+ "faceoff-circle",
15
+ "centre-circle",
16
+ // Basketball
17
+ "frontcourt",
18
+ "backcourt",
19
+ "restricted-area",
20
+ "paint",
21
+ "mid-range",
22
+ "corner-three-left",
23
+ "corner-three-right",
24
+ "above-the-break",
25
+ "three-point",
26
+ // Soccer
27
+ "defensive-third",
28
+ "middle-third",
29
+ "attacking-third",
30
+ "six-yard-box",
31
+ "own-six-yard-box",
32
+ "penalty-area",
33
+ "own-penalty-area",
34
+ "penalty-arc",
35
+ "own-penalty-arc",
36
+ "wing-left",
37
+ "half-space-left",
38
+ "central-corridor",
39
+ "half-space-right",
40
+ "wing-right",
41
+ // Baseball
42
+ "infield",
43
+ "outfield",
44
+ "fair-territory",
45
+ "foul-territory",
46
+ "over-the-wall",
47
+ "warning-track",
48
+ "left-field",
49
+ "centre-field",
50
+ "right-field",
51
+ "third-base-side",
52
+ "middle-infield",
53
+ "first-base-side",
54
+ // Football
55
+ "own-end-zone",
56
+ "own-half",
57
+ "opponent-half",
58
+ "red-zone",
59
+ "opponent-end-zone",
60
+ "end-zone",
61
+ "between-the-hashes",
62
+ "outside-hashes-left",
63
+ "outside-hashes-right",
64
+ ];
package/dist/score.d.ts CHANGED
@@ -29,6 +29,8 @@ export interface TeamView {
29
29
  wickets?: string;
30
30
  overs?: string;
31
31
  innings?: string[];
32
+ /** Judo, karate, kendo and sumo: what the side scored, as the sport counts it. */
33
+ budo?: import("./budo.score.ts").BudoView;
32
34
  }
33
35
  /**
34
36
  * A team's name and logo in its place. The place is a box in the surface's own frame; the words are set as the eye
@@ -63,6 +65,7 @@ export declare function badgeMarkup(left: TeamView, right: TeamView, o: {
63
65
  turned?: boolean;
64
66
  parts: boolean;
65
67
  id?: string;
68
+ situation?: string;
66
69
  }): {
67
70
  w: number;
68
71
  h: number;