mirror of
https://github.com/ganelson/inform.git
synced 2024-07-05 16:44:21 +03:00
658 lines
75 KiB
HTML
658 lines
75 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>3/rls</title>
|
|
<meta name="viewport" content="width=device-width initial-scale=1">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta http-equiv="Content-Language" content="en-gb">
|
|
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
</head>
|
|
<body>
|
|
<nav role="navigation">
|
|
<h1><a href="../webs.html">Sources</a></h1>
|
|
<ul>
|
|
<li><a href="../compiler.html">compiler</a></li>
|
|
<li><a href="../other.html"><b>other tools</b></a></li>
|
|
<li><a href="../extensions.html">extensions and kits</a></li>
|
|
<li><a href="../units.html">unit test tools</a></li>
|
|
</ul>
|
|
<h2>Other Tools</h2>
|
|
<ul>
|
|
<li><a href="../inblorb/index.html">inblorb</a></li>
|
|
<li><a href="../indoc/index.html">indoc</a></li>
|
|
<li><a href="../inpolicy/index.html">inpolicy</a></li>
|
|
<li><a href="../inrtps/index.html">inrtps</a></li>
|
|
</ul>
|
|
<h2>Foundation</h2>
|
|
<ul>
|
|
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
|
|
</ul>
|
|
|
|
|
|
</nav>
|
|
<main role="main">
|
|
|
|
<!--Weave of '3/sd' generated by 7-->
|
|
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../other.html">Other Tools</a></li><li><a href="index.html">inblorb</a></li><li><a href="index.html#3">Chapter 3: Other Material</a></li><li><b>Solution Deviser</b></li></ul><p class="purpose">To make a solution (.sol) file accompanying a release, if requested.</p>
|
|
|
|
<ul class="toc"><li><a href="#SP1">§1. Skein storage</a></li><li><a href="#SP3">§3. Walking through</a></li><li><a href="#SP4">§4. Step 1: building the Skein tree</a></li><li><a href="#SP10">§10. Step 2: identify the relevant lines</a></li><li><a href="#SP11">§11. Step 3: pruning irrelevant lines out of the tree</a></li><li><a href="#SP12">§12. Step 4: writing the solution file</a></li><li><a href="#SP14">§14. Writing individual commands and branch descriptions</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Skein storage. </b>A solution file is simply a list of commands which will win a work of IF,
|
|
starting from turn 1. In this section we will generate this list given the
|
|
Skein file for an Inform 7 project: to follow this code, it's useful first
|
|
to read the "Walkthrough solutions" section of the "Releasing" chapter
|
|
in the main Inform documentation.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">We will need to parse the entire skein into a tree structure, in which each
|
|
node (including leaves) is one of the following structures. We expect the
|
|
Inform user to have annotated certain nodes with the text <code class="display"><span class="extract">***</span></code> (three
|
|
asterisks); the solution file will ignore all paths in the skein which do
|
|
not lead to one of these <code class="display"><span class="extract">***</span></code> nodes. The surviving nodes, those in lines
|
|
which do lead to <code class="display"><span class="extract">***</span></code> endings, are called "relevant".
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Some knots have "branch descriptions", others do not. These are the
|
|
options where choices have to be made. The <code class="display"><span class="extract">branch_parent</span></code> and <code class="display"><span class="extract">branch_count</span></code>
|
|
fields are used to keep these labels: see below.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">skein_node</span><span class="plain"> {</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">id</span><span class="plain">; </span> <span class="comment">uniquely identifying ID used within the Skein file</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">command</span><span class="plain">; </span> <span class="comment">text of the command at this node</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">annotation</span><span class="plain">; </span> <span class="comment">text of any annotation added by the user</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">relevant</span><span class="plain">; </span> <span class="comment">is this node within one of the "relevant" lines in the skein?</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">branch_parent</span><span class="plain">; </span> <span class="comment">the trunk of the branch description, if any, is this way</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">branch_count</span><span class="plain">; </span> <span class="comment">the leaf of the branch description, if any, is this number</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">parent</span><span class="plain">; </span> <span class="comment">within the Skein tree: <code class="display"><span class="extract">NULL</span></code> for the root only</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">child</span><span class="plain">; </span> <span class="comment">within the Skein tree: <code class="display"><span class="extract">NULL</span></code> if a leaf</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">sibling</span><span class="plain">; </span> <span class="comment">within the Skein tree: <code class="display"><span class="extract">NULL</span></code> if the final option from its parent</span>
|
|
<span class="constant">MEMORY_MANAGEMENT</span>
|
|
<span class="plain">} </span><span class="reserved">skein_node</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The structure skein_node is private to this section.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>The root of the Skein, representing the start position before any command
|
|
is typed, lives here:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">root_skn</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">only <code class="display"><span class="extract">NULL</span></code> when the tree is empty</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. Walking through. </b>This section provides just one function to the rest of Inblorb: this one,
|
|
which implements the Blurb <code class="display"><span class="extract">solution</span></code> command.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Our method works in four steps. Steps 1 to 3 have a running time of O(K^2),
|
|
where K is the number of knots in the Skein, and step 4 is O(K log K),
|
|
so the process as a whole is O(K^2).
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::walkthrough</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">Skein_filename</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">walkthrough_filename</span><span class="plain">) {</span>
|
|
<span class="functiontext">Solution::build_skein_tree</span><span class="plain">(</span><span class="identifier">Skein_filename</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">root_skn</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">BlorbErrors::error</span><span class="plain">(</span><span class="string">"there appear to be no threads in the Skein"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="functiontext">Solution::identify_relevant_lines</span><span class="plain">();</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">root_skn</span><span class="plain">-</span><span class="element">>relevant</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) {</span>
|
|
<span class="functiontext">BlorbErrors::error</span><span class="plain">(</span><span class="string">"no threads in the Skein have been marked '***'"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="functiontext">Solution::prune_irrelevant_lines</span><span class="plain">();</span>
|
|
<span class="functiontext">Solution::write_solution_file</span><span class="plain">(</span><span class="identifier">walkthrough_filename</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::walkthrough is used in 3/rls (<a href="3-rls.html#SP6">§6</a>, <a href="3-rls.html#SP6_1">§6.1</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. Step 1: building the Skein tree. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">current_skein_node</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::build_skein_tree</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">Skein_filename</span><span class="plain">) {</span>
|
|
<span class="identifier">root_skn</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="functiontext">TextFiles::read</span><span class="plain">(</span><span class="identifier">Skein_filename</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, </span><span class="string">"can't open skein file"</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, </span><span class="functiontext">Solution::read_skein_pass_1</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">);</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="functiontext">TextFiles::read</span><span class="plain">(</span><span class="identifier">Skein_filename</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, </span><span class="string">"can't open skein file"</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, </span><span class="functiontext">Solution::read_skein_pass_2</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::read_skein_pass_1</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">line</span><span class="plain">, </span><span class="reserved">text_file_position</span><span class="plain"> *</span><span class="identifier">tfp</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">state</span><span class="plain">) { </span><span class="functiontext">Solution::read_skein_line</span><span class="plain">(</span><span class="identifier">line</span><span class="plain">, 1); }</span>
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::read_skein_pass_2</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">line</span><span class="plain">, </span><span class="reserved">text_file_position</span><span class="plain"> *</span><span class="identifier">tfp</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">state</span><span class="plain">) { </span><span class="functiontext">Solution::read_skein_line</span><span class="plain">(</span><span class="identifier">line</span><span class="plain">, 2); }</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::build_skein_tree is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="endnote">The function Solution::read_skein_pass_1 appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Solution::read_skein_pass_2 appears nowhere else.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. </b>The Skein is stored as an XML file. Its format was devised by Andrew Hunter
|
|
in the early days of the Inform user interface for Mac OS X, and this was
|
|
then adopted by the user interface on other platforms, so that projects could
|
|
be freely exchanged between users regardless of their platforms. That makes
|
|
it a kind of standard, but it isn't at present a public or documented one.
|
|
We shall therefore make few assumptions about it.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::read_skein_line</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">line</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">pass</span><span class="plain">) {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::find_node_ID_in_tag</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="string">"item"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pass</span><span class="plain"> == 1) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">) > 0) </span><<span class="cwebmacro">Create a new skein tree node with this node ID</span> <span class="cwebmacronumber">5.1</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_skein_node</span><span class="plain">) {</span>
|
|
<<span class="cwebmacro">Look for a "command" tag and set the command text from it</span> <span class="cwebmacronumber">5.3</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Look for an "annotation" tag and set the annotation text from it</span> <span class="cwebmacronumber">5.4</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">) > 0) </span><span class="identifier">current_skein_node</span><span class="plain"> = </span><span class="functiontext">Solution::find_node_with_ID</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_skein_node</span><span class="plain">) {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">child_node_id</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::find_node_ID_in_tag</span><span class="plain">(</span><span class="identifier">child_node_id</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="string">"child"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">child_node_id</span><span class="plain">) > 0) {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">new_child</span><span class="plain"> = </span><span class="functiontext">Solution::find_node_with_ID</span><span class="plain">(</span><span class="identifier">child_node_id</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">new_child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">BlorbErrors::error</span><span class="plain">(</span><span class="string">"the skein file is malformed (B)"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<<span class="cwebmacro">Make the parent-child relationship</span> <span class="cwebmacronumber">5.2</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">child_node_id</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::read_skein_line is used in <a href="#SP4">§4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5_1"></a><b>§5.1. </b>Note that the root is the first knot in the Skein file.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Create a new skein tree node with this node ID</span> <span class="cwebmacronumber">5.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">current_skein_node</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">skein_node</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">root_skn</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">root_skn</span><span class="plain"> = </span><span class="identifier">current_skein_node</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>id</span><span class="plain"> = </span><span class="functiontext">Str::duplicate</span><span class="plain">(</span><span class="identifier">node_id</span><span class="plain">);</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>command</span><span class="plain"> = </span><span class="functiontext">Str::new</span><span class="plain">();</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>annotation</span><span class="plain"> = </span><span class="functiontext">Str::new</span><span class="plain">();</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>branch_count</span><span class="plain"> = -1;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>branch_parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>relevant</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Creating knot with ID '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">node_id</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5_2"></a><b>§5.2. </b>We make <code class="display"><span class="extract">new_child</span></code> the youngest child of <code class="display"><span class="extract">current_skein_mode</span></code>:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Make the parent-child relationship</span> <span class="cwebmacronumber">5.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">new_child</span><span class="plain">-</span><span class="element">>parent</span><span class="plain"> = </span><span class="identifier">current_skein_node</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> = </span><span class="identifier">new_child</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">familial</span><span class="plain"> = </span><span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>child</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">familial</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">) </span><span class="identifier">familial</span><span class="plain"> = </span><span class="identifier">familial</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">;</span>
|
|
<span class="identifier">familial</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> = </span><span class="identifier">new_child</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5_3"></a><b>§5.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Look for a "command" tag and set the command text from it</span> <span class="cwebmacronumber">5.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>command</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Solution::find_text_of_tag</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="string">"command"</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Raw command '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::undo_XML_escapes_in_string</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="identifier">LOOP_THROUGH_TEXT</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">)</span>
|
|
<span class="functiontext">Str::put</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="functiontext">Characters::toupper</span><span class="plain">(</span><span class="functiontext">Str::get</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">)));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Processed command '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5_4"></a><b>§5.4. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Look for an "annotation" tag and set the annotation text from it</span> <span class="cwebmacronumber">5.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">current_skein_node</span><span class="plain">-</span><span class="element">>annotation</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Solution::find_text_of_tag</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="string">"annotation"</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Raw annotation '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::undo_XML_escapes_in_string</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Processed annotation '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP6"></a><b>§6. </b>Try to find a node ID element attached to a particular tag on the line:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::find_node_ID_in_tag</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">line</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">tag</span><span class="plain">) {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">, </span><span class="string">"%c*?<%s nodeId=\</span><span class="plain">"</span><span class="string">(%c*?)\</span><span class="plain">"</span><span class="string">%c*"</span><span class="plain">, </span><span class="identifier">tag</span><span class="plain">);</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">prototype_Cs</span><span class="plain">[128];</span>
|
|
<span class="functiontext">Str::copy_to_wide_string</span><span class="plain">(</span><span class="identifier">prototype_Cs</span><span class="plain">, </span><span class="identifier">prototype</span><span class="plain">, 128);</span>
|
|
<span class="reserved">match_results</span><span class="plain"> </span><span class="identifier">mr</span><span class="plain"> = </span><span class="functiontext">Regexp::create_mr</span><span class="plain">();</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Regexp::match</span><span class="plain">(&</span><span class="identifier">mr</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="identifier">prototype_Cs</span><span class="plain">)) </span><span class="functiontext">Str::copy</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">mr</span><span class="element">.exp</span><span class="plain">[0]);</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Str::clear</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
|
|
<span class="functiontext">Regexp::dispose_of</span><span class="plain">(&</span><span class="identifier">mr</span><span class="plain">);</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::find_node_ID_in_tag is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. </b>Try to find the text of a particular tag on the line:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Solution::find_text_of_tag</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">line</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">tag</span><span class="plain">) {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">, </span><span class="string">"%c*?>(%c*?)</%s%c*"</span><span class="plain">, </span><span class="identifier">tag</span><span class="plain">);</span>
|
|
<span class="reserved">match_results</span><span class="plain"> </span><span class="identifier">mr</span><span class="plain"> = </span><span class="functiontext">Regexp::create_mr</span><span class="plain">();</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">prototype_Cs</span><span class="plain">[128];</span>
|
|
<span class="functiontext">Str::copy_to_wide_string</span><span class="plain">(</span><span class="identifier">prototype_Cs</span><span class="plain">, </span><span class="identifier">prototype</span><span class="plain">, 128);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Regexp::match</span><span class="plain">(&</span><span class="identifier">mr</span><span class="plain">, </span><span class="identifier">line</span><span class="plain">, </span><span class="identifier">prototype_Cs</span><span class="plain">)) {</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">);</span>
|
|
<span class="functiontext">Str::copy</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">mr</span><span class="element">.exp</span><span class="plain">[0]);</span>
|
|
<span class="functiontext">Regexp::dispose_of</span><span class="plain">(&</span><span class="identifier">mr</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">);</span>
|
|
<span class="functiontext">Str::clear</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::find_text_of_tag is used in <a href="#SP5_3">§5.3</a>, <a href="#SP5_4">§5.4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§8. </b>This is not very efficient, but:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="functiontext">Solution::find_node_with_ID</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">id</span><span class="plain">) {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">skn</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">, </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>id</span><span class="plain">) == 0)</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">skn</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::find_node_with_ID is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§9. </b>Finally, we needed the following string hackery:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::undo_XML_escapes_in_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = 0, </span><span class="identifier">j</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'&'</span><span class="plain">) {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">k</span><span class="plain">=0;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">k</span><span class="plain">) != 0) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">k</span><span class="plain">) != </span><span class="character">';'</span><span class="plain">))</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="functiontext">Characters::tolower</span><span class="plain">(</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain"> + </span><span class="identifier">k</span><span class="plain">++)));</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">k</span><span class="plain">));</span>
|
|
<<span class="cwebmacro">We have identified an XML escape</span> <span class="cwebmacronumber">9.1</span>><span class="plain">;</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">++, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">++));</span>
|
|
<span class="plain">}</span>
|
|
<span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">++, 0);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::undo_XML_escapes_in_string is used in <a href="#SP5_3">§5.3</a>, <a href="#SP5_4">§5.4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1"></a><b>§9.1. </b>Note that all other ampersand-escapes are passed through verbatim.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">We have identified an XML escape</span> <span class="cwebmacronumber">9.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"&lt;"</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'<'</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"&gt;"</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'>'</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"&amp;"</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'&'</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"&apos;"</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'\</span><span class="plain">'</span><span class="character">'</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"&quot;"</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'\</span><span class="plain">"</span><span class="character">'</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">) { </span><span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">++, </span><span class="identifier">c</span><span class="plain">); </span><span class="identifier">i</span><span class="plain"> += </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">xml_escape</span><span class="plain">); </span><span class="reserved">continue</span><span class="plain">; }</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP9">§9</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§10. Step 2: identify the relevant lines. </b>We aim to show how to reach all knots in the Skein annotated with text which
|
|
begins with three asterisks. (We trim those asterisks away from the annotation
|
|
once we spot them: they have served their purpose.) A knot is "relevant"
|
|
if and only if one of its (direct or indirect) children is marked with three
|
|
asterisks in this way.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::identify_relevant_lines</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">skn</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain">) {</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>annotation</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Knot %S is annotated '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>id</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, 0) == </span><span class="character">'*'</span><span class="plain">) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, 1) == </span><span class="character">'*'</span><span class="plain">) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, 2) == </span><span class="character">'*'</span><span class="plain">)) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = 3, </span><span class="identifier">j</span><span class="plain">; </span><span class="reserved">while</span><span class="plain"> (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">' '</span><span class="plain">) </span><span class="identifier">i</span><span class="plain">++;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain">=0; </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">++, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">)); </span><span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">, 0);</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">knot</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">knot</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">; </span><span class="identifier">knot</span><span class="plain">; </span><span class="identifier">knot</span><span class="plain"> = </span><span class="identifier">knot</span><span class="plain">-</span><span class="element">>parent</span><span class="plain">) {</span>
|
|
<span class="identifier">knot</span><span class="plain">-</span><span class="element">>relevant</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Knot %S is relevant\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">knot</span><span class="plain">-</span><span class="element">>id</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::identify_relevant_lines is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. Step 3: pruning irrelevant lines out of the tree. </b>When the loop below concludes, the relevant nodes are exactly those in the
|
|
component of the tree root, because:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<ul class="items"><li>(a) No irrelevant node can be the child of a relevant one; and no
|
|
relevant node can be the child of an irrelevant one by definition. So the
|
|
tree falls into components each of which is fully relevant or fully not.
|
|
</li><li>(b) Since we never break any relevant-parent-relevant-child relationships, the
|
|
number of components containing at least one relevant node is unchanged.
|
|
</li><li>(c) Since the Skein is initially a tree and not a forest, we start with
|
|
just one component, and it contains the tree root, which is known to be
|
|
relevant (we would have given up with an error message if not).
|
|
</li><li>(d) And therefore at the end of the loop the "tree" consists of a single
|
|
component headed by the tree root and containing all of the relevant nodes,
|
|
together with any number of other components each of which contains only
|
|
irrelevant ones.
|
|
</li></ul>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::prune_irrelevant_lines</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">skn</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>relevant</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) && (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>parent</span><span class="plain">))</span>
|
|
<<span class="cwebmacro">Delete this node from its parent</span> <span class="cwebmacronumber">11.1</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::prune_irrelevant_lines is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11_1"></a><b>§11.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Delete this node from its parent</span> <span class="cwebmacronumber">11.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>parent</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> == </span><span class="identifier">skn</span><span class="plain">) {</span>
|
|
<span class="identifier">skn</span><span class="plain">-</span><span class="element">>parent</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn2</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>parent</span><span class="plain">-</span><span class="element">>child</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">skn2</span><span class="plain">) && (</span><span class="identifier">skn2</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> != </span><span class="identifier">skn</span><span class="plain">)) </span><span class="identifier">skn2</span><span class="plain"> = </span><span class="identifier">skn2</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">skn2</span><span class="plain">) && (</span><span class="identifier">skn2</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> == </span><span class="identifier">skn</span><span class="plain">)) </span><span class="identifier">skn2</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">skn</span><span class="plain">-</span><span class="element">>parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">skn</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP11">§11</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§12. Step 4: writing the solution file. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::write_solution_file</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">walkthrough_filename</span><span class="plain">) {</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">TO_struct</span><span class="plain">;</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">SOL</span><span class="plain"> = &</span><span class="identifier">TO_struct</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">STREAM_OPEN_TO_FILE</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="identifier">walkthrough_filename</span><span class="plain">, </span><span class="constant">UTF8_ENC</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">)</span>
|
|
<span class="functiontext">BlorbErrors::fatal_fs</span><span class="plain">(</span><span class="string">"can't open solution text file for output"</span><span class="plain">, </span><span class="identifier">walkthrough_filename</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="string">"Solution to \</span><span class="plain">"</span><span class="string">"</span><span class="plain">); </span><span class="functiontext">Placeholders::write</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"TITLE"</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="string">"\</span><span class="plain">"</span><span class="string"> by "</span><span class="plain">); </span><span class="functiontext">Placeholders::write</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"AUTHOR"</span><span class="plain">); </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="string">"\</span><span class="plain">n</span><span class="string">\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::recursively_solve</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">, </span><span class="identifier">root_skn</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
|
|
<span class="identifier">STREAM_CLOSE</span><span class="plain">(</span><span class="identifier">SOL</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::write_solution_file is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. </b>The following prints commands to the solution file from the position <code class="display"><span class="extract">skn</span></code> —
|
|
which means just after typing its command — with the aim of reaching all
|
|
relevant endings we can get to from there.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::recursively_solve</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">last_branch</span><span class="plain">) {</span>
|
|
<<span class="cwebmacro">Follow the skein down until we reach a divergence, if we do</span> <span class="cwebmacronumber">13.1</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Print the various alternatives from this knot where the threads diverge</span> <span class="cwebmacronumber">13.2</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Show the solutions down each of these alternative lines in turn</span> <span class="cwebmacronumber">13.3</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::recursively_solve is used in <a href="#SP12">§12</a>, <a href="#SP13_3">§13.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13_1"></a><b>§13.1. </b>If there's only a single option from here, we could print it and then
|
|
call <code class="display"><span class="extract">Solution::recursively_solve</span></code> down from it. That would make the code shorter and
|
|
clearer, perhaps, but it would clobber the C stack: our recursion depth
|
|
might be into the tens of thousands on long solution files. So we tail-recurse
|
|
instead of calling ourselves, so to speak, and just run down the thread
|
|
until we reach a choice. (If we never do reach a choice, we can return —
|
|
there is nowhere else to reach.)
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Follow the skein down until we reach a divergence, if we do</span> <span class="cwebmacronumber">13.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">skn</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain">;</span>
|
|
<span class="functiontext">Solution::write_command</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">skn</span><span class="plain">, </span><span class="constant">NORMAL_COMMAND</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13_2"></a><b>§13.2. </b>Thus we are here only when there are at least two alternative commands
|
|
we might use from position <code class="display"><span class="extract">skn</span></code>.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Print the various alternatives from this knot where the threads diverge</span> <span class="cwebmacronumber">13.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Choice:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">branch_counter</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">option</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">option</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain">; </span><span class="identifier">option</span><span class="plain">; </span><span class="identifier">option</span><span class="plain"> = </span><span class="identifier">option</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">option</span><span class="plain">-</span><span class="element">>child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">Solution::write_command</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">option</span><span class="plain">, </span><span class="constant">BRANCH_TO_END_COMMAND</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">option</span><span class="plain">-</span><span class="element">>branch_count</span><span class="plain"> = </span><span class="identifier">branch_counter</span><span class="plain">++;</span>
|
|
<span class="identifier">option</span><span class="plain">-</span><span class="element">>branch_parent</span><span class="plain"> = </span><span class="identifier">last_branch</span><span class="plain">;</span>
|
|
<span class="functiontext">Solution::write_command</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">option</span><span class="plain">, </span><span class="constant">BRANCH_TO_LINE_COMMAND</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13_3"></a><b>§13.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Show the solutions down each of these alternative lines in turn</span> <span class="cwebmacronumber">13.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">option</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">option</span><span class="plain"> = </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>child</span><span class="plain">; </span><span class="identifier">option</span><span class="plain">; </span><span class="identifier">option</span><span class="plain"> = </span><span class="identifier">option</span><span class="plain">-</span><span class="element">>sibling</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">option</span><span class="plain">-</span><span class="element">>child</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">Branch ("</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::write_branch_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">option</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">")\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::recursively_solve</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">option</span><span class="plain">, </span><span class="identifier">option</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§14. Writing individual commands and branch descriptions. </b></p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">NORMAL_COMMAND</span><span class="plain"> 1</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">BRANCH_TO_END_COMMAND</span><span class="plain"> 2</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">BRANCH_TO_LINE_COMMAND</span><span class="plain"> 3</span>
|
|
</pre>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::write_command</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">cmd_skn</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">form</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> != </span><span class="constant">NORMAL_COMMAND</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%S"</span><span class="plain">, </span><span class="identifier">cmd_skn</span><span class="plain">-</span><span class="element">>command</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> != </span><span class="constant">NORMAL_COMMAND</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" -> "</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">BRANCH_TO_LINE_COMMAND</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"go to branch ("</span><span class="plain">);</span>
|
|
<span class="functiontext">Solution::write_branch_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">cmd_skn</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">")"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"end"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">cmd_skn</span><span class="plain">-</span><span class="element">>annotation</span><span class="plain">) > 0) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" ... %S"</span><span class="plain">, </span><span class="identifier">cmd_skn</span><span class="plain">-</span><span class="element">>annotation</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::write_command is used in <a href="#SP13_1">§13.1</a>, <a href="#SP13_2">§13.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§15. </b>For instance, at the third option from a thread which ran back to being
|
|
the second option from a thread which ran back to being the seventh option
|
|
from the original position, the following would print "7.2.3". Note that
|
|
only the knots representing the positions after commands which make a choice
|
|
are labelled in this way.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Solution::write_branch_name</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">skein_node</span><span class="plain"> *</span><span class="identifier">skn</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>branch_parent</span><span class="plain">) {</span>
|
|
<span class="functiontext">Solution::write_branch_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>branch_parent</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"."</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d"</span><span class="plain">, </span><span class="identifier">skn</span><span class="plain">-</span><span class="element">>branch_count</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Solution::write_branch_name is used in <a href="#SP13_3">§13.3</a>, <a href="#SP14">§14</a>.</p>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><a href="3-rls.html">Back to 'Releaser'</a></li><li><a href="3-laaf.html">Continue with 'Links and Auxiliary Files'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|