{"id":383,"date":"2025-10-27T16:04:10","date_gmt":"2025-10-27T20:04:10","guid":{"rendered":"http:\/\/wordpress.home.internal\/?p=383"},"modified":"2025-11-04T15:52:36","modified_gmt":"2025-11-04T15:52:36","slug":"playing-by-the-rules","status":"publish","type":"post","link":"https:\/\/lcigaming.ca\/articles\/playing-by-the-rules\/","title":{"rendered":"Playing by the Rules"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this post I switch from talking about Blazor infrastructure to focusing on application logic.  I will discuss rules-based processing, which is an approach to problem solving that deviates from the typical procedural programming model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Rules-based processing came out of AI research in the 1960s and 1970s, through work on <a href=\"https:\/\/en.wikipedia.org\/wiki\/Expert_system\">Expert Systems<\/a>.  The intent was to build a system that can deduce new facts from a set of existing facts by applying a series of rules.  These rules would be specified by &#8220;experts&#8221; in a given field, thus the new system would have the appearance of being guided by these experts themselves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The term &#8220;rules-based processing&#8221; may be a bit misleading. The &#8220;rules&#8221; here are not constraints. Rather, they are <em>if-then<\/em> constructs that allow a set of facts to be progressively expanded. For example, from the rules for <a href=\"https:\/\/en.wikipedia.org\/wiki\/Crazy_Eights\">Crazy Eights<\/a>:<\/p>\n\n\n\n<dl class=\"wp-block-description-list-block-description-list\"><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>If &#8230;<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\"><strong>Then &#8230;<\/strong><\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230;<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230;<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; have a card with matching rank<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; discard that card<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; have a card with matching suit<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; discard that card<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; have an eight of any suit<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; discard that card, declare a new suit<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; have one of the above and don&#8217;t wish to discard<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; draw a card<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; none of the above and stock cards exist<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; draw a card and go back to the beginning<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\">&#8230; none of the above and the stock is empty<\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">&#8230; pass play to left<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\"><\/dd><\/dl>\n\n\n\n<p class=\"wp-block-paragraph\">Many procedural programming languages support this type of logic through constructs such as <em>if-then<\/em> and <em>switch<\/em>. Rules-based systems differ from procedural languages in several ways:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>There is no explicit nor implicit order to how rules are evaluated.<\/li>\n\n\n\n<li>Multiple rules may apply for a given set of facts.  How the rules engine reacts to this state depends on how the underlying facts are presented and what conflict resolution mechanisms are in place.<\/li>\n\n\n\n<li>There is no <em>else<\/em> or <em>default<\/em> construct.  Such a requirement would need to be specified as a test of the non-existence of a set of facts.<\/li>\n\n\n\n<li>If the application of a rule results in facts being created or modified, these facts can cause other rules to be applied, including rules that may have already been run.  This is known as <em>forward chaining<\/em>.<\/li>\n\n\n\n<li>If multiple facts are created or modified, as a result of external action or by running a rule, the rule set is evaluated for each fact individually.  There is no way to update multiple facts atomically.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These differences may cause surprising results for those more used to procedural programming.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Early rules-based systems performed a brute-force approach to applying rules based on fact changes by testing each rule for each change.  These systems were severely limited in the number of rules they could process due to the limitations in available computer processing at the time.  In the mid-1970s Charles L. Forgy created the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Rete_algorithm\">Rete Algorithm<\/a>, which greatly improved the processing time for such a system.  This algorithm uses a special structure that has indexing to help locate applicable conditions for rules associated with fact changes.  A consequence of this is that rules must be compiled into this special structure at the beginning of processing, and that facts need to be specifically inserted into and updated within this structure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are many modern implementations of the Rete algorithm, including some built into commercial decision support systems.  In this post we will use <a href=\"https:\/\/nrules.net\/?tabs=cli%2Cwindows\">NRules<\/a>, which is an open-source tool built in C#.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Simple Game<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Although the most common application for rules-base processing is in business decision making, I will instead show how the approach can be used to play the game of Tic-Tac-Toe.  Hopefully the study of a fairly trivial game will allow the ideas to be presented clearly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game of Tic-Tac-Toe involves two players alternatively placing markers (typically &#8220;X&#8221; and &#8220;O&#8221;) in cells of a 3&#215;3 grid until one player has three of their markers in a row &#8211; horizontally, vertically, or diagonally &#8211; or until there are no more empty cells. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a class library project:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Project name: TicTacToe<\/li>\n\n\n\n<li>Template: Class Library<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I used .NET 10.0 (Preview) for my project.  It should work equally well with .NET 9.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The source code for this post is available on <a href=\"https:\/\/github.com\/BarryALay\/blog1101-source\" title=\"\">GitHub<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Model<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One aspect of the game domain is clear enough &#8211; the 3&#215;3 grid. I created class <em>Grid<\/em> with an array with three rows and three columns. Less obvious is the support for the concept of three cells &#8220;in a row&#8221;. I created a <em>Line <\/em>class with three cells. I chose the name &#8220;Line&#8221; rather than &#8220;Row&#8221; to avoid confusion with the use of the word &#8220;row&#8221; to mean a horizontal set of cells. I also have a <em>Move <\/em>object to capture a player&#8217;s move and a <em>GameStage <\/em>object to capture the current state of the game, whether starting, active, or a win or a draw has taken place. All of these objects become <em>facts <\/em>in the NRules session.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create folder <em>Engine <\/em>with subfolders <em>Model <\/em>and <em>Rules<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Model\\Grid.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace TicTacToe.Engine.Model\n{\n    internal enum CellType\n    {\n        Empty, X, O, None\n    }\n\n    internal class Grid\n    {\n        public static int MinRow = 1;\n        public static int MaxRow = 3;\n        public static int MinColumn = 1;\n        public static int MaxColumn = 3;\n\n        private readonly CellType&#91;,&#93; cells = new CellType&#91;3, 3&#93;\n        {\n            { CellType.Empty, CellType.Empty, CellType.Empty },\n            { CellType.Empty, CellType.Empty, CellType.Empty },\n            { CellType.Empty, CellType.Empty, CellType.Empty }\n        };\n\n        public CellType this&#91;int row, int column&#93;\n        {\n            get\n            {\n                if (row &lt; MinRow || row > MaxRow || \n                    column &lt; MinColumn || column > MaxColumn) return CellType.None;\n                return cells&#91;row - 1, column - 1&#93;;\n            }\n            set\n            {\n                if (row &lt; MinRow || row > MaxRow || \n                    column &lt; MinColumn || column > MaxColumn) return;\n                cells&#91;row - 1, column - 1&#93; = value;\n            }\n        }\n\n        public void SetCellType(int row, int column, CellType cellType) => \n            this&#91;row, column&#93; = cellType;\n\n        public void Clear()\n        {\n            for (int row = MinRow; row &lt;= MaxRow; row++)\n                for (int column = MinColumn; column &lt;= MaxColumn; column++)\n                    this&#91;row, column&#93; = CellType.Empty;\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">Empty<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">None<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Grid<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MinRow<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MaxRow<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MinColumn<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MaxColumn<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">&#91;,&#93; <\/span><span style=\"color: #6F42C1\">cells<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">&#91;<\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            { CellType.Empty, CellType.Empty, CellType.Empty },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            { CellType.Empty, CellType.Empty, CellType.Empty },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            { CellType.Empty, CellType.Empty, CellType.Empty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        };<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">this<\/span><span style=\"color: #24292E\">&#91;<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">get<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (row <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinRow <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> row <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxRow <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    column <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinColumn <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> column <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxColumn) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> CellType.None;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> cells&#91;row <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">set<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (row <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinRow <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> row <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxRow <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    column <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinColumn <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> column <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxColumn) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cells&#91;row <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">SetCellType<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cellType<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #005CC5\">this<\/span><span style=\"color: #24292E\">&#91;row, column&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> cellType;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Clear<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">for<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> MinRow; row <\/span><span style=\"color: #D73A49\">&lt;=<\/span><span style=\"color: #24292E\"> MaxRow; row<\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">for<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> MinColumn; column <\/span><span style=\"color: #D73A49\">&lt;=<\/span><span style=\"color: #24292E\"> MaxColumn; column<\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #005CC5\">this<\/span><span style=\"color: #24292E\">&#91;row, column&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Note that I have a public method <em>SetCellType<\/em> that is a proxy for the indexer set method. The reason for this will become apparent shortly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Model\\Move.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace TicTacToe.Engine.Model\n{\n    internal enum MoveStatus\n    {\n        Pending, Processed, Error\n    }\n\n    internal class Move(CellType type, int row, int column)\n    {\n        public CellType Type { get; set; } = type;\n        public MoveStatus Status { get; set; } = MoveStatus.Pending;\n\n        public int Row { get; } = row;\n\n        public int Column { get; } = column;\n\n        public void SetStatus(MoveStatus status) => Status = status;\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MoveStatus<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">Pending<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Processed<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Error<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Type<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> type;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MoveStatus<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Status<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> MoveStatus.Pending;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Row<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> row;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Column<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> column;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">SetStatus<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">MoveStatus<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">status<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Status <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> status;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Once again, we have an explicit set method.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create Engine\\Model\\Line.cs:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace TicTacToe.Engine.Model\n{\n    internal enum LineType\n    {\n        Row, Column, Diagonal\n    }\n\n    internal class Line(LineType type, int id)\n    {\n        public LineType Type { get; set; } = type;\n\n        public int Id { get; set; } = id;\n\n        public static int MaxLines = 8;\n\n        public static int MinIndex = 1;\n        public static int MaxIndex = 3;\n\n        public static int MainDiagonal = 0;\n        public static int CounterDiagonal = 1;\n\n        private CellType[] cells = &#91;CellType.Empty, CellType.Empty, CellType.Empty&#93;;\n\n        private readonly CellType[] XWin = &#91;CellType.X, CellType.X, CellType.X&#93;;\n        private readonly CellType[] OWin = &#91;CellType.O, CellType.O, CellType.O&#93;;\n\n        public void Clear()\n        {\n            cells = &#91;CellType.Empty, CellType.Empty, CellType.Empty&#93;;\n        }\n\n        public bool AcceptsMove(Move move)\n        {\n            if (move.Row &lt; MinIndex || move.Row > MaxIndex || \n                move.Column &lt; MinIndex || move.Column > MaxIndex) return false;\n            switch (Type)\n            {\n                case LineType.Row:\n                    return Id == move.Row &amp;&amp; cells&#91;move.Column - 1&#93; == CellType.Empty;\n                case LineType.Column:\n                    return Id == move.Column &amp;&amp; cells&#91;move.Row - 1&#93; == CellType.Empty;\n                case LineType.Diagonal:\n                    if (Id == MainDiagonal)\n                    {\n                        return move.Row == move.Column &amp;&amp; \n                               cells&#91;move.Column - 1&#93; == CellType.Empty;\n                    }\n                    else\n                    {\n                        return move.Row + move.Column == 4 &amp;&amp; \n                               cells&#91;move.Column - 1&#93; == CellType.Empty;\n                    }\n            }\n\n            return false;\n        }\n\n        public void AddMove(Move move)\n        {\n            if (!AcceptsMove(move)) return;\n            switch (Type)\n            {\n                case LineType.Row:\n                    cells&#91;move.Column - 1&#93; = move.Type;\n                    break;\n                case LineType.Column:\n                    cells&#91;move.Row - 1&#93; = move.Type;\n                    break;\n                case LineType.Diagonal:\n                    cells&#91;move.Column - 1&#93; = move.Type;\n                    break;\n            }\n        }\n\n        public bool XWins => cells.SequenceEqual(XWin);\n        public bool OWins => cells.SequenceEqual(OWin);\n        public bool HasWin()\n        {\n            return XWins || OWins;\n        }\n\n        public bool IsFullMixed()\n        {\n            if (HasWin()) return false;\n            return !cells.Any(p => p == CellType.Empty);\n        }\n\n        public CellType GetWinType()\n        {\n            if (HasWin())\n            {\n                return cells&#91;0&#93;;\n            }\n            else\n            {\n                return CellType.Empty;\n            }\n        }\n\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">Row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Column<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Diagonal<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">id<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Type<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> type;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Id<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> id;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MaxLines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">8<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MinIndex<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MaxIndex<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MainDiagonal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterDiagonal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">cells<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;CellType.Empty, CellType.Empty, CellType.Empty&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">XWin<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;CellType.X, CellType.X, CellType.X&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">OWin<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;CellType.O, CellType.O, CellType.O&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Clear<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            cells <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;CellType.Empty, CellType.Empty, CellType.Empty&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AcceptsMove<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (move.Row <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinIndex <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> move.Row <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxIndex <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                move.Column <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> MinIndex <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> move.Column <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> MaxIndex) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">switch<\/span><span style=\"color: #24292E\"> (Type)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Row<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Id <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> move.Row <\/span><span style=\"color: #D73A49\">&amp;&amp;<\/span><span style=\"color: #24292E\"> cells&#91;move.Column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Column<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Id <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> move.Column <\/span><span style=\"color: #D73A49\">&amp;&amp;<\/span><span style=\"color: #24292E\"> cells&#91;move.Row <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Diagonal<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (Id <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MainDiagonal)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> move.Row <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> move.Column <\/span><span style=\"color: #D73A49\">&amp;&amp;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                               cells&#91;move.Column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> move.Row <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> move.Column <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">4<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">&amp;&amp;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                               cells&#91;move.Column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AddMove<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #6F42C1\">AcceptsMove<\/span><span style=\"color: #24292E\">(move)) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">switch<\/span><span style=\"color: #24292E\"> (Type)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Row<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cells&#91;move.Column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> move.Type;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Column<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cells&#91;move.Row <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> move.Type;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LineType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Diagonal<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cells&#91;move.Column <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> move.Type;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">XWins<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> cells.<\/span><span style=\"color: #6F42C1\">SequenceEqual<\/span><span style=\"color: #24292E\">(XWin);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">OWins<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> cells.<\/span><span style=\"color: #6F42C1\">SequenceEqual<\/span><span style=\"color: #24292E\">(OWin);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">HasWin<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> XWins <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> OWins;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IsFullMixed<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">HasWin<\/span><span style=\"color: #24292E\">()) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #24292E\">cells.<\/span><span style=\"color: #6F42C1\">Any<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">p<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> p <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetWinType<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">HasWin<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> cells&#91;<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This is the most complex of the model objects.  When working with rules processing in general and <em>NRules <\/em>in particular there is a tradeoff in where to put the complexity.  Much of the testing that is done in methods such as <em>AcceptsMove <\/em>and <em>HasWin <\/em>could be done using rules.  This tradeoff will become more apparent when we look at the rules themselves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Model\\GameStage.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace TicTacToe.Engine.Model\n{\n    internal enum GameStageType\n    {\n        Initial, New, Active, Win, Draw, Error\n    }\n\n    internal enum GameStageErrorType\n    {\n        None, MoveNotValid, MoveInUse\n    }\n\n    internal class GameStage(GameStageType stage)\n    {\n        public GameStageType Stage { get; set; } = stage;\n        public CellType Winner { get; set; } = CellType.Empty;\n        public GameStageErrorType Error { get; set; } = GameStageErrorType.None;\n\n        public void SetStage(GameStageType newStage) => Stage = newStage;\n        public void SetWinner(CellType winner) => Winner = winner;\n        public void SetErrorType(GameStageErrorType error) => Error = error;\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">Initial<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">New<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Active<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Win<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Draw<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Error<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStageErrorType<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">None<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">MoveNotValid<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">MoveInUse<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Stage<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> stage;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Winner<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStageErrorType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Error<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> GameStageErrorType.None;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">newStage<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Stage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> newStage;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">SetWinner<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">winner<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Winner <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> winner;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">SetErrorType<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">GameStageErrorType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">error<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Error <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> error;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">There are six stages for the game engine:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-border-color has-white-border-color\"><tbody><tr><td><strong>Initial<\/strong><\/td><td>Engine is initialized, but no actual game is in progress<\/td><\/tr><tr><td><strong>New<\/strong><\/td><td>A trigger stage to start a new game<\/td><\/tr><tr><td><strong>Active<\/strong><\/td><td>A tic-tac-toe game is currently in progress<\/td><\/tr><tr><td><strong>Win<\/strong><\/td><td>The tic-tac-toe game has been won<\/td><\/tr><tr><td><strong>Draw<\/strong><\/td><td>The tic-tac-toe game has ended in a draw<\/td><\/tr><tr><td><strong>Error<\/strong><\/td><td>An error has occurred<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The game will switch between these stages as a result of external actions and rule processing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The API<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As we are building a class library, we will need to provide some sort of API to be able to use it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>API.cs<\/em> at the root of the class library project (or rename the template-provided <em>Class1.cs<\/em>):<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#24292e;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules;\nusing NRules.Fluent;\nusing System.Reflection;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe\n{\n    public class API\n    {\n        private readonly RuleRepository ruleRepository;\n        private readonly ISessionFactory sessionFactory;\n        private readonly ISession session;\n        private readonly GameStage gameStage;\n        private readonly Grid grid;\n\n        public void NewGame()\n        {\n            gameStage.SetStage(GameStageType.New);\n            session.Update(gameStage);\n            session.Fire();\n        }\n\n        public enum Side { X, O, None };\n        public void Move(Side side, int row, int column)\n        {\n            if (side == Side.None) return;\n            CellType type = side switch\n            {\n                Side.X => CellType.X,\n                Side.O => CellType.O,\n                _ => CellType.Empty,\n            };\n            var move = new Move(type, row, column);\n            session.Insert(move);\n            session.Fire();\n        }\n\n        public API()\n        {\n            ruleRepository = new RuleRepository();\n            ruleRepository.Load(\n                x => x.PrivateTypes(true).From(Assembly.GetExecutingAssembly()));\n            sessionFactory = ruleRepository.Compile();\n            session = sessionFactory.CreateSession();\n\n            \/\/ initialize model\n\n            gameStage = new GameStage(GameStageType.Initial);\n            session.Insert(gameStage);\n\n            grid = new Grid();\n            session.Insert(grid);\n\n            foreach (int item in Enumerable.Range(1, 3))\n            {\n                session.Insert(new Line(LineType.Row, item));\n                session.Insert(new Line(LineType.Column, item));\n            }\n            session.Insert(new Line(LineType.Diagonal, Line.MainDiagonal));\n            session.Insert(new Line(LineType.Diagonal, Line.CounterDiagonal));\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Reflection<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleRepository<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ruleRepository<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ISessionFactory<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">sessionFactory<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ISession<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">session<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NewGame<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.New);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">None<\/span><span style=\"color: #24292E\"> };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">side<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (side <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> Side.None) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> side <\/span><span style=\"color: #D73A49\">switch<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.X,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.O,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.Empty,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(type, row, column);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(move);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            ruleRepository <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleRepository<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            ruleRepository.<\/span><span style=\"color: #6F42C1\">Load<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> x.<\/span><span style=\"color: #6F42C1\">PrivateTypes<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">).<\/span><span style=\"color: #6F42C1\">From<\/span><span style=\"color: #24292E\">(Assembly.<\/span><span style=\"color: #6F42C1\">GetExecutingAssembly<\/span><span style=\"color: #24292E\">()));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            sessionFactory <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> ruleRepository.<\/span><span style=\"color: #6F42C1\">Compile<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> sessionFactory.<\/span><span style=\"color: #6F42C1\">CreateSession<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ initialize model<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\">(GameStageType.Initial);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            grid <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(grid);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">item<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> Enumerable.<\/span><span style=\"color: #6F42C1\">Range<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Row, item));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Column, item));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Diagonal, Line.MainDiagonal));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Diagonal, Line.CounterDiagonal));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The constructor at lines 38-61 initializes the <em>NRules <\/em>engine:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The rule repository is created and loaded with the rules defined in the library using reflection.  The <em>PrivateTypes <\/em>method is used to allow rules that are defined as &#8220;internal&#8221; to be loaded.  By default only public classes are examined.<\/li>\n\n\n\n<li>The loaded rules are compiled into the session.<\/li>\n\n\n\n<li>The model is initialized with the <em>GameStage<\/em>, <em>Grid<\/em>, and the eight <em>Line<\/em>s needed to represent the state of the game.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the <em>Line <\/em>instances are created and inserted individually. <em>NRules <\/em>has its own internal structures for efficiently accessing facts. Using a local structure such as a <em>List <\/em>here could be confusing as the rules engine would not be aware of list operations such as <em>Add <\/em>or <em>Remove<\/em>, resulting in a disparity between what is visible in the external program and what is &#8220;known&#8221; to the rules engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>NewGame <\/em>method at lines 16-21 updates the <em>GameStage <\/em>to trigger a new game. Note that while the <em>GameStage <\/em>instance is available as a local variable to be modified, in order for the rules engine to act upon any changes it needs to be notified of these changes through the <em>Update <\/em>method on the rules session. The session <em>Fire <\/em>method is called to run any rules that are impacted by the changes. For details on what happens next, see the next section.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>Move <\/em>method at lines 23-36 introduces a new game move. The new object is introduced to the rules engine via the <em>Insert<\/em> method on the session. The call to the session <em>Fire <\/em>method causes the move to be evaluated and acted upon. This will be detailed in the next section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Rules<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Rules are composed of two parts: the <em>antecedent<\/em>, which describes the conditions under which the rule applies, and the <em>consequent<\/em>, which describes the action to take under those circumstances. The antecedent is specified as a set of conditions for <em>facts<\/em> within the system. The consequent is specified as a set of updates to these <em>facts<\/em>. In <em>NRules <\/em>these <em>facts <\/em>are represented by C# class objects that have been inserted into the current <em>NRules session<\/em>. When a fact is inserted or updated <em>NRules <\/em>locates rules that have this fact as part of their antecedent. If all of the pre-conditions for a rule are satisfied the rule becomes <em>activated<\/em>. When the <em>Fire <\/em>method of the <em>NRules session<\/em> is called the set of activated rules is examined to determine which rule has the highest priority. That rule then <em>fires<\/em>, which means that its consequent is acted upon. While it is possible to explicitly specify the priority for a rule, it is best to avoid having ambiguity in which rule is fired by choosing the pre-conditions carefully.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The rules engine is designed to use rules to transform facts into new or updated facts.  Since <em>NRules <\/em>uses plain C# objects for facts it is possible to update the facts in plain C# code.  The rules engine will be unaware of these changes unless you explicitly tell it that you have done so.  As a result you need to be careful when updating facts in open code.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Getting Started<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the firing of a rule depends on its pre-conditions being met.  There is no way to force a rule to be fired directly.  In some cases we want to indirectly cause a rule to fire by deliberately introducing a fact change.  In the previous section we set the <em>GameStage Stage <\/em>to <em>New<\/em> in the <em>API NewGame <\/em>method.  The <em>NewGameRule<\/em> responds to this change and (re)initializes the <em>Grid<\/em> and <em>Line<\/em>s for a new game.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Rules\\NewGameRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#24292e;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing NRules.RuleModel;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class NewGameRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Grid grid = default!;\n            IEnumerable&lt;Line> lines = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.New)\n                .Match(() => grid)\n                .Query(() => lines, query => query.Match&lt;Line>([]).Collect())\n                ;\n\n            Then()\n                .Do(ctx => stage.SetStage(GameStageType.Active))\n                .Do(ctx => ctx.Update(stage))\n                .Do(ctx => ClearLines(ctx, lines))\n                .Do(ctx => grid.Clear())\n                .Do(ctx => ctx.Update(grid))\n                ;\n        }\n\n        private static void ClearLines(IContext context, IEnumerable&lt;Line> lines)\n        {\n            foreach (Line line in lines)\n            {\n                line.Clear();\n                context.Update(line);\n            }\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RuleModel<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NewGameRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.New)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> lines, <\/span><span style=\"color: #6F42C1\">query<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> query.<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;([]).<\/span><span style=\"color: #6F42C1\">Collect<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Active))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(stage))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClearLines<\/span><span style=\"color: #24292E\">(ctx, lines))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid.<\/span><span style=\"color: #6F42C1\">Clear<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(grid))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClearLines<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">IContext<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">context<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> lines)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                line.<\/span><span style=\"color: #6F42C1\">Clear<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                context.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(line);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lines 15-19 above list the conditions for this rule firing (the antecedent).  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Line 16 matches on an instance of <em>GameStage <\/em>that has a <em>State <\/em>of <em>New<\/em>.  As it happens, we will only ever have one instance of <em>GameStage<\/em>, so this rule will come into effect if that instance happens to be in stage <em>New<\/em>.  This <em>GameStage <\/em>instance is assigned to the local variable <em>stage<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Line 17 matches on any instance of <em>Grid<\/em>.  Once again, there will only be one instance, and that will be assigned to variable <em>grid<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Line 18 matches on all instances of <em>Line<\/em>, and assigns the collection to the variable <em>lines<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the GameStage is in the correct state, this rule will fire and cause lines 21-27 to execute (the consequent).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lines 22 and 23 update the <em>GameStage Stage <\/em>to <em>Active<\/em>. Note that the setter method <em>SetStage <\/em>is called rather than setting the public property <em>Stage<\/em>. This is because the <em>Do <\/em>method accepts an <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/advanced-topics\/expression-trees\/\">expression tree<\/a>. Expression trees are fairly limited in what they can do, and in particular do not support assignment. This update is done first so that the rule will not be activated again when the <em>Grid <\/em>and <em>Line<\/em>s are updated. Note that after modifying the <em>GameStage <\/em>we need to inform the rules engine of the change via the <em>Update <\/em>method on the <em>NRules context<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Line 24 calls the static method <em>ClearLines <\/em>in order to set all of the <em>Line <\/em>instances that were captured in the <em>lines <\/em>collection to their initial state. As with <em>GameStage<\/em>, we need to inform the rules engine of the modifications to the <em>Line <\/em>instances via the <em>Update <\/em>method on the <em>context<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lines 25 and 26 clear the <em>Grid<\/em>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Making Moves<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>API Move <\/em>method simply inserts a new <em>Move <\/em>object into the session.  This is intended to trigger the <em>MoveRule <\/em>rule.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Rules\\MoveRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing NRules.RuleModel;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class MoveRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Grid grid = default!;\n            Move move = default!;\n            IEnumerable&lt;Line> lines = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, move => move.Status == MoveStatus.Pending)\n                .Match(() => grid, grid => grid&#91;move.Row, move.Column&#93; == CellType.Empty)\n                .Query(() => lines, query => query\n                    .Match&lt;Line>(l => l.AcceptsMove(move))\n                    .Collect()\n                )\n                ;\n\n            Then()\n                .Do(ctx => move.SetStatus(MoveStatus.Processed))\n                .Do(ctx => ctx.Update(move))\n                .Do(ctx => grid.SetCellType(move.Row, move.Column, move.Type))\n                .Do(ctx => ctx.Update(grid))\n                .Do(ctx => UpdateLines(ctx, lines, move))\n                ;\n        }\n\n        private static void UpdateLines(IContext context, IEnumerable&lt;Line> lines, Move move)\n        {\n            foreach (Line line in lines)\n            {\n                line.AddMove(move);\n                context.Update(line);\n            }\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RuleModel<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MoveRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Pending)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid&#91;move.Row, move.Column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> lines, <\/span><span style=\"color: #6F42C1\">query<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> query<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">AcceptsMove<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Collect<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.<\/span><span style=\"color: #6F42C1\">SetStatus<\/span><span style=\"color: #24292E\">(MoveStatus.Processed))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid.<\/span><span style=\"color: #6F42C1\">SetCellType<\/span><span style=\"color: #24292E\">(move.Row, move.Column, move.Type))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(grid))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UpdateLines<\/span><span style=\"color: #24292E\">(ctx, lines, move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UpdateLines<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">IContext<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">context<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> lines)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                line.<\/span><span style=\"color: #6F42C1\">AddMove<\/span><span style=\"color: #24292E\">(move);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                context.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(line);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now we have a couple of more pre-conditions to meet.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <em>GameStage Stage <\/em>needs to be <em>Active<\/em>.<\/li>\n\n\n\n<li>We have a <em>Move <\/em>that is in <em>Status Pending<\/em>.<\/li>\n\n\n\n<li>The <em>Grid <\/em>cell that is the target of the <em>Move <\/em>is <em>Empty<\/em>.<\/li>\n\n\n\n<li>We have a set of <em>Line<\/em>s that will accept the <em>Move<\/em>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Note that we have used the <em>AcceptsMove <\/em>method of <em>Line <\/em>to determine if the <em>Line <\/em>can accommodate the <em>Move <\/em>(is appropriate for the <em>Row <\/em>and <em>Column <\/em>and has an <em>Empty <\/em>spot for the new move <em>Type<\/em>). We could have instead put the test in the rule itself. Copying the logic from <em>AcceptsMove <\/em>into the rule would have made it much more complex and harder to debug. The tradeoff is that placing the logic in the rule would allow more flexibility in handling special cases driven by other conditions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If these conditions are met make some updates.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set the <em>Move Status <\/em>to <em>Processed<\/em>.<\/li>\n\n\n\n<li>Set the target <em>Grid <\/em>cell to the <em>Move Type<\/em>.<\/li>\n\n\n\n<li>Update the matched <em>Line<\/em>s to account for the <em>Move<\/em>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Note that we first set the <em>Status <\/em>for <em>Move <\/em>to <em>Processed<\/em>. This prevents the rule from re-activating when the <em>Grid <\/em>and <em>Line<\/em>s are updated.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handling Errors<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The requirement of multiple pre-conditions for this rule leads to the question of what happens when they are not all met.  More specifically, what happens we have a <em>Pending Move <\/em>that targets a <em>Grid <\/em>cell that is already in use?  Such a move would be invalid but it might be better to have some sort of response rather than just ignoring it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In procedural code we might use a &#8220;then&#8221; clause to handle the error condition.  Such a construct is not available here.  Instead, we need to create another rule to handle the condition.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\Rules\\DuplicateMoveRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class DuplicateMoveRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Move move = default!;\n            Grid grid = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, m => m.Status == MoveStatus.Pending)\n                .Or(x => x\n                    .Match(() => grid, g => g&#91;move.Row, move.Column&#93; == CellType.X)\n                    .Match(() => grid, g => g&#91;move.Row, move.Column&#93; == CellType.O)\n                    )\n                ;\n\n            Then()\n                .Do(ctx => move.SetStatus(MoveStatus.Error))\n                .Do(ctx => ctx.Update(move))\n                .Do(ctx => stage.SetStage(GameStageType.Error))\n                .Do(ctx => stage.SetErrorType(GameStageErrorType.MoveInUse))\n                .Do(ctx => ctx.Update(stage))\n                ;\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DuplicateMoveRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">m<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> m.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Pending)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Or<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> x<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">g<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> g&#91;move.Row, move.Column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.X)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">g<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> g&#91;move.Row, move.Column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.O)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.<\/span><span style=\"color: #6F42C1\">SetStatus<\/span><span style=\"color: #24292E\">(MoveStatus.Error))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Error))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetErrorType<\/span><span style=\"color: #24292E\">(GameStageErrorType.MoveInUse))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(stage))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This tests for the case where the target of the <em>Pending Move <\/em>already has a marker from a previous move and sets the error conditions appropriately.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We also have the case where the proposed move is not on the board at all, for example if it specifies column &#8220;4&#8221;.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create Engine\\Rules\\InvalidMoveRule.cs:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class InvalidMoveRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Move move = default!;\n            Grid grid = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, m => m.Status == MoveStatus.Pending)\n                .Match(() => grid, g => g&#91;move.Row, move.Column&#93; == CellType.None);\n                ;\n\n            Then()\n                .Do(ctx => move.SetStatus(MoveStatus.Error))\n                .Do(ctx => ctx.Update(move))\n                .Do(ctx => stage.SetStage(GameStageType.Error))\n                .Do(ctx => stage.SetErrorType(GameStageErrorType.MoveNotValid))\n                .Do(ctx => ctx.Update(stage))\n                ;\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InvalidMoveRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">m<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> m.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Pending)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">g<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> g&#91;move.Row, move.Column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.None);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.<\/span><span style=\"color: #6F42C1\">SetStatus<\/span><span style=\"color: #24292E\">(MoveStatus.Error))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Error))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetErrorType<\/span><span style=\"color: #24292E\">(GameStageErrorType.MoveNotValid))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(stage))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our <em>Grid <\/em>is set up to respond <em>None <\/em>when queried about the type of a cell that is out of range.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ordinarily you would put checks in place to ensure that such a <em>Move <\/em>is not created in the first place, perhaps by making it impossible to select such an action in a game front end.  It is still worthwhile to handle the condition in the backend logic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Both of these rules cause the game to enter a state that is unrecoverable via the API.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modify <em>API.cs<\/em> to add a way out:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules;\nusing NRules.Fluent;\nusing System.Reflection;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe\n{\n    public class API\n    {\n\n...\n\n        public void ResetError()\n        {\n            if (gameStage.Stage != GameStageType.Error) return;\n            gameStage.SetStage(GameStageType.Active);\n            session.Update(gameStage);\n            session.Fire();\n        }\n\n...\n\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Reflection<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ResetError<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (gameStage.Stage <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> GameStageType.Error) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Active);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since the <em>Move <\/em>that caused the error has already been transitioned to <em>Status Error<\/em>, this will not cause the problem to reoccur.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that while the above two rules handle error conditions, this does not prevent the pre-condition tests for other rules from being executed on error.  For this reason, tests such as <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>    .Match(() => grid, grid => grid&#91;move.Row, move.Column&#93; == CellType.Empty)<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #24292E\">    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid&#91;move.Row, move.Column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">for MoveRule need to function when the move row\/column values are out of bounds.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Ending the Game<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">If we keep making valid moves we will eventually get to the point where either someone has won or the game has ended in a draw.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the first case, create <em>Engine\\Rules\\HaveWinRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class HaveWinRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Move move = default!;\n            IEnumerable&lt;Line> lines = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, move => move.Status == MoveStatus.Processed)\n                .Query(() => lines, query => query\n                    .Match&lt;Line>(l => l.HasWin())\n                    .Collect()\n                    .Where(l => l.Any())\n                )\n                ;\n\n            Then()\n                .Do(ctx => stage.SetStage(GameStageType.Win))\n                .Do(ctx => stage.SetWinner(lines.First().GetWinType()))\n                .Do(ctx => ctx.Update(stage))\n                ;\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">HaveWinRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Processed)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> lines, <\/span><span style=\"color: #6F42C1\">query<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> query<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">HasWin<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Collect<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Where<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">Any<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Win))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetWinner<\/span><span style=\"color: #24292E\">(lines.<\/span><span style=\"color: #6F42C1\">First<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">GetWinType<\/span><span style=\"color: #24292E\">()))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(stage))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since a single move can create more than one winning three-in-a-row line, the query above collects all of them and the consequent picks one to indicate the win.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the second case, create <em>Engine\\Rules\\HaveDrawRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class HaveDrawRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Move move = default!;\n            IEnumerable&lt;Line> lines = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, move => move.Status == MoveStatus.Processed)\n                .Query(() => lines, query => query\n                    .Match&lt;Line>(l => l.IsFullMixed())\n                    .Collect()\n                    .Where(l => l.Count() == Line.MaxLines)\n                )\n                ;\n\n            Then()\n                .Do(ctx => stage.SetStage(GameStageType.Draw))\n                .Do(ctx => stage.SetWinner(CellType.Empty))\n                .Do(ctx => ctx.Update(stage))\n                ;\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">HaveDrawRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Processed)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> lines, <\/span><span style=\"color: #6F42C1\">query<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> query<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">IsFullMixed<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Collect<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Where<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">Count<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> Line.MaxLines)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Draw))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage.<\/span><span style=\"color: #6F42C1\">SetWinner<\/span><span style=\"color: #24292E\">(CellType.Empty))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(stage))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is slightly more complicated.  We need to make sure that all of the lines have three filled cells and are not wins.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These two rules depend on the results of <em>MoveRule <\/em>&#8211; when <em>MoveRule <\/em>sets the <em>Move Status <\/em>to <em>Processed <\/em>and updates the <em>Line<\/em>s, these two rules test the results.  As such, they are examples of <em>forward chaining<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Testing is always a good idea, but it is especially helpful when developing with <em>NRules<\/em>.  I find that even simple changes can cause some mystifying results without insight into what is happening.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I created an <em>MSTest <\/em>project called <em>TicTacToeTest <\/em>in the same <em>TicTacToe <\/em>solution and referenced the main project.  I also added some extra methods to <em>API.cs<\/em> for testing purposes:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules;\nusing NRules.Diagnostics;\nusing NRules.Fluent;\nusing System.Reflection;\nusing System.Text;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe\n{\n    public class API\n    {\n        private readonly RuleRepository ruleRepository;\n        private readonly ISessionFactory sessionFactory;\n        private readonly ISession session;\n        private readonly GameStage gameStage;\n        private readonly Grid grid;\n\n        public void NewGame()\n        {\n            gameStage.SetStage(GameStageType.New);\n            session.Update(gameStage);\n            session.Fire();\n        }\n\n        public enum Side { X, O, None };\n        public void Move(Side side, int row, int column)\n        {\n            if (side == Side.None) return;\n            CellType type = side switch\n            {\n                Side.X => CellType.X,\n                Side.O => CellType.O,\n                _ => CellType.Empty,\n            };\n            var move = new Move(type, row, column);\n            session.Insert(move);\n            session.Fire();\n        }\n\n        public void ResetError()\n        {\n            if (gameStage.Stage != GameStageType.Error) return;\n            gameStage.SetStage(GameStageType.Active);\n            session.Update(gameStage);\n            session.Fire();\n        }\n\n        public List&lt;string> GetRules()\n        {\n            List&lt;string> rules = [];\n            foreach (var rule in ruleRepository.GetRules())\n            {\n                rules.Add(rule.Name);\n            }\n            return rules;\n        }\n\n        public List&lt;string> GetLines()\n        {\n            List&lt;string> lines = [];\n            foreach (var line in session.Query&lt;Line>())\n            {\n                lines.Add(line.ToString());\n            }\n            return lines;\n        }\n\n        public List&lt;string> GetGrid()\n        {\n            List&lt;string> gridLines = [];\n            for (int row = Grid.MinRow; row &lt;= Grid.MaxRow; row++)\n            {\n                StringBuilder sb = new();\n                for (int column = Grid.MinColumn; column &lt;= Grid.MaxColumn; column++)\n                {\n                    sb.Append(grid&#91;row, column&#93; switch { \n                                                    CellType.Empty => \" \", \n                                                    CellType.X => \"X\", \n                                                    CellType.O => \"O\", \n                                                    _ => \"*\" });\n                }\n                gridLines.Add(sb.ToString());\n            }\n            return gridLines;\n        }\n\n        public enum GameStatus { None, Active, Win, Draw, Error };\n        public GameStatus GetStatus()\n        {\n            return gameStage.Stage switch\n            {\n                GameStageType.Active => GameStatus.Active,\n                GameStageType.Win => GameStatus.Win,\n                GameStageType.Draw => GameStatus.Draw,\n                GameStageType.Error => GameStatus.Error,\n                _ => GameStatus.None,\n            };\n        }\n\n        public enum ErrorType { None, MoveNotValid, MoveInUse };\n        public ErrorType GetErrorType()\n        {\n            return gameStage.Error switch\n            {\n                GameStageErrorType.MoveNotValid => ErrorType.MoveNotValid,\n                GameStageErrorType.MoveInUse => ErrorType.MoveInUse,\n                _ => ErrorType.None,\n            };\n        }\n\n        public Side GetWinner()\n        {\n            if (gameStage.Stage == GameStageType.Win)\n            {\n                return gameStage.Winner switch\n                {\n                    CellType.X => Side.X,\n                    CellType.O => Side.O,\n                    _ => Side.None,\n                };\n            }\n            else\n            {\n                return Side.None;\n            }\n        }\n\n        private void RuleFiring(Object? obj, AgendaEventArgs args)\n        {\n            Console.WriteLine($\"..rule {args.Rule.Name} firing\");\n        }\n\n        private void RuleFired(Object? obj, AgendaEventArgs args)\n        {\n            Console.WriteLine($\"..rule {args.Rule.Name} fired\");\n        }\n\n        public API()\n        {\n            ruleRepository = new RuleRepository();\n            ruleRepository.Load(\n                x => x.PrivateTypes(true).From(Assembly.GetExecutingAssembly()));\n            sessionFactory = ruleRepository.Compile();\n            session = sessionFactory.CreateSession();\n\n            \/\/ initialize model\n\n            gameStage = new GameStage(GameStageType.Initial);\n            session.Insert(gameStage);\n\n            grid = new Grid();\n            session.Insert(grid);\n\n            foreach (int item in Enumerable.Range(1, 3))\n            {\n                session.Insert(new Line(LineType.Row, item));\n                session.Insert(new Line(LineType.Column, item));\n            }\n            session.Insert(new Line(LineType.Diagonal, Line.MainDiagonal));\n            session.Insert(new Line(LineType.Diagonal, Line.CounterDiagonal));\n\n            session.Events.RuleFiringEvent += RuleFiring;\n            session.Events.RuleFiredEvent += RuleFired;\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Diagnostics<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Reflection<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Text<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleRepository<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ruleRepository<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ISessionFactory<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">sessionFactory<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ISession<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">session<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NewGame<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.New);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">None<\/span><span style=\"color: #24292E\"> };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">side<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (side <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> Side.None) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> side <\/span><span style=\"color: #D73A49\">switch<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.X,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.O,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> CellType.Empty,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(type, row, column);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(move);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ResetError<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (gameStage.Stage <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> GameStageType.Error) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage.<\/span><span style=\"color: #6F42C1\">SetStage<\/span><span style=\"color: #24292E\">(GameStageType.Active);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Fire<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">GetRules<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">rules<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> [];<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">rule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> ruleRepository.<\/span><span style=\"color: #6F42C1\">GetRules<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                rules.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(rule.Name);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> rules;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">GetLines<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> [];<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> session.<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;())<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                lines.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(line.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> lines;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">GetGrid<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">gridLines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> [];<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">for<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> Grid.MinRow; row <\/span><span style=\"color: #D73A49\">&lt;=<\/span><span style=\"color: #24292E\"> Grid.MaxRow; row<\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">StringBuilder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">sb<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">for<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> Grid.MinColumn; column <\/span><span style=\"color: #D73A49\">&lt;=<\/span><span style=\"color: #24292E\"> Grid.MaxColumn; column<\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                    sb.<\/span><span style=\"color: #6F42C1\">Append<\/span><span style=\"color: #24292E\">(grid&#91;row, column&#93; <\/span><span style=\"color: #D73A49\">switch<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                    <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Empty<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot; &quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                    <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;X&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                    <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;O&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                    <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;*&quot;<\/span><span style=\"color: #24292E\"> });<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                gridLines.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(sb.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> gridLines;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStatus<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #6F42C1\">None<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Active<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Win<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Draw<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Error<\/span><span style=\"color: #24292E\"> };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStatus<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetStatus<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">switch<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Active<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> GameStatus.Active,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Win<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> GameStatus.Win,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Draw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> GameStatus.Draw,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Error<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> GameStatus.Error,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> GameStatus.None,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ErrorType<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #6F42C1\">None<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">MoveNotValid<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">MoveInUse<\/span><span style=\"color: #24292E\"> };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ErrorType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetErrorType<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> gameStage.Error <\/span><span style=\"color: #D73A49\">switch<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageErrorType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">MoveNotValid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ErrorType.MoveNotValid,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">GameStageErrorType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">MoveInUse<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ErrorType.MoveInUse,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ErrorType.None,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Side<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetWinner<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Win)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> gameStage.Winner <\/span><span style=\"color: #D73A49\">switch<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">X<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Side.X,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">CellType<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">O<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Side.O,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #005CC5\">_<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> Side.None,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Side.None;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleFiring<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Object<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">obj<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">AgendaEventArgs<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            Console.<\/span><span style=\"color: #6F42C1\">WriteLine<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">$&quot;..rule {<\/span><span style=\"color: #24292E\">args<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Rule<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Name<\/span><span style=\"color: #032F62\">} firing&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleFired<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Object<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">obj<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">AgendaEventArgs<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            Console.<\/span><span style=\"color: #6F42C1\">WriteLine<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">$&quot;..rule {<\/span><span style=\"color: #24292E\">args<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Rule<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Name<\/span><span style=\"color: #032F62\">} fired&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            ruleRepository <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">RuleRepository<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            ruleRepository.<\/span><span style=\"color: #6F42C1\">Load<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> x.<\/span><span style=\"color: #6F42C1\">PrivateTypes<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">).<\/span><span style=\"color: #6F42C1\">From<\/span><span style=\"color: #24292E\">(Assembly.<\/span><span style=\"color: #6F42C1\">GetExecutingAssembly<\/span><span style=\"color: #24292E\">()));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            sessionFactory <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> ruleRepository.<\/span><span style=\"color: #6F42C1\">Compile<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> sessionFactory.<\/span><span style=\"color: #6F42C1\">CreateSession<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ initialize model<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            gameStage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\">(GameStageType.Initial);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(gameStage);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            grid <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(grid);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">item<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> Enumerable.<\/span><span style=\"color: #6F42C1\">Range<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Row, item));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Column, item));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Diagonal, Line.MainDiagonal));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            session.<\/span><span style=\"color: #6F42C1\">Insert<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">(LineType.Diagonal, Line.CounterDiagonal));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            session.Events.RuleFiringEvent <\/span><span style=\"color: #D73A49\">+=<\/span><span style=\"color: #24292E\"> RuleFiring;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            session.Events.RuleFiredEvent <\/span><span style=\"color: #D73A49\">+=<\/span><span style=\"color: #24292E\"> RuleFired;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Here are some example tests in <em>TestRules.cs<\/em> in the <em>TicTacToeTest <\/em>project:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using TicTacToe;\n\nnamespace TicTacToeTest\n{\n    &#91;TestClass&#93;\n    public sealed class TestRules\n    {\n        &#91;TestMethod&#93;\n        public void TestNewGame()\n        {\n            var api = new API();\n\n            var rules = api.GetRules();\n            Assert.IsGreaterThan(0, rules.Count);\n\n            api.NewGame();\n\n            var lines = api.GetLines();\n            Assert.HasCount(8, lines);\n        }\n\n        &#91;TestMethod&#93;\n        public void TestMove()\n        {\n            var api = new API();\n\n            api.NewGame();\n            api.Move(API.Side.X, 1, 1);\n            var lines = api.GetLines();\n            int count = lines.Where(l => l.Contains('X')).Count();\n            Assert.IsGreaterThan(0, count);\n        }\n\n...\n\n        &#91;TestMethod&#93;\n        public void TestDuplicateMoveWithReset()\n        {\n            var api = new API();\n\n            api.NewGame();\n            api.Move(API.Side.X, 1, 1);\n            api.Move(API.Side.O, 1, 1);\n\n            var status1 = api.GetStatus();\n            var errorType1 = api.GetErrorType();\n            Assert.AreEqual(API.GameStatus.Error, status1, \"no error\");\n            Assert.AreEqual(API.ErrorType.MoveInUse, errorType1, \"error type not correct\");\n\n            api.ResetError();\n            api.Move(API.Side.O, 1, 2);\n\n            var status2 = api.GetStatus();\n            Assert.AreEqual(API.GameStatus.Active, status2, \"not active\");\n        }\n\n...\n\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToeTest<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &#91;<\/span><span style=\"color: #6F42C1\">TestClass<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">sealed<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestRules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">TestMethod<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestNewGame<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">api<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">rules<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetRules<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">IsGreaterThan<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">, rules.Count);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">NewGame<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetLines<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">HasCount<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">8<\/span><span style=\"color: #24292E\">, lines);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">TestMethod<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestMove<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">api<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">NewGame<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(API.Side.X, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetLines<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">count<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> lines.<\/span><span style=\"color: #6F42C1\">Where<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">Contains<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;X&#39;<\/span><span style=\"color: #24292E\">)).<\/span><span style=\"color: #6F42C1\">Count<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">IsGreaterThan<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">, count);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">TestMethod<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestDuplicateMoveWithReset<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">api<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">NewGame<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(API.Side.X, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(API.Side.O, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">status1<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetStatus<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">errorType1<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetErrorType<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">AreEqual<\/span><span style=\"color: #24292E\">(API.GameStatus.Error, status1, <\/span><span style=\"color: #032F62\">&quot;no error&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">AreEqual<\/span><span style=\"color: #24292E\">(API.ErrorType.MoveInUse, errorType1, <\/span><span style=\"color: #032F62\">&quot;error type not correct&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">ResetError<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            api.<\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\">(API.Side.O, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">status2<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> api.<\/span><span style=\"color: #6F42C1\">GetStatus<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            Assert.<\/span><span style=\"color: #6F42C1\">AreEqual<\/span><span style=\"color: #24292E\">(API.GameStatus.Active, status2, <\/span><span style=\"color: #032F62\">&quot;not active&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A common issue with rules-based processing is determining why a rule <em>doesn&#8217;t<\/em> fire.  There is no direct way to track the execution of pre-condition tests, but you can put a test into a static method in the rule and trace that.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, modify <em>Engine\\Rules\\MoveRule.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using NRules.Fluent.Dsl;\nusing NRules.RuleModel;\nusing TicTacToe.Engine.Model;\n\nnamespace TicTacToe.Engine.Rules\n{\n    internal class MoveRule : Rule\n    {\n        public override void Define()\n        {\n            GameStage stage = default!;\n            Grid grid = default!;\n            Move move = default!;\n            IEnumerable&lt;Line> lines = default!;\n\n            When()\n                .Match(() => stage, gameStage => gameStage.Stage == GameStageType.Active)\n                .Match(() => move, move => move.Status == MoveStatus.Pending)\n\/\/                .Match(() => grid, grid => grid&#91;move.Row, move.Column&#93; == CellType.Empty)\n                .Match(() => grid, grid => TestGridCell(grid, move.Row, move.Column))\n                .Query(() => lines, query => query\n                    .Match&lt;Line>(l => l.AcceptsMove(move))\n                    .Collect()\n                )\n                ;\n\n            Then()\n                .Do(ctx => move.SetStatus(MoveStatus.Processed))\n                .Do(ctx => ctx.Update(move))\n                .Do(ctx => grid.SetCellType(move.Row, move.Column, move.Type))\n                .Do(ctx => ctx.Update(grid))\n                .Do(ctx => UpdateLines(ctx, lines, move))\n                ;\n        }\n\n        private static bool TestGridCell(Grid grid, int row, int column)\n        {\n            bool result = grid&#91;row, column&#93; == CellType.Empty;\n\n            Console.WriteLine(\n                $\"..rule {nameof(MoveRule)}: test 'grid&#91;{row}, {column}&#93; == CellType.Empty' = {result}\");\n\n            return result;\n        }\n\n        private static void UpdateLines(IContext context, IEnumerable&lt;Line> lines, Move move)\n        {\n            foreach (Line line in lines)\n            {\n                line.AddMove(move);\n                context.Update(line);\n            }\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Fluent<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Dsl<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NRules<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RuleModel<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TicTacToe<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Rules<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MoveRule<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">Rule<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Define<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">GameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">stage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">When<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> stage, <\/span><span style=\"color: #6F42C1\">gameStage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> gameStage.Stage <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> GameStageType.Active)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move, <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.Status <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> MoveStatus.Pending)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #6A737D\">\/\/                .Match(() =&gt; grid, grid =&gt; grid&#91;move.Row, move.Column&#93; == CellType.Empty)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid, <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestGridCell<\/span><span style=\"color: #24292E\">(grid, move.Row, move.Column))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Query<\/span><span style=\"color: #24292E\">(() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> lines, <\/span><span style=\"color: #6F42C1\">query<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> query<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #6F42C1\">l<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> l.<\/span><span style=\"color: #6F42C1\">AcceptsMove<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    .<\/span><span style=\"color: #6F42C1\">Collect<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Then<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> move.<\/span><span style=\"color: #6F42C1\">SetStatus<\/span><span style=\"color: #24292E\">(MoveStatus.Processed))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> grid.<\/span><span style=\"color: #6F42C1\">SetCellType<\/span><span style=\"color: #24292E\">(move.Row, move.Column, move.Type))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> ctx.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(grid))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">Do<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ctx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UpdateLines<\/span><span style=\"color: #24292E\">(ctx, lines, move))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TestGridCell<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">Grid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">grid<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">row<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">column<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">result<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> grid&#91;row, column&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> CellType.Empty;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            Console.<\/span><span style=\"color: #6F42C1\">WriteLine<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;..rule {<\/span><span style=\"color: #D73A49\">nameof<\/span><span style=\"color: #032F62\">(<\/span><span style=\"color: #24292E\">MoveRule<\/span><span style=\"color: #032F62\">)}: test &#39;grid&#91;{<\/span><span style=\"color: #24292E\">row<\/span><span style=\"color: #032F62\">}, {<\/span><span style=\"color: #24292E\">column<\/span><span style=\"color: #032F62\">}&#93; == CellType.Empty&#39; = {<\/span><span style=\"color: #24292E\">result<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> result;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UpdateLines<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">IContext<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">context<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">IEnumerable<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">Move<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">move<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">Line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> lines)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                line.<\/span><span style=\"color: #6F42C1\">AddMove<\/span><span style=\"color: #24292E\">(move);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                context.<\/span><span style=\"color: #6F42C1\">Update<\/span><span style=\"color: #24292E\">(line);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now when you run <em>TestDuplicateMoveWithReset <\/em>from the test suite you get the following output:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"518\" height=\"351\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/11\/TestDuplicateMoveWithReset-output-2.png\" alt=\"\" class=\"wp-image-395\" srcset=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/11\/TestDuplicateMoveWithReset-output-2.png 518w, https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/11\/TestDuplicateMoveWithReset-output-2-300x203.png 300w\" sizes=\"auto, (max-width: 518px) 100vw, 518px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this post I have shown how to use NRules to implement basic validation for a tic-tac-toe game. This implementation just verifies the moves it receives through the API. It does not actually <em>play <\/em>the game. It does not even verify that the moves are made in alternating player sequence.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In my next post I will expand on this to show how to hook up a simple Blazor web application and also to have the program &#8220;play&#8221; one of the sides.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rules-based processing provides an alternative to classic procedural programming for providing decision support.  This post shows how to implement validation for a simple game.<\/p>\n","protected":false},"author":1,"featured_media":310,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[10],"tags":[12,17,18],"class_list":["post-383","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-c","tag-nrules","tag-rules"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/383","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/comments?post=383"}],"version-history":[{"count":3,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/383\/revisions"}],"predecessor-version":[{"id":397,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/383\/revisions\/397"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media\/310"}],"wp:attachment":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media?parent=383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/categories?post=383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/tags?post=383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}