<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shintaro Inagaki</title>
    <description>The latest articles on DEV Community by Shintaro Inagaki (@shinagaki).</description>
    <link>https://dev.to/shinagaki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4164873%2F59f2a024-e758-4c99-809c-5dd89ff66823.jpg</url>
      <title>DEV Community: Shintaro Inagaki</title>
      <link>https://dev.to/shinagaki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shinagaki"/>
    <language>en</language>
    <item>
      <title>PCN: a text notation for curling games, one line per shot</title>
      <dc:creator>Shintaro Inagaki</dc:creator>
      <pubDate>Mon, 05 Oct 2026 21:06:43 +0000</pubDate>
      <link>https://dev.to/shinagaki/pcn-a-text-notation-for-curling-games-one-line-per-shot-41c8</link>
      <guid>https://dev.to/shinagaki/pcn-a-text-notation-for-curling-games-one-line-per-shot-41c8</guid>
      <description>&lt;p&gt;Shogi has kifu and chess has PGN: one move per line, readable by anyone, replayable by software, and you can &lt;code&gt;diff&lt;/code&gt; two of them. Curling, as far as I could find, has no public notation that does the same job.&lt;/p&gt;

&lt;p&gt;World Curling publishes every shot of the Olympics and the World Championships as "Shot by Shot". Each shot has its type and the statistician's rating, and there is even a diagram of the stones. But the format is PDF. That is fine for a person reading it, but a machine has to parse it every time, and the stone positions exist only as images. The research simulator Digital Curling has a log format, but it is not built to take records of real games.&lt;/p&gt;

&lt;p&gt;The notation actually came first. Years ago I started on a puzzle game about curling and began working out a format for writing its games down, then left it half-finished. In August 2026 I was working with a Hokkaido Curling Tour livestream on in the background, remembered it, and dug out the unfinished spec. I rewrote the physics while I was at it, and that turned into a curling strategy board, &lt;a href="https://curlflux.creco.net/?lang=en" rel="noopener noreferrer"&gt;CurlFlux&lt;/a&gt;. Once I needed to replay real games in the browser, I had to settle the notation too. The result is &lt;strong&gt;PCN (Portable Curling Notation)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through the spec from top to bottom, with the reasons behind each design decision. It is long, but it is written so that after reading it you know all of PCN. The app itself is introduced in &lt;a href="https://creco.net/curlflux-curling-simulator/" rel="noopener noreferrer"&gt;a separate article&lt;/a&gt; (in Japanese).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is still a draft, and that is the reason for this article.&lt;/strong&gt; I am a programmer who watches a lot of curling, with no playing experience. So there must still be things that happen in real games and cannot be written in this format, and people who have played are far better placed to find them than I am. If you read something and think "you couldn't write this", please tell me.&lt;/p&gt;

&lt;p&gt;The spec is public (the Japanese text is normative; there is an English edition):&lt;br&gt;
&lt;a href="https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.en.md" rel="noopener noreferrer"&gt;https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.en.md&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary for busy readers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plain text, one shot per line.&lt;/strong&gt; The header uses PGN's &lt;code&gt;[Key "Value"]&lt;/code&gt;; the body repeats &lt;code&gt;End&lt;/code&gt; lines, shot lines and &lt;code&gt;Score&lt;/code&gt; lines. Everything after &lt;code&gt;;&lt;/code&gt; is a comment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The shot codes are taken directly from World Curling's statisticians' material.&lt;/strong&gt; Shot type (Task) is one letter, rotation (Handle) is &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;&lt;/code&gt;, and the rating (Points) is 0 to 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Four layers by depth of information.&lt;/strong&gt; Line score only → shot type and rating → coordinates of every stone → motion at release. Write only the layers you have&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only up to layer ③ (coordinates) carries across implementations.&lt;/strong&gt; Layer ④ (motion) depends on the physics engine, so it is written together with an &lt;code&gt;Engine&lt;/code&gt; tag, and a different engine ignores it and rebuilds from the coordinates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcomes as coordinates, reasons as comments.&lt;/strong&gt; Infractions, games cut short, measurements, time-outs: everything that happens in a game can be written with these two. How the game ended (&lt;code&gt;Termination&lt;/code&gt;) and the result (&lt;code&gt;Result&lt;/code&gt;) are separate axes&lt;/li&gt;
&lt;li&gt;Rule defaults are inferred from the era and the format. Games from before 1993, mixed doubles and wheelchair all fit the same format&lt;/li&gt;
&lt;li&gt;A finishing stage for the data (&lt;code&gt;Curation&lt;/code&gt;), so automated processing does not overwrite records that were adjusted by hand&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The big picture
&lt;/h2&gt;

&lt;p&gt;First, a whole file. End 1 of Japan vs Poland at the 2026 World Men's Championship.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PCN "1.0"]
[Event "LGT World Men's Curling Championship 2026"]
[Site "Ogden, UT, USA"]
[Date "2026.04.02"]
[Stage "Round Robin Session 18"]
[Sheet "A"]
[Red "JPN - Japan"]
[Yellow "POL - Poland"]
[RedPlayers "KOIZUMI S; USUI S; YAMAGUCHI T; YANAGISAWA R"]
[YellowPlayers "LOBAZA B; CIEMINSKI M; DOMIN K; STYCH K"]
[Ends "10"]
[LSFE "Red"]
[Result "5-0"]
[Termination "Concede"]

End 1 hammer=R
1 Y F&amp;gt;4
2 R D&amp;gt;4
3 Y D&amp;gt;2
4 R D&amp;lt;4
5 Y D&amp;lt;2
6 R T&amp;lt;3
7 Y S&amp;lt;2
8 R H&amp;gt;3
9 Y H&amp;gt;4
10 R T&amp;lt;2
11 Y D&amp;lt;3
12 R H&amp;lt;4
13 Y P&amp;gt;1
14 R H&amp;gt;3
15 Y S&amp;lt;2
16 R D&amp;lt;4
Score 3-0

End 2 hammer=Y
1 R F&amp;gt;4
...
Score 2-0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A file consists of a &lt;strong&gt;header (tags)&lt;/strong&gt; and a &lt;strong&gt;body (a sequence of ends)&lt;/strong&gt;. Blank lines can go anywhere, and everything from &lt;code&gt;;&lt;/code&gt; to the end of the line is a comment. Case is significant.&lt;/p&gt;

&lt;p&gt;The shot line &lt;code&gt;13 Y P&amp;gt;1&lt;/code&gt; reads like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;13&lt;/code&gt;: sequence number within the end&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Y&lt;/code&gt;: thrown by Yellow. Usually this can be left out (see below)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;P&lt;/code&gt;: Promotion Take-out, a shot that hits one of your own stones or a guard and drives it in&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&lt;/code&gt;: clockwise rotation. For a right-hander that is an in-turn, and the stone curls to the right&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt;: the statistician's rating 1 (25%). Close to a miss&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This game was 5-0 after two ends, and Poland conceded. &lt;code&gt;[Termination "Concede"]&lt;/code&gt; says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five design principles
&lt;/h2&gt;

&lt;p&gt;These are at the top of the spec. Every detailed rule after this follows from them.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Four layers by depth of information
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Sources that exist today&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;① Line score&lt;/td&gt;
&lt;td&gt;Points per end, the team with the hammer in end 1 (LSFE), last stone draw&lt;/td&gt;
&lt;td&gt;World Curling results database, national association result pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;② Description&lt;/td&gt;
&lt;td&gt;Thrower, shot type, rotation, 0–4 rating&lt;/td&gt;
&lt;td&gt;World Curling / CURLIT Shot by Shot (PDF, Game Centre)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;③ Positions&lt;/td&gt;
&lt;td&gt;Coordinates of every stone after each shot&lt;/td&gt;
&lt;td&gt;Diagrams in Results Books (images), Live Scores SVG, coaching apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;④ Motion&lt;/td&gt;
&lt;td&gt;Position, velocity and spin at release&lt;/td&gt;
&lt;td&gt;Simulators (Digital Curling and others), measuring equipment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① Line score   →  ② Description           →  ③ Positions  →  ④ Motion
   Score lines       Task / Handle / Points      @ lines         v= and Engine

③: every implementation can follow the same board
④: exact replay with the same engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You write only the layers you have, in the same file. The first World Championship in 1959 has nothing but a line score, so it becomes a layer-① file (the scores here are made up):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PCN "1.0"]
[Event "Scotch Cup 1959"]
[Date "1959.??.??"]
[Red "Canada"]
[Yellow "Scotland"]
[Ends "12"]
[LSFE "Red"]
[Result "7-4"]

End 1 hammer=R
Score 1-0
End 2
Score 0-2
End 3
Score 2-0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even without a single shot line, this is valid PCN. At the other end, a practice session recorded in a simulator has everything up to layer ④.&lt;/p&gt;

&lt;p&gt;With layer ④, a deterministic physics engine can replay the game exactly. How to present a record without layer ④ is left to the implementation. It may show the layer-③ positions as the board, or it may generate throws that fit layer ③ or are consistent with layer ② and animate them. When a generated throw is written back into the record, &lt;code&gt;est&lt;/code&gt; marks it as an estimate.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Contain existing records rather than replace them
&lt;/h3&gt;

&lt;p&gt;When creating a new format, the thing I most wanted to avoid was adding "yet another proprietary format". The design lets public records (line scores, Shot by Shot, position diagrams, coaching-app CSV, simulator logs) each go straight into one of the layers ①–④. Converting a World Curling PDF gives a layer ②③ PCN; throwing stones in CurlFlux gives one with layer ④ too.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Line-oriented and appendable
&lt;/h3&gt;

&lt;p&gt;One shot per line. &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt; and spreadsheets all work. The file reads from top to bottom, so adding a line per throw gives you a live record. An end without a &lt;code&gt;Score&lt;/code&gt; line is "in progress".&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Match World Curling practice
&lt;/h3&gt;

&lt;p&gt;The shot types and ratings use the definitions and one-letter codes from &lt;em&gt;Curling Statistics: How to Score&lt;/em&gt;, the manual for World Curling and CURLIT statisticians. The classification statisticians assign at every game becomes the notation as it is. The only thing I changed is how rotation is written (see below).&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Implicit values only where derivable
&lt;/h3&gt;

&lt;p&gt;Throwing order (who throws first) and the thrower follow from the rules, so they may be omitted. Only exceptions (a skip throwing the lead's stones, a throwing-order violation) are written explicitly. Conversely, nothing that cannot be derived is omitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Header: tags
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;[Key "Value"]&lt;/code&gt; per line. Inside a value, &lt;code&gt;"&lt;/code&gt; is written &lt;code&gt;\"&lt;/code&gt; and &lt;code&gt;\&lt;/code&gt; is written &lt;code&gt;\\&lt;/code&gt;. Order is free, but putting &lt;code&gt;PCN&lt;/code&gt; first is recommended. The rule is that &lt;strong&gt;unknown tags are preserved and ignored&lt;/strong&gt;, and the same goes for unknown &lt;code&gt;key=value&lt;/code&gt; pairs and comments in the body. That way information added by future extensions or other processors is not lost on a round trip.&lt;/p&gt;

&lt;p&gt;Only three are required: &lt;code&gt;PCN&lt;/code&gt; (the spec version, &lt;code&gt;"1.0"&lt;/code&gt;) and &lt;code&gt;Red&lt;/code&gt; / &lt;code&gt;Yellow&lt;/code&gt; (team names). Everything else is optional. Let's go through them by purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identifying the game
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Event&lt;/code&gt;, &lt;code&gt;Site&lt;/code&gt; (city, country), &lt;code&gt;Venue&lt;/code&gt; (the building), &lt;code&gt;Date&lt;/code&gt; (&lt;code&gt;YYYY.MM.DD&lt;/code&gt;, unknown parts as &lt;code&gt;??&lt;/code&gt;), &lt;code&gt;Time&lt;/code&gt;, &lt;code&gt;Stage&lt;/code&gt; (round or session, &lt;code&gt;"Round Robin Session 18"&lt;/code&gt; or &lt;code&gt;"Semi-final"&lt;/code&gt;, either is fine), &lt;code&gt;Sheet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Time&lt;/code&gt; is &lt;strong&gt;venue local time&lt;/strong&gt;. World Curling records are written in local time, so PCN follows them, and the time zone is inferred from &lt;code&gt;Site&lt;/code&gt;. Only if you want UTC do you add &lt;code&gt;TZ&lt;/code&gt; (&lt;code&gt;"+09:00"&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Teams
&lt;/h3&gt;

&lt;p&gt;Teams are identified by &lt;strong&gt;stone colour&lt;/strong&gt;, &lt;code&gt;Red&lt;/code&gt; and &lt;code&gt;Yellow&lt;/code&gt;, as World Curling does. Even if the actual stones are blue or green, Red/Yellow are used nominally, and the display colour goes in &lt;code&gt;RedColor&lt;/code&gt; / &lt;code&gt;YellowColor&lt;/code&gt; (&lt;code&gt;#rrggbb&lt;/code&gt;). Records of domestic events in Japan often have blue stones, so this separation was necessary.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RedPlayers&lt;/code&gt; / &lt;code&gt;YellowPlayers&lt;/code&gt; list the players in throwing order, separated by &lt;code&gt;;&lt;/code&gt;: lead; second; third; fourth. By default the third is the vice-skip and the fourth is the skip. For teams where that is not the case, you can add &lt;code&gt;(S)&lt;/code&gt; (skip) or &lt;code&gt;(V)&lt;/code&gt; (vice-skip) after a name. A team playing with three writes three names; the first two then throw three stones each and the third throws two, as in World Curling rule R3(c)(i). Mixed doubles has two names.&lt;/p&gt;

&lt;p&gt;There are also &lt;code&gt;RedShort&lt;/code&gt; / &lt;code&gt;YellowShort&lt;/code&gt; (an abbreviation such as &lt;code&gt;JPN&lt;/code&gt;), &lt;code&gt;RedCoach&lt;/code&gt;, &lt;code&gt;RedReserve&lt;/code&gt; (alternates) and &lt;code&gt;RedSub&lt;/code&gt; (substitutions during the game, free text such as &lt;code&gt;"E6 TANAKA for SUZUKI Y"&lt;/code&gt;). &lt;code&gt;RedSub&lt;/code&gt; is display metadata. Who threw after a substitution is written with &lt;code&gt;orderR=&lt;/code&gt; / &lt;code&gt;orderY=&lt;/code&gt; on the end line (the delivery rotation from that end on, see below) or with &lt;code&gt;p=&lt;/code&gt; on a shot line. Alternates are referred to by the numbers that follow &lt;code&gt;Players&lt;/code&gt; (with four &lt;code&gt;Players&lt;/code&gt;, the first alternate is &lt;code&gt;5&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Format and rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Format&lt;/code&gt;: &lt;code&gt;Team&lt;/code&gt; (default) / &lt;code&gt;MixedDoubles&lt;/code&gt; / &lt;code&gt;Wheelchair&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ends&lt;/code&gt;: scheduled ends. Default &lt;code&gt;10&lt;/code&gt;; mixed doubles &lt;code&gt;8&lt;/code&gt;. Write it explicitly for 8-end games&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Stones&lt;/code&gt;: stones per team per end. Default &lt;code&gt;8&lt;/code&gt;, mixed doubles &lt;code&gt;5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FGZ&lt;/code&gt;: the number of stones protected by the free guard zone rule, &lt;code&gt;0&lt;/code&gt; / &lt;code&gt;3&lt;/code&gt; / &lt;code&gt;4&lt;/code&gt; / &lt;code&gt;5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NoTick&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt; / &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ThinkingTime&lt;/code&gt;: thinking time (&lt;code&gt;"38:00"&lt;/code&gt; for 10 ends, &lt;code&gt;"30:00"&lt;/code&gt; for 8, &lt;code&gt;"22:00"&lt;/code&gt; for mixed doubles)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;FGZ&lt;/code&gt; and &lt;code&gt;NoTick&lt;/code&gt; may be omitted. If they are, the rules of the time are inferred from &lt;code&gt;Date&lt;/code&gt; and &lt;code&gt;Format&lt;/code&gt;. The table of defaults comes in a later section.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Wheelchair&lt;/code&gt; plays like the four-player game (the difference is that there is no sweeping), so the body is written the same way. It is, however, exempt from the no-tick rule, so it does affect the rule defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ice and sheet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SheetWidth&lt;/code&gt;: sheet width in metres. The default &lt;code&gt;4.75&lt;/code&gt; is World Curling's maximum. Existing facilities may be as narrow as &lt;code&gt;4.42&lt;/code&gt;, and narrow club sheets can be 14 ft 2 in, &lt;code&gt;4.28&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ice&lt;/code&gt;: ice conditions. Three values, as in &lt;code&gt;"hh=13.8 curl=1.41 turns=5"&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hh&lt;/code&gt;: hog-to-hog time (seconds) of a draw that stops on the tee&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl&lt;/code&gt;: for a draw to the tee released straight with the centre line as its aim, &lt;strong&gt;how far to the side of the aim line it ends up when it stops&lt;/strong&gt; (m)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;turns&lt;/code&gt;: the standard number of turns, i.e. how many times a stone rotates from release until it stops. &lt;code&gt;5&lt;/code&gt; if omitted&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Ice&lt;/code&gt; exists for the portability of layer ④. A player calibrates its own friction and curl to match &lt;code&gt;hh&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt;. Even if the physics models differ, it gives a way to get close to "the same ice". Engine-specific multipliers (&lt;code&gt;friction=&lt;/code&gt; &lt;code&gt;curlx=&lt;/code&gt;) may be added alongside.&lt;/p&gt;

&lt;p&gt;I defined &lt;code&gt;curl&lt;/code&gt; as "the offset from the aim line" to match how players and ice technicians talk when they say "this ice curls four and a half feet". &lt;code&gt;turns&lt;/code&gt; is there because some physics models curl differently depending on the number of turns. Two and a half to three and a half turns used to be normal, but top players now throw around five, so the default is &lt;code&gt;5&lt;/code&gt;. &lt;code&gt;curl&lt;/code&gt; is written as the value for a draw thrown with that number of turns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result and termination
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LSFE&lt;/code&gt;: the team with the hammer (last stone) in end 1. &lt;code&gt;Red&lt;/code&gt; / &lt;code&gt;Yellow&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LSD&lt;/code&gt;: last stone draw. &lt;code&gt;"Red 286.3; Yellow 199.6"&lt;/code&gt; (cm; outside the house = 199.6)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Result&lt;/code&gt;: final score &lt;code&gt;"Red-Yellow"&lt;/code&gt;. In progress or unknown: &lt;code&gt;"*"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Termination&lt;/code&gt;: how the game closed. &lt;code&gt;Normal&lt;/code&gt; / &lt;code&gt;Concede&lt;/code&gt; / &lt;code&gt;Stopped&lt;/code&gt; / &lt;code&gt;Forfeit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Timeout&lt;/code&gt;: time-outs, listed as "team, end, before which of that team's stones" (counted per team, not the shot number within the end), as in &lt;code&gt;"Y E6 before 5; R EE before 3"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Termination&lt;/code&gt; was a hard part of the design, so it gets its own section later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source and quality
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Engine&lt;/code&gt;: identifier of the physics engine that replays the layer-④ motion, as &lt;code&gt;name/version&lt;/code&gt;. Required when motion is written&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Source&lt;/code&gt;: source (URL etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Annotator&lt;/code&gt;: who recorded it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Curation&lt;/code&gt;: the finishing stage of the data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Curation&lt;/code&gt; came out of an accident in my own implementation. Its value is a single ordered ladder: &lt;code&gt;generated&lt;/code&gt; &amp;lt; &lt;code&gt;adjusted&lt;/code&gt; &amp;lt; &lt;code&gt;verified&lt;/code&gt; &amp;lt; &lt;code&gt;reenacted&lt;/code&gt;. Motion generated automatically from positions and left as is: &lt;code&gt;generated&lt;/code&gt;. Positions or throws adjusted by hand after that: &lt;code&gt;adjusted&lt;/code&gt;. Every throw that matters for the outcome checked against video: &lt;code&gt;verified&lt;/code&gt;. Fully reproduced with keyframes: &lt;code&gt;reenacted&lt;/code&gt;. If absent, it counts as &lt;code&gt;generated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The rule is that &lt;strong&gt;a processor about to overwrite a file at &lt;code&gt;adjusted&lt;/code&gt; or above with an automatic regeneration should refuse (or at least warn)&lt;/strong&gt;. I once did exactly that: a record I had spent hours adjusting while watching the video got overwritten by an automated step. The lesson was that the format itself needs a safety valve to stop machines from erasing human work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Body: end lines
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;End &amp;lt;n&amp;gt; [hammer=R|Y] [key=value ...]
  ...shot lines...
Score &amp;lt;red&amp;gt;-&amp;lt;yellow&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;n&lt;/code&gt; starts at 1. Extra ends beyond the schedule simply continue the numbering (11, 12 …); showing them as "EE" is up to the player.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hammer=&lt;/code&gt; may be omitted. It is then derived from the previous end (the team that did not score gets the hammer next; a blank keeps it) and from &lt;code&gt;LSFE&lt;/code&gt;. If an explicit value conflicts with the derived one, the explicit value wins and a warning is shown. This doubles as a way to catch mistakes in records.&lt;/p&gt;

&lt;p&gt;The other attributes are &lt;code&gt;powerplay=R|Y&lt;/code&gt; (the team that used its mixed doubles power play) and &lt;code&gt;clockR=&lt;/code&gt; / &lt;code&gt;clockY=&lt;/code&gt; (thinking time left at the end of the end).&lt;/p&gt;

&lt;h3&gt;
  
  
  Things that change mid-game: ice and delivery rotation
&lt;/h3&gt;

&lt;p&gt;Two things change during a game, and both became end attributes that apply "from that end on".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change of ice&lt;/strong&gt;, &lt;code&gt;hh=&lt;/code&gt; / &lt;code&gt;curl=&lt;/code&gt;. For things like heavy ice early on while the pebble is fresh, or ice getting faster after scraping or as the temperature changes. Scraping happens between ends, and measurements are taken end by end, so an end attribute fits exactly. If only one is written, the other keeps its previous value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;End 6 hammer=R hh=14.3 curl=1.40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Change of delivery rotation&lt;/strong&gt;, &lt;code&gt;orderR=&lt;/code&gt; / &lt;code&gt;orderY=&lt;/code&gt;. This is for bringing in an alternate. The player numbers are listed with commas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;End 5 hammer=Y orderY=5,2,3,4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means "from end 5, the first alternate (&lt;code&gt;5&lt;/code&gt;) throws lead". With one number per player, each player throws the number of stones divided by the number of players. Mixed doubles takes two numbers: the first throws stones 1 and 5, the second stones 2 to 4.&lt;/p&gt;

&lt;p&gt;It is an end attribute because that is how the rules work. The delivery rotation may change only when an alternate is brought in, that happens at the start of an end, and the replaced player cannot return to the game (WCF R3). A record where someone else threw a single stone is written with &lt;code&gt;p=&lt;/code&gt; on the shot line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Score&lt;/code&gt; is the score of that end. A blank is &lt;code&gt;Score 0-0&lt;/code&gt;. An end not played to completion, because of a concession for example, is marked with &lt;code&gt;X&lt;/code&gt;: &lt;code&gt;Score X&lt;/code&gt; (neither team threw) or something like &lt;code&gt;Score 2-X&lt;/code&gt;. Leaving out the &lt;code&gt;Score&lt;/code&gt; line itself means "not yet decided", which is the state of an end in progress in a live record.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenarios (cutting out a position)
&lt;/h3&gt;

&lt;p&gt;A strategy board is often used as "think about the next shot from this position". You cut out just the last three stones of end 10, without the throws that came before. For that, the starting end can take two attributes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;End 10 hammer=Y thrown=7-6 score=4-5
Setup
@ R0.10,0.30* R-0.60,1.90 Y-0.40,1.20 Y0.35,-0.50 Y0.02,3.40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;thrown=7-6&lt;/code&gt; says that at the start of the end the first team has thrown 7 stones and the second team 6 (the next shot is the hammer team's 7th). &lt;code&gt;score=4-5&lt;/code&gt; is the cumulative score at the start of the end. It is a different thing from the &lt;code&gt;Score&lt;/code&gt; line in the body (the result of the end). A processor that reads these starts counting from this end number, score, hammer and stone count. It is a tool only for cutting out positions; a normal full record does not need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Body: shot lines
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;number&amp;gt; [R|Y] &amp;lt;shot&amp;gt; [key=value ...] [; comment]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Number and side
&lt;/h3&gt;

&lt;p&gt;The number is the sequence number within the end: 1–16 in the four-player game, 1–10 in mixed doubles. The side &lt;code&gt;R&lt;/code&gt; / &lt;code&gt;Y&lt;/code&gt; may be omitted; &lt;strong&gt;if it is, the team without the hammer throws first, then they alternate&lt;/strong&gt;. You write it only for records where the throwing order went wrong (a throwing-order violation, for example). When a line without a side follows a line with an explicit side, it is read as thrown by "the team that has thrown fewer stones".&lt;/p&gt;

&lt;h3&gt;
  
  
  Shot codes
&lt;/h3&gt;

&lt;p&gt;The order is &lt;code&gt;&amp;lt;Task&amp;gt;&amp;lt;Handle&amp;gt;&amp;lt;Points&amp;gt;&amp;lt;annotation&amp;gt;&lt;/code&gt;, as in &lt;code&gt;D&amp;gt;4&lt;/code&gt;, &lt;code&gt;T&amp;lt;2&lt;/code&gt;, &lt;code&gt;P&amp;gt;1!?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task (shot type)&lt;/strong&gt; is the one-letter code from the statisticians' manual.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Draw&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Front (placed short of the house; includes centre / corner guards)&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Guard (protecting a specific stone)&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise / Tap Back&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wick / Split / Soft-peeling&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Freeze&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Take-out&lt;/td&gt;
&lt;td&gt;fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hit and Roll&lt;/td&gt;
&lt;td&gt;fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clearing (peel)&lt;/td&gt;
&lt;td&gt;fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Double Take-out&lt;/td&gt;
&lt;td&gt;fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Promotion Take-out (run-back)&lt;/td&gt;
&lt;td&gt;fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Through (intentional)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not considered (burned stone etc.)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unspecified (no task assigned)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last three involve a small trick. In the statisticians' manual, &lt;code&gt;-&lt;/code&gt; (Through) is a Task whose rating is automatically "not considered", and &lt;code&gt;X&lt;/code&gt; (Not considered) is really a &lt;strong&gt;Points value&lt;/strong&gt;. PCN keeps both as Task codes so the syntax is uniform: &lt;code&gt;-&lt;/code&gt; takes neither Handle nor Points, and &lt;code&gt;X&lt;/code&gt; takes no Points.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?&lt;/code&gt; (Unspecified) is a PCN addition. I added it for throws that have a position diagram but no Shot by Shot classification. PCN requires a Task, and this code avoids forcing an unknown throw into a particular type. The spec says a player may build the throw without a type hint and fill in the type from the resulting board (the position is authoritative). Chess-style annotations also have &lt;code&gt;?&lt;/code&gt;, but that one comes after the Task, so the position tells them apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handle (rotation)&lt;/strong&gt; is &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clockwise (seen from above). In-turn for a right-hander. The stone curls &lt;strong&gt;right&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Counter-clockwise. Out-turn for a right-hander. The stone curls &lt;strong&gt;left&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The statisticians' manual writes In-turn / Out-turn (&lt;code&gt;I&lt;/code&gt; / &lt;code&gt;O&lt;/code&gt;), but those words flip meaning with the thrower's handedness. A left-hander's in-turn is the same rotation as a right-hander's out-turn. PCN ignores handedness and records only the direction the stone rotates (as World Curling does). I chose &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; because you can see at a glance which way the stone curls. If unknown, leave it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fptf48xifzjaxkzm07y4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fptf48xifzjaxkzm07y4n.png" alt="Paths of two stones aimed at the same button. The clockwise one (&gt;) comes in from the left and curls right; the counter-clockwise one (&lt;) comes in from the right and curls left"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Two stones aimed at the same button. The direction of the symbol matches the direction the stone curls (the paths were actually solved with the physics engine)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Points (rating)&lt;/strong&gt; is &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;4&lt;/code&gt;, corresponding to World Curling's 0 / 25 / 50 / 75 / 100%. It is assigned following the statisticians' guidelines. For a take-out, for example: 4 = opponent removed and shooter stays, 3 = stays but rolls, 2 = both out, 0 = the opponent stays. Some older scoring used 5 or 6 as the maximum; PCN does not represent those and rounds them to the 4-point scale on import (4 and above become &lt;code&gt;4&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;World Curling statistics record hog-line and FGZ violations as "Player's Fault", separately from the Task. In PCN you write the intended Task as it is and give the reason in an &lt;code&gt;x=&lt;/code&gt; field (see below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotations&lt;/strong&gt; are &lt;code&gt;!&lt;/code&gt; (good), &lt;code&gt;!!&lt;/code&gt; (brilliant), &lt;code&gt;?&lt;/code&gt; (dubious), &lt;code&gt;??&lt;/code&gt; (bad), &lt;code&gt;!?&lt;/code&gt; and &lt;code&gt;?!&lt;/code&gt;, placed after Points. Points is the statistician's objective rating; the annotation is the writer's subjective opinion. I borrowed this from chess notation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Additional fields
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Form&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1&lt;/code&gt;–&lt;/td&gt;
&lt;td&gt;Thrower: which entry of the &lt;code&gt;Players&lt;/code&gt; tag (alternates continue the numbering). If omitted, the end's delivery rotation (&lt;code&gt;orderR=&lt;/code&gt; / &lt;code&gt;orderY=&lt;/code&gt;; otherwise the regular order, two stones each)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;t=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;seconds&lt;/td&gt;
&lt;td&gt;Hog-to-hog time (hog line to hog line), e.g. &lt;code&gt;t=12.7&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;i=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;seconds&lt;/td&gt;
&lt;td&gt;Split time (delivery-end back line to hog line, 8.230 m), e.g. &lt;code&gt;i=3.7&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clock=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MM:SS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Thinking time left after the shot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x,y,vx,vy,w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Layer-④ motion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;est&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;flag&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;v=&lt;/code&gt; is not a measurement but an estimate generated from layers ② / ③&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;p=&lt;/code&gt; is for a single stone thrown outside the regular order, such as a skip throwing the lead's stone. If the order changed because of a substitution, &lt;code&gt;orderR=&lt;/code&gt; / &lt;code&gt;orderY=&lt;/code&gt; on the end line is shorter to write. &lt;code&gt;t=&lt;/code&gt; is exactly the hog-to-hog time shown on TV broadcasts, and it is the primary information about how fast the ice is.&lt;/p&gt;
&lt;h2&gt;
  
  
  Body: board lines
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The &lt;code&gt;@&lt;/code&gt; line
&lt;/h3&gt;

&lt;p&gt;Right after a shot line, a line starting with &lt;code&gt;@&lt;/code&gt; gives the coordinates of every stone &lt;strong&gt;after&lt;/strong&gt; that shot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 Y T&amp;lt;4
@ Y-0.02,3.61 Y0.31,-0.55
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Items are &lt;code&gt;&amp;lt;R|Y&amp;gt;&amp;lt;x&amp;gt;,&amp;lt;y&amp;gt;&lt;/code&gt;, separated by spaces, in any order&lt;/li&gt;
&lt;li&gt;Only stones in play are written. Removed stones are not&lt;/li&gt;
&lt;li&gt;If there are no stones, the line is just &lt;code&gt;@&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A stone with a trailing &lt;code&gt;*&lt;/code&gt; is &lt;strong&gt;the final position of the stone thrown in that shot, when it stayed in play&lt;/strong&gt;. At most one per position. Do not mark a position where the thrown stone went out of play&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;*&lt;/code&gt; corresponds to the stone drawn with a thick black rim in World Curling's diagrams. With it, there is no ambiguity about which stone was thrown when a throw is rebuilt from the positions. Where a hit swaps stones around, without this mark there can be two solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcwjib61vcxvmzdnaq90w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcwjib61vcxvmzdnaq90w.png" alt="How a PCN @ line maps to the board. For the line @ R0.45,0.98* R0.08,0.26 Y0.08,2.69 Y0.05,0.58, only the stone R0.45,0.98, the one with the trailing *, is drawn with a thick black rim"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How the &lt;code&gt;@&lt;/code&gt; line maps to the board. Only the one stone thrown in this shot gets the `&lt;/em&gt;`*&lt;/p&gt;

&lt;p&gt;There is one more important rule. &lt;code&gt;@&lt;/code&gt; means "the board after that shot, &lt;strong&gt;as settled before the next shot is thrown&lt;/strong&gt;". Stones repositioned by an umpire, and corrections made from video or photos, belong in this board. &lt;code&gt;Setup&lt;/code&gt; is never written in the middle of an end.&lt;/p&gt;
&lt;h3&gt;
  
  
  The &lt;code&gt;Setup&lt;/code&gt; line
&lt;/h3&gt;

&lt;p&gt;To start from an arbitrary position, write &lt;code&gt;Setup&lt;/code&gt; and a board line right after &lt;code&gt;End&lt;/code&gt;. Mixed doubles pre-positioned stones, practice problems and tactical study all use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;End 1 hammer=Y
Setup
@ R0.00,3.50 Y0.00,0.30
1 R D&amp;lt;4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In mixed doubles two stones are placed at the start of each end (rule R17(f)). The stone of the team with the hammer goes in the house, the other one is a centre guard. In this example yellow has the hammer, so the yellow stone is in the house and the red stone is the guard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coordinates and motion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Coordinate system
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Unit: &lt;strong&gt;metres&lt;/strong&gt;. Two decimals (1 cm) is standard, up to four if needed&lt;/li&gt;
&lt;li&gt;Origin: &lt;strong&gt;the tee (centre of the button) of the house in play&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+x&lt;/code&gt; is to the thrower's right, &lt;code&gt;+y&lt;/code&gt; is toward the thrower (the hack). Guards have &lt;code&gt;y &amp;gt; 0&lt;/code&gt;, the back of the house has &lt;code&gt;y &amp;lt; 0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reference dimensions (World Curling): 12-foot circle radius 1.829, 8-foot 1.219, 4-foot 0.610, button 0.152, hog line &lt;code&gt;y = 6.401&lt;/code&gt;, back line &lt;code&gt;y = −1.829&lt;/code&gt;, sheet width 4.75 (&lt;code&gt;|x| ≤ 2.375&lt;/code&gt;), stone radius 0.1455&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pbyfy6t95yn9lqmjspw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pbyfy6t95yn9lqmjspw.png" alt="The PCN coordinate system. The origin is the tee of the house, +x is to the thrower's right, +y is toward the thrower. The figure shows the radii of the 12-foot (1.829), 8-foot (1.219), 4-foot (0.610) circles and the button (0.152), plus the back line, the hog line and the sheet width"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The coordinate system. The coordinates alone tell you where a stone is relative to the rings&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I put the origin at the tee because then you can see how a stone relates to the rings just by looking at its coordinates. &lt;code&gt;Y0.31,-0.55&lt;/code&gt; reads as "31 cm right of the tee, 55 cm behind it, inside the 4-foot". Digital Curling, which is used in research, has its origin at the hack with &lt;code&gt;y&lt;/code&gt; pointing toward the house, so the conversion is &lt;code&gt;x_pcn = x_dc&lt;/code&gt;, &lt;code&gt;y_pcn = 38.405 − y_dc&lt;/code&gt; (38.405 m from the hack to the tee).&lt;/p&gt;
&lt;h3&gt;
  
  
  Motion &lt;code&gt;v=x,y,vx,vy,w&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x,y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m&lt;/td&gt;
&lt;td&gt;Stone centre at the start of the record (release)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vx,vy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s&lt;/td&gt;
&lt;td&gt;Velocity vector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;Angular velocity, &lt;strong&gt;positive = counter-clockwise&lt;/strong&gt; seen from above (a &lt;code&gt;&amp;gt;&lt;/code&gt; stone is negative)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;14.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0.3541&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;30.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;-2.1746&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1.2495&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R0.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.98&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R0.08&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Y0.08&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;2.69&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Y0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.58&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;y=30.8&lt;/code&gt; is the release point. &lt;code&gt;vy&lt;/code&gt; is negative because the stone travels toward the tee (&lt;code&gt;−y&lt;/code&gt;). &lt;code&gt;w&lt;/code&gt; is positive, which agrees with the Handle &lt;code&gt;&amp;lt;&lt;/code&gt; (counter-clockwise).&lt;/p&gt;
&lt;h2&gt;
  
  
  The portability trade-off: layer ③ is the common language
&lt;/h2&gt;

&lt;p&gt;This is the part of the design I thought about most. With layer-④ motion, the same physics engine reproduces the stones' movement exactly. But with a different physics model, the same release stops somewhere else. The friction model and the curl formula differ from one implementation to the next.&lt;/p&gt;

&lt;p&gt;So the spec says that &lt;code&gt;v=&lt;/code&gt; is always written together with an &lt;code&gt;Engine&lt;/code&gt; tag, and &lt;strong&gt;a player with a different engine ignores &lt;code&gt;v=&lt;/code&gt; and rebuilds the throw from the layer-③ coordinates&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v= present ──┬─ Engine matches ──→ replay the physics as is (exact)
             └─ Engine differs ──→ do not use v= ──┐
                                                    ├──→ fit the throw from @
@ only ─────────────────────────────────────────────┘

② only ──→ generate a throw consistent with Task, Handle, Points and the board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are seven guidelines for implementers of the playback side:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;v=&lt;/code&gt; present and &lt;code&gt;Engine&lt;/code&gt; matches yours → replay the physics as is&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v=&lt;/code&gt; present but &lt;code&gt;Engine&lt;/code&gt; differs → do not use &lt;code&gt;v=&lt;/code&gt;. If there is an &lt;code&gt;Ice&lt;/code&gt; tag, calibrate your engine to it first, then solve from &lt;code&gt;@&lt;/code&gt; as in 3&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@&lt;/code&gt; present → fit a throw from the difference between consecutive boards: the stopping point for draws, the contact outcome for hits. The resulting &lt;code&gt;v=&lt;/code&gt; may be saved with &lt;code&gt;est&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Layer ② only → generate a throw consistent with Task, Handle, Points and the board. The lower the Points, the farther from the target. &lt;code&gt;-&lt;/code&gt; passes without touching anything; &lt;code&gt;X&lt;/code&gt; leaves the board unchanged&lt;/li&gt;
&lt;li&gt;Show generated or fitted throws as estimates in the UI (with &lt;code&gt;≈&lt;/code&gt;, for example)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not apply rule-violation judgement when replaying a recorded game.&lt;/strong&gt; The ruling of the day is already reflected in the record, and re-judging with estimated physics causes false positives&lt;/li&gt;
&lt;li&gt;When reading a live record, treat a final end without &lt;code&gt;Score&lt;/code&gt; as in progress, and read it on the assumption that lines may be appended&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In other words, layer ③ is "the common language in which every implementation follows the same board", and layer ④ is "exact reproduction and bit-level verification within one engine". Almost all of the CurlFlux library is layer ④ with &lt;code&gt;est&lt;/code&gt;, which means: open it in CurlFlux and you see motion close to the video; open it in another implementation and you get the same boards from layer ③.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing irregularities
&lt;/h2&gt;

&lt;p&gt;Games have infractions, games cut short, and umpires repositioning stones. If you start handling these case by case with dedicated codes, the spec grows without limit. PCN has just two principles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcomes are expressed by the &lt;code&gt;@&lt;/code&gt; board&lt;/strong&gt; (which can represent any position). &lt;strong&gt;Reasons are expressed by a &lt;code&gt;; comment&lt;/code&gt; or an &lt;code&gt;x=&lt;/code&gt; field.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Violations
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;x=&amp;lt;code&amp;gt;&lt;/code&gt; and write the &lt;strong&gt;board after the ruling&lt;/strong&gt; in &lt;code&gt;@&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Ruling (reflected in &lt;code&gt;@&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=fgz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Protected-stone (free guard zone) violation&lt;/td&gt;
&lt;td&gt;Moved stones returned, shooter removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=notick&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No-tick violation&lt;/td&gt;
&lt;td&gt;The non-offending team's choice (restore / leave) in &lt;code&gt;@&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=hog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hog-line violation (late release), or a stone that did not reach the hog line&lt;/td&gt;
&lt;td&gt;Shooter removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=burn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Burned stone (touched while moving)&lt;/td&gt;
&lt;td&gt;The opponent's choice (leave / restore / remove) in &lt;code&gt;@&lt;/code&gt;. Details in a comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=reposition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stones repositioned by an umpire&lt;/td&gt;
&lt;td&gt;The repositioned board in &lt;code&gt;@&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x=wrong&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wrong stone or wrong order&lt;/td&gt;
&lt;td&gt;Result of the ruling in &lt;code&gt;@&lt;/code&gt;. Details in a comment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 R T&amp;lt;0 x=fgz ; opponent's centre guard removed → restored, shooter removed
@ Y0.05,3.42 R-0.21,0.88
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Task is the intended one (a take-out) as it is, the rating is 0, the reason is &lt;code&gt;x=fgz&lt;/code&gt;, and the outcome is &lt;code&gt;@&lt;/code&gt;. When the FGZ rule is in effect the player can detect and restore this automatically, so the restoration happens even without &lt;code&gt;@&lt;/code&gt;, but if you are keeping a record, writing it is the safe choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the game ended
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Termination&lt;/code&gt; tag has only four values, describing &lt;strong&gt;how the game closed&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Normal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All scheduled ends played (default)&lt;/td&gt;
&lt;td&gt;Total score&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Concede&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One team conceded&lt;/td&gt;
&lt;td&gt;The team that did not concede&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Stopped&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cut short before the scheduled ends&lt;/td&gt;
&lt;td&gt;Total score at the stop. A tie is a draw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Forfeit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Decided by something other than play (no-show, disqualification, out of thinking time)&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;Result&lt;/code&gt; tag&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The reason is not part of the value; it goes in a comment on the final end's line.&lt;/strong&gt; There is no end to the possible reasons: an event's time limit for games, a facility failure, the weather, an opponent not turning up. Assigning a code to each would never finish. A reader decides how to handle the game from &lt;code&gt;Termination&lt;/code&gt; and simply shows the reason as a comment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Ends "8"]
[Result "5-4"]
[Termination "Stopped"]
…
End 7 ; game reached the event time limit (2.5 hours); last end
…
Score 1-0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some finer decisions are in here too. Losing on time is &lt;code&gt;Forfeit&lt;/code&gt;, not &lt;code&gt;Stopped&lt;/code&gt; (because it is an ending that decides a loser). A game that ends tied under &lt;code&gt;Stopped&lt;/code&gt; is a draw, and &lt;code&gt;Termination&lt;/code&gt; has no value for draws, because &lt;strong&gt;how the game ended and the result are separate axes&lt;/strong&gt;. Ends that were not played are &lt;code&gt;Score X&lt;/code&gt;, and &lt;code&gt;Result&lt;/code&gt; carries the deciding score.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything else
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Measurements&lt;/strong&gt;: the outcome shows in &lt;code&gt;@&lt;/code&gt; and &lt;code&gt;Score&lt;/code&gt;, so nothing extra is needed. Add a comment if you like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-outs&lt;/strong&gt;: write &lt;code&gt;; time-out&lt;/code&gt; on the shot line where it was taken, or list them for the whole game in the &lt;code&gt;Timeout&lt;/code&gt; tag&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power play&lt;/strong&gt;: &lt;code&gt;End … powerplay=R|Y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Substitutions and ice changes&lt;/strong&gt;: &lt;code&gt;End … orderR=&lt;/code&gt; / &lt;code&gt;orderY=&lt;/code&gt; and &lt;code&gt;End … hh=&lt;/code&gt; / &lt;code&gt;curl=&lt;/code&gt; (from that end on)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blank end&lt;/strong&gt;: &lt;code&gt;Score 0-0&lt;/code&gt; (hammer kept)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extra ends&lt;/strong&gt;: just continue &lt;code&gt;End n&lt;/code&gt; beyond the scheduled ends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In progress&lt;/strong&gt;: leave out the &lt;code&gt;Score&lt;/code&gt; line&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Inferring the rules from era and format
&lt;/h2&gt;

&lt;p&gt;When there are no &lt;code&gt;FGZ&lt;/code&gt; / &lt;code&gt;NoTick&lt;/code&gt; tags, the rules of the time are inferred from &lt;code&gt;Date&lt;/code&gt; and &lt;code&gt;Format&lt;/code&gt;. The reference is when World Curling (international play) adopted each rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Four-player and wheelchair&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Period&lt;/th&gt;
&lt;th&gt;&lt;code&gt;FGZ&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;NoTick&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Basis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;to June 1993&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;Before FGZ (prototype: the 1990-91 Moncton Rule, trialled at the 1992 Olympics)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;from July 1993&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;Four-rock FGZ in international play from the 1993-94 season&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;from July 2018&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;Decided at the September 2017 Congress, five-rock from 2018-19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;from July 2022&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;No-tick from the 2022-23 season (not wheelchair)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Canadian national championships alone used &lt;strong&gt;three rocks&lt;/strong&gt; from 1993-94 to 2001-02. That differs from the international basis, so it is not a default; you write &lt;code&gt;FGZ "3"&lt;/code&gt; explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixed doubles&lt;/strong&gt; uses &lt;code&gt;FGZ 3&lt;/code&gt; and &lt;code&gt;NoTick false&lt;/code&gt; regardless of era.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is protected depends on the format
&lt;/h3&gt;

&lt;p&gt;The same &lt;code&gt;FGZ&lt;/code&gt; tag protects different things in the four-player game and in mixed doubles. I only realised the two needed separate descriptions when I re-read the rules while writing the spec.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Four-player and wheelchair (R6)&lt;/strong&gt;: before the 6th stone is delivered, putting an &lt;strong&gt;opponent's&lt;/strong&gt; stone that is &lt;strong&gt;in the FGZ (between the tee line and the hog line at the playing end, excluding the house) out of play&lt;/strong&gt; is a violation. Your own stones may be removed, and stones in the house are not covered&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed doubles (R17(e))&lt;/strong&gt;: before the 4th stone is delivered, putting &lt;strong&gt;any stone already delivered or pre-positioned, own or opponent's&lt;/strong&gt;, &lt;strong&gt;out of play&lt;/strong&gt; is a violation. The location is not limited to the FGZ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No-tick (R7)&lt;/strong&gt;: before the 6th stone is delivered, moving an &lt;strong&gt;opponent's&lt;/strong&gt; stone that is in the FGZ and touching the centre line off the line, or out of the FGZ, is a violation. The ruling is the non-offending team's choice. It does not apply to mixed doubles or wheelchair&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PCN records the throw as it happened, and the player does the judging. When replaying a recorded game, however, the recommendation is not to apply the judgement and to use the &lt;code&gt;@&lt;/code&gt; boards as they are. The ruling of the day is already in the record, so re-judging with estimated physics causes false positives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engine extension line: &lt;code&gt;Anim&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Some stone movements cannot be reproduced by physics. An unnatural path transcribed from video, for example a scene where two stones met at an unexpected angle and rolled away. For movements like these, the spec reserves a line for &lt;strong&gt;hand-authored animation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight praat"&gt;&lt;code&gt;&lt;span class="m"&gt;9&lt;/span&gt; &lt;span class="k"&gt;R S&amp;gt;3&lt;/span&gt;
&lt;span class="k"&gt;Anim R0 dur=2&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="k"&gt;4 0:&lt;/span&gt;&lt;span class="m"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;30.8&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;4.0&lt;/span&gt; &lt;span class="m"&gt;0.8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.8&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;
&lt;span class="nf"&gt;@&lt;/span&gt; Y&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;0.02&lt;/span&gt;,&lt;span class="m"&gt;3.5&lt;/span&gt; R&lt;span class="m"&gt;0.45&lt;/span&gt;,&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;stone&amp;gt;&lt;/code&gt; is &lt;code&gt;&amp;lt;R|Y&amp;gt;&amp;lt;number&amp;gt;&lt;/code&gt;. &lt;code&gt;0&lt;/code&gt; is the stone thrown in this shot; &lt;code&gt;1&lt;/code&gt; and up count existing stones of that colour in the order of the previous board line&lt;/li&gt;
&lt;li&gt;Time is normalised from 0 to 1 (0 = start of the throw, 1 = stop). The real duration is &lt;code&gt;dur=&lt;/code&gt; (seconds)&lt;/li&gt;
&lt;li&gt;Interpolation between keyframes is fixed as &lt;strong&gt;centripetal Catmull-Rom (α = 0.5)&lt;/strong&gt;, so that every implementation draws the same curve&lt;/li&gt;
&lt;li&gt;Stones without an &lt;code&gt;Anim&lt;/code&gt; line stay still (no physics). Physics and animation are not mixed within one throw&lt;/li&gt;
&lt;li&gt;A stone that is not in the post-shot &lt;code&gt;@&lt;/code&gt; is removed at &lt;code&gt;t=1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A shot with &lt;code&gt;Anim&lt;/code&gt; is replayed from it in preference to &lt;code&gt;v=&lt;/code&gt;, and &lt;code&gt;@&lt;/code&gt; is its final board. Implementations that do not support it ignore the line and can still replay from &lt;code&gt;@&lt;/code&gt; or &lt;code&gt;v=&lt;/code&gt;. This is the first instance of the rule that future extensions are identified by their leading word, and lines with an unknown leading word are preserved and ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  For programs: PCN-JSON and EBNF
&lt;/h2&gt;

&lt;p&gt;The spec defines a JSON representation that maps one-to-one to the text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pcn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Red"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Yellow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"no"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hammer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"R"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"setup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"shots"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"no"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"side"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"handle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"player"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hogToHog"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"board"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s2"&gt;"Y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.42&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"v"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"est"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"nag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"yellow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;handle&lt;/code&gt; is &lt;code&gt;"&amp;gt;"&lt;/code&gt; / &lt;code&gt;"&amp;lt;"&lt;/code&gt; / &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;points&lt;/code&gt; is an integer or &lt;code&gt;null&lt;/code&gt;, and &lt;code&gt;X&lt;/code&gt; in &lt;code&gt;score&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The grammar fits on one screen in EBNF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight augeas"&gt;&lt;code&gt;&lt;span class="n"&gt;file&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;line&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;shot&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;tag&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="kr"&gt;key&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="s"&gt;"]"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"End"&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;score&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Score"&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;setup&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Setup"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;shot&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;shotspec&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"est"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;board&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;WS&lt;/span&gt; &lt;span class="n"&gt;stone&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stone&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;side&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"R"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"Y"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;shotspec&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;nag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"F"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"G"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"R"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"W"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"Z"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"T"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"H"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"S"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"P"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"?"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;handle&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;points&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;nag&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"?"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;kv&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;key&lt;/span&gt; &lt;span class="s"&gt;"="&lt;/span&gt; &lt;span class="kr"&gt;value&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;comment&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;";"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The derivation rules are written down too. The throwing side comes from &lt;code&gt;hammer&lt;/code&gt;; the hammer comes from &lt;code&gt;LSFE&lt;/code&gt; and each &lt;code&gt;Score&lt;/code&gt;; each player throws &lt;code&gt;Stones&lt;/code&gt; divided by the number of players; the percentage is &lt;code&gt;Points × 25&lt;/code&gt;; a team's percentage is &lt;code&gt;Σpoints ÷ (4 × rated shots)&lt;/code&gt; (&lt;code&gt;-&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt; are not in the denominator). The final score is the sum of the &lt;code&gt;Score&lt;/code&gt; lines, and if it disagrees with the &lt;code&gt;Result&lt;/code&gt; tag, &lt;code&gt;Result&lt;/code&gt; wins with a warning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned from implementing it
&lt;/h2&gt;

&lt;p&gt;Writing a spec and actually pushing hundreds of games through it turned out to be different jobs. Here are the things I tripped over, in order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some records' scores do not match their boards.&lt;/strong&gt; In the first public dataset I imported, the end score disagreed with the score counted from the final positions in 13% of ends. Concessions were not recorded either. In the end I removed that data from the library, and made the validation command check that "the score counted from the positions matches the &lt;code&gt;Score&lt;/code&gt; line". I now accept records from only two sources: World Curling / CURLIT records, and records transcribed from video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;@&lt;/code&gt; always wins.&lt;/strong&gt; When a record has &lt;code&gt;@&lt;/code&gt;, the player snaps to the &lt;code&gt;@&lt;/code&gt; positions even if the physics lands slightly off. I used to keep the physics result when it was within a tolerance, but then every read-and-write round trip moved stones by 1 to 8 cm. It stopped once I decided to "always keep the recorded positions". The spec's definition, "&lt;code&gt;@&lt;/code&gt; is the board as settled before the next shot", was made explicit because of this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trap of trusting &lt;code&gt;v=&lt;/code&gt; because &lt;code&gt;Engine&lt;/code&gt; matches.&lt;/strong&gt; A player replays &lt;code&gt;v=&lt;/code&gt; as is when the &lt;code&gt;[Engine]&lt;/code&gt; tag matches its own. If you fix a physics constant and forget about this, old releases get replayed under the new physics, and the positions drift without any warning. In my measurements the error doubled. At first I kept the &lt;code&gt;Engine&lt;/code&gt; version fixed, because it is an identifier carried in distributed files, and relied on procedure: whenever the physics changed, I rebuilt every record from layer ③. Since the end of September, CurlFlux bumps the version (&lt;code&gt;curlflux/1&lt;/code&gt; → &lt;code&gt;curlflux/2&lt;/code&gt;) whenever a physics change alters where the same &lt;code&gt;v=&lt;/code&gt; stops. Older files then fall back to their positions instead of replaying wrongly, and the library is rebuilt from layer ③ in the same pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The diagrams are images.&lt;/strong&gt; The position diagrams in Results Books are images embedded in the PDF, and the stone coordinates are extracted by image processing. It takes about 4 seconds per game (about 90 before I vectorised the code). Recent Live Scores, on the other hand, serve the boards as SVG, which gives the numbers directly. Converting the same game from both and comparing them, the positions agreed to within 2–3 cm. That comparison is also how I found the step needed to remove the "ghost stones" in the PDFs (stones drawn transparently that are already out of play).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some throws have no type.&lt;/strong&gt; I explained above why I added &lt;code&gt;?&lt;/code&gt;. It is a compromise between a design that requires a Task and not wanting to guess at what is unknown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Machines erase human work.&lt;/strong&gt; The &lt;code&gt;Curation&lt;/code&gt; ladder and the rule against overwriting were added after the accident where an adjusted record was overwritten by automated processing. If the format carries a mark saying "a person has worked on this file", tools can see it and stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Published tools
&lt;/h2&gt;

&lt;p&gt;The spec, grammar, JSON schema and examples are in the public repository (github.com/shinagaki/pcn). The validation and conversion tools belong to the reference implementation, CurlFlux, so here I only list how they are used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node tools/pcn.mjs validate &amp;lt;file.pcn&amp;gt;          &lt;span class="c"&gt;# grammar, derivation rules, score check&lt;/span&gt;
node tools/pcn.mjs replay &amp;lt;file.pcn&amp;gt;            &lt;span class="c"&gt;# replay with physics, error against layer-③ positions&lt;/span&gt;
node tools/pcn.mjs &lt;span class="nb"&gt;export&lt;/span&gt; &amp;lt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &amp;lt;out.pcn&amp;gt;        &lt;span class="c"&gt;# write out normalised&lt;/span&gt;
node tools/pcn.mjs json &amp;lt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &amp;lt;out.json&amp;gt;         &lt;span class="c"&gt;# to PCN-JSON&lt;/span&gt;
python tools/wcf-pdf-to-pcn.py &amp;lt;pdf&amp;gt; &amp;lt;out.pcn&amp;gt;  &lt;span class="c"&gt;# World Curling Shot by Shot PDF → PCN (layers ② ③)&lt;/span&gt;
python tools/curlit-sse-to-pcn.py …             &lt;span class="c"&gt;# Live Scores JSON/SVG → PCN&lt;/span&gt;
python tools/curlr-to-pcn.py …                  &lt;span class="c"&gt;# CurlR (a CC0 dataset) → PCN, for verification&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the browser, CurlFlux has "Open PCN", which replays your own files as they are. Positions (scenarios) built on the strategy board can be saved as PCN.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The bronze medal game of the 2018 PyeongChang Olympics, before the last stone of the final end. This record was converted from the Shot by Shot PDF and its positions adjusted against the video, so its &lt;code&gt;Curation&lt;/code&gt; is &lt;code&gt;verified&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://curlflux.creco.net/?replay=og2018-women-bronze-gbr-jpn&amp;amp;lang=en#s=168" rel="noopener noreferrer"&gt;https://curlflux.creco.net/?replay=og2018-women-bronze-gbr-jpn&amp;amp;lang=en#s=168&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The PCN of this game is in the public repository as &lt;code&gt;examples/og2018-women-bronze-gbr-jpn.pcn&lt;/code&gt;. You can see &lt;code&gt;[Ice "hh=13.8 curl=1.66 …"]&lt;/code&gt; and &lt;code&gt;[Curation "verified"]&lt;/code&gt; in the header, and on each shot line &lt;code&gt;t=&lt;/code&gt; (hog-to-hog time from the broadcast), &lt;code&gt;v=&lt;/code&gt; (with &lt;code&gt;est&lt;/code&gt;) and &lt;code&gt;@&lt;/code&gt; (with the &lt;code&gt;*&lt;/code&gt; mark).&lt;/p&gt;

&lt;h2&gt;
  
  
  Status and what comes next
&lt;/h2&gt;

&lt;p&gt;The spec is a v1.0 draft (6th revision, September 2026). The &lt;code&gt;[PCN "1.0"]&lt;/code&gt; value in files names the format family it follows and is not revised while the document is a draft; 1.0 is frozen once the content is settled. It is an unofficial document with no affiliation to World Curling or CURLIT, and where interpretations of the rules differ, the originals prevail (&lt;em&gt;The Rules of Curling&lt;/em&gt;, July 2024, and &lt;em&gt;Curling Statistics: How to Score&lt;/em&gt;, 2025).&lt;/p&gt;

&lt;p&gt;Having built it, I think the value of a notation is decided less by the spec than by "how many records flow into it". Right now there are about 660 games from World Curling's public records and from video (15 of them with every shot checked against video). I have also stored more than 900 games of this season's Live Scores, ready to convert to PCN (publishing them requires the rights holders' permission, so for now they are used only for verification and statistics). It becomes a real "common language" only once coaching apps and simulators can write PCN.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would help most right now is for people to break it.&lt;/strong&gt; Take a game you know well (one with an unusual ending, one with a measurement, one with an infraction, one you scored yourself), write it in PCN, and if something will not go in, that is a hole in the spec. I want to know before 1.0 is frozen, so please tell me in a GitHub Issue or on X (@creco). Pointing out where I have misread the rules helps just as much.&lt;/p&gt;

&lt;p&gt;The spec lives in &lt;strong&gt;a repository separate from the app&lt;/strong&gt;. A notation that belongs to one particular program cannot work as a notation, so the canonical text is on GitHub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository (spec, grammar, JSON schema, examples): &lt;a href="https://github.com/shinagaki/pcn" rel="noopener noreferrer"&gt;https://github.com/shinagaki/pcn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Spec (English): &lt;a href="https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.en.md" rel="noopener noreferrer"&gt;https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.en.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Spec (Japanese, normative): &lt;a href="https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.md" rel="noopener noreferrer"&gt;https://github.com/shinagaki/pcn/blob/main/spec/PCN_SPEC.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CurlFlux: &lt;a href="https://curlflux.creco.net/?lang=en" rel="noopener noreferrer"&gt;https://curlflux.creco.net/?lang=en&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>curling</category>
    </item>
  </channel>
</rss>
