Watrophy: code challenges by Robert Smith Wed, 21 Mar 2018 05:23:04 +0000 Robert Smith #38: Spirals 2018-03-20 2018-03-20 Robert Smith http://www.watrophy.com <p>Recall that the symbol $\mathbb{Z}^2$ denotes the set of all coordinate pairs with integer components.</p> <p>A <strong>spiral of length $n\ge 1$</strong> is a counter-clockwise spiral starting at $(0,0)$ extending to the right to $(n,0)$, wrapping around so as to cover $\mathbb{Z}^2$ completely.</p> <p>Consider the following spiral of length $2$.</p> <pre><code>*--*--*--*--*--* | | * *--*--*--* * | | (0,0) | | * * x--*--x * | | (2,0) | * *--*--*--*--* | *--*--*--*--*--* ...</code></pre> <p>The points of the spiral have a natural ordering. The above spiral can be written as a sequence $s$ where \begin{align} s_0 &amp;= (0,0), &amp; s_3 &amp;= (2,1),\\ s_1 &amp;= (1,0), &amp; s_4 &amp;= (1,1),\\ s_2 &amp;= (2,0), &amp; s_5 &amp;= (0,1), \end{align} and so on.</p> <p>There are three challenges. Given an $n\ge 1$, do the following.</p> <ol> <li><p>Given a $k\ge 0$, find $s_k$.</p></li> <li><p>Given a point $(\alpha, \beta)\in\mathbb{Z}^2$, find the $k$ such that $s_k = (\alpha,\beta)$.</p></li> <li><p>Print the spiral of length $2$ to the terminal by printing the values of $k$ in their correct positions. (And make it look nice by ensuring the numbers are aligned and reasonably spaced out.)</p></li> </ol> #37: Staircase Paths 2018-02-10 2018-02-10 Robert Smith http://www.watrophy.com <h2>Prerequisites</h2> <p>The symbol $\mathbb{Z}^n$ denotes the set of all coordinate $n$-tuples with integer components. These are one kind of <strong>$n$-dimensional lattice</strong>.</p> <p>Given two points $s=(s_1,\ldots, s_n)$ and $e=(e_1, \ldots, e_n)$, their <a href="https://en.wikipedia.org/wiki/Taxicab_geometry" ><strong>taxicab distance</strong></a> is $$\Vert s-e\Vert_1 := \sum_{i=1}^n\vert s_i-e_i\vert.$$</p> <p>Given a complex number $z$, we denote its <strong>normalization</strong> as $$\operatorname{N}(z) := \begin{cases} 0 &amp; \text{if }z=0,\\ z/\vert z\vert &amp; \text{otherwise.} \end{cases}$$</p> <h2>Challenge</h2> <p>A staircase path between two points, informally, is any path by going only right or up.</p> <p>Formally, given the starting point $s \in\mathbb{Z}^n$ and ending point $e \in\mathbb{Z}^n$ with $s\leq e$ (i.e., each component of $s$ is less than or equal to each corresponding component of $e$), a <strong>staircase path</strong> is a sequence of $\ell:=1+\Vert s-e\Vert_1$ coordinates $\sigma_0,\ldots,\sigma_{\ell}$ with the following facts:</p> <ol> <li><p>$\sigma_0 = s$,</p></li> <li><p>$s\leq \sigma_k \leq e$ (in the sense described above), and</p></li> <li><p>exactly one component of $\sigma_{k+1} - \sigma_k$ is $1$, with the other $n-1$ components equal to $0$.</p></li> </ol> <p>Denote the <strong>set of all staircase paths</strong> from $s$ to $e$ as $\{s\to e\}$.</p> <p><strong>Part 1</strong>: Verify that facts 1–3 imply $\sigma_{\ell} = e$.</p> <p>Next, consider the set $\mathbb{T}^{m\times n}$ defined as $n\times m$ matrices whose entries are complex numbers of <a href="https://en.wikipedia.org/wiki/Circle_group" >unit modulus</a>. For consistency with the above, let's suppose the bottom-left element of each matrix is identified by $(1,1)$ and top-right element is $(n, m)$.</p> <p><strong>Part 2</strong>: Implement the function $$f : \mathbb{T}^{m\times n}\to \mathbb{T}\cup\{0\}$$ defined by $$f(M) := \operatorname{N}\left(\sum_{\Sigma\in\{(1,1)\to(m,n)\}}\prod_{(x,y)\in\Sigma} M_{x,y}\right).$$</p> <p><strong>Extra Credit</strong>: Generalize $f$ to work on a tensor of any order.</p> #36: Falling Leaves 2018-02-08 2018-02-08 Robert Smith http://www.watrophy.com <p>Imagine you have a $k$-ary rooted tree $T$ defined by the following diagram:</p> <pre><code> [ A ] [ / \ ] [ B C ] T := [ / \ / \ ]. [ D E F G ] [ / \ \ ] [ H I J ]</code></pre> <p>The leaves of $T$ are $$\operatorname{leaves}(T) := \{\mathtt{H}, \mathtt{I}, \mathtt{E}, \mathtt{J}, \mathtt{G}\}.$$ Imagine the leaves fall off though an operation called $\operatorname{fall}$ so that $\operatorname{fall}(T)$ is</p> <pre><code> [ A ] [ / \ ] fall(T) = [ B C ]. [ / / ] [ D F ]</code></pre> <p>After another iteration, we get $\operatorname{fall}^2(T)$, which is</p> <pre><code> [ A ] fall²(T) = [ / \ ]. [ B C ]</code></pre> <p>And $\operatorname{fall}^3(T) = \mathtt{A}$, the root.</p> <p>Write a function which takes <em>any</em> $k$-ary rooted tree $T$ and prints out the sequence $$\ell_i(T) := \big(\operatorname{leaves}\circ\operatorname{fall}^i\big)(T)$$ for $0\leq i \leq n$ where $n$ is defined such that $\operatorname{fall}^n(T)$ is the root of $T$. (Since it is a sequence, it should be printed in order.)</p> <p>For the example above, in somewhat abbreviated notation, we have $$\ell(T) := (\mathtt{HIEJG}, \mathtt{DF}, \mathtt{BC}, \mathtt{A}).$$</p> <p><em>Thanks to <a href="https://medium.com/@stevenheidel" >Steven Heidel</a> for telling me about this wonderful problem.</em></p> #35: All CARs and CDRs 2018-02-06 2018-02-06 Robert Smith http://www.watrophy.com <p>Most Lisps have combinations of <code>car</code> and <code>cdr</code> built in, usually up to four levels deep, e.g., <code>caaddr</code> and <code>cdaddr</code> are built-ins referring to</p> <pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">lambda</span></i> <span class="paren2">(<span class="code">x</span>)</span> <span class="paren2">(<span class="code">car <span class="paren3">(<span class="code">car <span class="paren4">(<span class="code">cdr <span class="paren5">(<span class="code">cdr x</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span> <span class="comment">; and </span><span class="paren1">(<span class="code"><i><span class="symbol">lambda</span></i> <span class="paren2">(<span class="code">x</span>)</span> <span class="paren2">(<span class="code">cdr <span class="paren3">(<span class="code">car <span class="paren4">(<span class="code">cdr <span class="paren5">(<span class="code">cdr x</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></code></pre> <p>respectively. Implement a macro <code>(generate-cxr n)</code> which generates the definitions of all <code>car</code>/<code>cdr</code> combinations up to <code>n</code> times.</p> <p>If your language doesn't support macros or dynamic definitions, write a function of the same name which produces a list of all <code>car</code>/<code>cdr</code> combinations as anonymous functions.</p> <p><strong>Extra Credit</strong>: Implement this as efficiently as possible, using the least amount of space.</p> #34: All Manner of Brackets 2018-02-06 2018-02-06 Robert Smith http://www.watrophy.com <p>We all know the problem of checking/counting parentheses pairs. This time, given a list of open and close characters which must match each other, check if the expression is valid. For example, consider the following pairs:</p> <pre><code>(defparameter *open-close-pairs* '((#$$. #$$) (#$. #$) (#\{ . #\}) (#\&lt; . #\&gt;)))</code></pre> <p>Write a function <code>validate</code> which takes a string like <code>&quot;({&lt;&gt;[()]}[])&quot;</code> and a table of open-close pairs and return a Boolean indicating the validity of the string.</p> #33: Random Arithmetic Problems 2018-01-31 2018-01-31 Robert Smith http://www.watrophy.com <h3>Part 1</h3> <p>Write a function <code>random-expression</code> which generates a random math expression built up by numbers, <code>+</code>, unary/binary <code>-</code>, <code>*</code>, <code>/</code>, <code>^</code>, and <code>sqrt</code>. There should be two outputs: (1) the generated expression in unevaluated form, and (2) the evaluated answer. Decide on and explain your choice of arguments to <code>random-expression</code> to bound the <em>size</em> of the expression.</p> <p><em>Bonus</em>: Write this in both a dynamically typed language and a strictly typed language.</p> <h3>Part 2</h3> <p>Extend <code>evaluate-expression</code> to take into account a variable called <code>operator-table</code> which contains the operators used in random generation and their arities. For example, the default table might look like this in Common Lisp:</p> <pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defvar</span></i> <span class="special">*operator-table*</span> '<span class="paren2">(<span class="code"><span class="paren3">(<span class="code">+ 2</span>)</span> <span class="paren3">(<span class="code">- 1 2</span>)</span> <span class="comment">; unary and binary - </span> <span class="paren3">(<span class="code">* 2</span>)</span> <span class="paren3">(<span class="code">/ 2</span>)</span> <span class="paren3">(<span class="code">expt 2</span>)</span> <span class="paren3">(<span class="code">sqrt 1</span>)</span></span>)</span></span>)</span></span></code></pre> <p>Feel free to add information to the table as you see fit.</p> #32: Promises from Scratch 2018-01-31 2018-01-31 Robert Smith http://www.watrophy.com <p>In the <a href="1-Delayed-Evaluation.html" >first challenge</a>, we created a syntactic primitive called a <em>thunk</em> to construct delayed computations, which could later be run by simply calling them.</p> <p>However, there is a slight problem. Suppose we make the following thunk:</p> <pre><code><span class="code"><span class="paren1">(<span class="code"><a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-8.html#%_idx_190" class="symbol"><i><span class="symbol">define</span></i></a> x <span class="paren2">(<span class="code">thunk <span class="paren3">(<span class="code"><a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_624" class="symbol">display</a> <span class="string">"Hello!"</span></span>)</span> <span class="paren3">(<span class="code"><a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_278" class="symbol">+</a> 1 1</span>)</span></span>)</span></span>)</span></span></code></pre> <p>Then when we run the thunk by doing <code>(x)</code> in Scheme or <code>(funcall x)</code> in Common Lisp, it will print <code>&quot;Hello!&quot;</code> and compute <code>2</code> on each invocation. In Common Lisp notation:</p> <pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defvar</span></i> <span class="special">*thunk*</span> <span class="paren2">(<span class="code">thunk <span class="paren3">(<span class="code">format t <span class="string">"Hello!"</span></span>)</span> <span class="paren3">(<span class="code">+ 1 1</span>)</span></span>)</span></span>)</span> <span class="paren1">(<span class="code">funcall <span class="special">*thunk*</span></span>)</span> <span class="comment">; Prints: Hello! </span> <span class="comment">; Returns: 2 </span> <span class="paren1">(<span class="code">funcall <span class="special">*thunk*</span></span>)</span> <span class="comment">; Prints: Hello! </span> <span class="comment">; Returns: 2</span></span></code></pre> <p>This may not be desirable if we want to simulate things such as <a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need" >call-by-need</a> evaluation semantics.</p> <p>In this exercise, create two abstractions, <code>delay</code> and <code>force</code> to ameliorate this issue. The <code>delay</code> abstraction should be similar to <code>thunk</code> in that it creates a delayed computation using <code>lambda</code>. We call the result of <code>delay</code> a <em>promise</em>.</p> <p>The abstraction <code>force</code> is responsible now for actually evaluating the promise and producing an answer. However, using <code>force</code> a second time will give back a cached result.</p> <p>Here's an example in Common Lisp notation:</p> <pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defvar</span></i> <span class="special">*promise*</span> <span class="paren2">(<span class="code">delay <span class="paren3">(<span class="code">format t <span class="string">"Hello!"</span></span>)</span> <span class="paren3">(<span class="code">+ 1 1</span>)</span></span>)</span></span>)</span> <span class="paren1">(<span class="code">force <span class="special">*promise*</span></span>)</span> <span class="comment">; Prints: Hello! </span> <span class="comment">; Returns: 2 </span> <span class="paren1">(<span class="code">force <span class="special">*promise*</span></span>)</span> <span class="comment">; Does not print. </span> <span class="comment">; Returns: 2</span></span></code></pre> #31: Aperiodic Tiling 2018-01-30 2018-01-30 Robert Smith http://www.watrophy.com <p><a href="https://en.wikipedia.org/wiki/Wang_tile" >Wang tiles</a> are a collection of oriented squares with colored edges such that when you place the squares side-by-side with matching colors, the plane will tile aperiodically. That is to say, <em>without rotating or reflecting the tiles</em>, when placed according to the color matching rule, repetitions of tiles cannot occur within contiguous sections of the plane, as soon as the sections are large enough.</p> <p>Wang tiles are specified by listing their colors starting with the top edge and going clockwise. One set of Wang tiles consists of 13 tiles using 4 colors. The tiles are listed below.</p> <pre><code>Wang Tiles ---------- RRRG BRBG Example Tile: RGBW RGGG WBRB Red BBWB +----+ WWRW | | Green RGBW White | | BWBR +----+ BRWR Blue GGBR RWRG</code></pre> <h3>Part 1</h3> <p>Write a program that generates a random $M\times N$ rectangle of Wang tiles.</p> <h3>Part 2</h3> <p>Suppose the <em>centers</em> of the squares are placed in the plane at integer lattice points. Then we can identify each square in the plane by its center.</p> <p>Write a function <code>(spiral n)</code> which gives the $n$th coordinate of a spiral starting at $(0, 0)$ to $(1, 0)$ and proceeding counterclockwise. The first few values are:</p> <pre><code>0 =&gt; (0, 0) 3 =&gt; (0, 1) 6 =&gt; (-1, -1) 1 =&gt; (1, 0) 4 =&gt; (-1, 1) 7 =&gt; (0, -1) 2 =&gt; (1, 1) 5 =&gt; (-1, 0) 8 =&gt; (1, -1)</code></pre> <p>With this, write a function <code>(wang-spiral n)</code> which produces a Wang tiling valid on the coordinates <code>(spiral 0)</code> to <code>(spiral (- n 1))</code>.</p> <h3>Extra Credit</h3> <p>Draw your artwork.</p> #30: Combinator Practice 2018-01-30 2018-01-30 Robert Smith http://www.watrophy.com <p>In <a href="15-Simple-Combinators.html" >Challenge #15</a>, we wrote a few simple combinators. Here we write a few more.</p> <p>In addition to combinator practice, this exercise will be written so as to practice math notation comprehension.</p> <p>For each of these, implement the combinator and write the most general type for that combinator.</p> <ol> <li><p>Combinator $C_1$ which &quot;flips&quot; the arguments of binary function. It takes $f : X\times Y\to Z$ to $C_1 f = f' : Y \times X \to Z$ such that for all $x\in X$ and $y \in Y$, $$f(x,y) = f'(y,x).$$ This combinator is an <em>involution</em> because $C_1^2$ is the identity.</p></li> <li><p>Combinator $C_2$ which duplicates an argument to a binary function. It takes $f : X\times X\to Z$ to $C_2 g = f' : X \to Z$ such that for all $x\in X$, $$f(x,x) = f(x).$$</p></li> <li><p>Combinator $C_3$ which takes two functions with the same domain $X$, and produces a function taking $x\in X$ and returning $(f(x), g(x))$.</p></li> <li><p>Combinator $C_4$ which takes a function, and produces a <em>curried</em> function of two arguments, such that the second argument supplied is effectively ignored.</p></li> </ol> <p><em>Fun Fact</em>: In Haskell, the combinators above are called <code>flip</code>, <code>join</code>, <code>liftM2 (,)</code>, and <code>(const .)</code> respectively.</p> #29: Multiplying Long-Hand 2018-01-30 2018-01-30 Robert Smith http://www.watrophy.com <p>Modern CPUs only support multiplying integers of a fixed size, which is usually 32- or 64-bits.</p> <p>In grade school, most of us learned how to multiply numbers long-hand; we write the two numbers down, one above the other, and proceed to do the multiplication. It often looks like so:</p> <pre><code> 123 x 45 ---- 615 + 492 ------ 5535</code></pre> <p>If you've forgotten this method for multiplying, you might consult a children's arithmetic book.</p> <p>The goal of this exercise is to implement the long multiplication algorithm. While not required, it is certainly convenient if your language supports arbitrary precision integers out of the box.</p> <h3>Part 1</h3> <p>As testing utilities, write two functions:</p> <ul> <li><p><code>(digits n)</code> which takes a non-negative integer and produces a list of base-10 digits from least to most significant. For example, <code>(digits 123)</code> shall return <code>(3 2 1)</code>. Decide on what <code>(digits 0)</code> should be.</p></li> <li><p><code>(undigits dlist)</code> which does the opposite: takes a list of digits and produces a non-negative integer.</p></li> </ul> <p>Furthermore, answer the following questions:</p> <ul> <li><p>Is any list of digits a valid representation of a non-negative integer?</p></li> <li><p>What is the <em>precise</em> relationship between <code>digits</code> and <code>undigits</code>?</p></li> </ul> <h3>Part 2</h3> <p>Implement the long multiplication algorithm as a function <code>long-multiply</code> which takes two lists of base-10 numbers and produces a list representing the product.</p> <h3>Part 3</h3> <p>Modify <code>long-multiply</code> to print out what the process might look like with pencil and paper. For example:</p> <pre><code><span class="code"><span class="paren1">(<span class="code">display-long-multiply '<span class="paren2">(<span class="code">3 2 1</span>)</span> '<span class="paren2">(<span class="code">5 4</span>)</span></span>)</span> <span class="comment">; Outputs: </span><span class="comment">; </span><span class="comment">; 123 </span><span class="comment">; x 45 </span><span class="comment">; ---- </span><span class="comment">; 615 </span><span class="comment">; + 492 </span><span class="comment">; ------ </span><span class="comment">; 5535</span></span></code></pre> <h3>Part 4</h3> <p>If you implemented the previous parts successfully, you may not have done so with absolute mathematical correctness. Without loss of generality, suppose we are multiplying two $N$-digit numbers. Then, in the second step of the algorithm, we will produce the $N$ terms that we need to add up. When we perform the addition in each column, each of which consist of at most $N$ base-10 digits, our sum will likely exceed our digit size.</p> <p>Answer these questions:</p> <ol> <li><p>What is the maximum size of a number we could sum to in a column?</p></li> <li><p>What is an example of two numbers whose multiplication process leads to that sum?</p></li> <li><p>If we are truly constrained on a computer where every storable register, be it in the processor or RAM, is limited to holding a digit between 0 and 9, how can we modify the algorithm to accommodate?</p></li> </ol> <p>Finally, perform the modifications to the algorithm.</p>