C Answers to Exercises

\(\newcommand{\footnotename}{footnote}\) \(\def \LWRfootnote {1}\) \(\newcommand {\footnote }[2][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\newcommand {\footnotemark }[1][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\let \LWRorighspace \hspace \) \(\renewcommand {\hspace }{\ifstar \LWRorighspace \LWRorighspace }\) \(\newcommand {\TextOrMath }[2]{#2}\) \(\newcommand {\mathnormal }[1]{{#1}}\) \(\newcommand \ensuremath [1]{#1}\) \(\newcommand {\LWRframebox }[2][]{\fbox {#2}} \newcommand {\framebox }[1][]{\LWRframebox } \) \(\newcommand {\setlength }[2]{}\) \(\newcommand {\addtolength }[2]{}\) \(\newcommand {\setcounter }[2]{}\) \(\newcommand {\addtocounter }[2]{}\) \(\newcommand {\arabic }[1]{}\) \(\newcommand {\number }[1]{}\) \(\newcommand {\noalign }[1]{\text {#1}\notag \\}\) \(\newcommand {\cline }[1]{}\) \(\newcommand {\directlua }[1]{\text {(directlua)}}\) \(\newcommand {\luatexdirectlua }[1]{\text {(directlua)}}\) \(\newcommand {\protect }{}\) \(\def \LWRabsorbnumber #1 {}\) \(\def \LWRabsorbquotenumber "#1 {}\) \(\newcommand {\LWRabsorboption }[1][]{}\) \(\newcommand {\LWRabsorbtwooptions }[1][]{\LWRabsorboption }\) \(\def \mathchar {\ifnextchar "\LWRabsorbquotenumber \LWRabsorbnumber }\) \(\def \mathcode #1={\mathchar }\) \(\let \delcode \mathcode \) \(\let \delimiter \mathchar \) \(\def \oe {\unicode {x0153}}\) \(\def \OE {\unicode {x0152}}\) \(\def \ae {\unicode {x00E6}}\) \(\def \AE {\unicode {x00C6}}\) \(\def \aa {\unicode {x00E5}}\) \(\def \AA {\unicode {x00C5}}\) \(\def \o {\unicode {x00F8}}\) \(\def \O {\unicode {x00D8}}\) \(\def \l {\unicode {x0142}}\) \(\def \L {\unicode {x0141}}\) \(\def \ss {\unicode {x00DF}}\) \(\def \SS {\unicode {x1E9E}}\) \(\def \dag {\unicode {x2020}}\) \(\def \ddag {\unicode {x2021}}\) \(\def \P {\unicode {x00B6}}\) \(\def \copyright {\unicode {x00A9}}\) \(\def \pounds {\unicode {x00A3}}\) \(\let \LWRref \ref \) \(\renewcommand {\ref }{\ifstar \LWRref \LWRref }\) \( \newcommand {\multicolumn }[3]{#3}\) \(\require {textcomp}\) \(\newcommand {\intertext }[1]{\text {#1}\notag \\}\) \(\let \Hat \hat \) \(\let \Check \check \) \(\let \Tilde \tilde \) \(\let \Acute \acute \) \(\let \Grave \grave \) \(\let \Dot \dot \) \(\let \Ddot \ddot \) \(\let \Breve \breve \) \(\let \Bar \bar \) \(\let \Vec \vec \) \(\renewcommand {\vec }{\boldsymbol }\) \(\newcommand {\Edge }{\ensuremath {\,\textemdash \,}}\) \(\newcommand \Const [1]{\text {\textsf {#1}}}\) \(\DeclareMathOperator {\lerp }{lerp}\) \(\DeclareMathOperator {\bitlen }{bitlen}\) \(\DeclareMathOperator {\sign }{sign}\) \(\newcommand {\I }{\mathrm {i}}\) \(\newcommand \AND {\mathbin {\&}}\) \(\newcommand \OR {\mathbin {|}}\) \(\newcommand \XOR {\mathbin {{}^{\wedge }}}\) \(\newcommand \shl {\ll }\) \(\newcommand \shr {\ggg }\) \(\newcommand \asr {\gg }\) \(\newcommand \NOT {\ensuremath {\mathord {\sim }}}\) \(\newcommand {\isep }{\mathrel {{.}\,{.}}}\) \(\newcommand {\Id }[1]{\mathit {#1}}\) \(\newcommand {\const }[1]{\mathsf {#1}}\) \(\newcommand {\algorithmname }[1]{\text {\textsc {#1}}}\) \(\newcommand {\bits }[1]{\text {#1}}\) \(\newcommand {\hexa }[1]{\mathtt {0x#1}}\) \(\newcommand {\num }[1]{#1}\) \(\newcommand {\qed }{\quad \square }\) \(\newcommand {\idiv }[2]{\lfloor #1/#2\rfloor }\) \(\newcommand \attribdot {\ensuremath {\mkern 1.5mu.\mkern 1.5mu}}\) \(\newcommand \attribxr [2]{#1\attribdot \text {#2}}\) \(\newcommand \attribir [2]{\Id {#1}\attribdot \text {#2}}\) \(\newcommand \attribii [2]{\Id {#1}\attribdot \Id {#2}}\) \(\newcommand \textsc [1]{#1}\) \(\require {colortbl}\) \(\let \LWRorigcolumncolor \columncolor \) \(\renewcommand {\columncolor }[2][named]{\LWRorigcolumncolor [#1]{#2}\LWRabsorbtwooptions }\) \(\let \LWRorigrowcolor \rowcolor \) \(\renewcommand {\rowcolor }[2][named]{\LWRorigrowcolor [#1]{#2}\LWRabsorbtwooptions }\) \(\let \LWRorigcellcolor \cellcolor \) \(\renewcommand {\cellcolor }[2][named]{\LWRorigcellcolor [#1]{#2}\LWRabsorbtwooptions }\) \(\newcommand {\tcbset }[1]{}\) \(\newcommand {\tcbsetforeverylayer }[1]{}\) \(\newcommand {\tcbox }[2][]{\boxed {\text {#2}}}\) \(\newcommand {\tcboxfit }[2][]{\boxed {#2}}\) \(\newcommand {\tcblower }{}\) \(\newcommand {\tcbline }{}\) \(\newcommand {\tcbtitle }{}\) \(\newcommand {\tcbsubtitle [2][]{\mathrm {#2}}}\) \(\newcommand {\tcboxmath }[2][]{\boxed {#2}}\) \(\newcommand {\tcbhighmath }[2][]{\boxed {#2}}\) \(\newcommand {\toprule }[1][]{\hline }\) \(\let \midrule \toprule \) \(\let \bottomrule \toprule \) \(\def \LWRbooktabscmidruleparen (#1)#2{}\) \(\newcommand {\LWRbooktabscmidrulenoparen }[1]{}\) \(\newcommand {\cmidrule }[1][]{\ifnextchar (\LWRbooktabscmidruleparen \LWRbooktabscmidrulenoparen }\) \(\newcommand {\morecmidrules }{}\) \(\newcommand {\specialrule }[3]{\hline }\) \(\newcommand {\addlinespace }[1][]{}\) \(\newcommand {\LWRsubmultirow }[2][]{#2}\) \(\newcommand {\LWRmultirow }[2][]{\LWRsubmultirow }\) \(\newcommand {\multirow }[2][]{\LWRmultirow }\) \(\newcommand {\mrowcell }{}\) \(\newcommand {\mcolrowcell }{}\) \(\newcommand {\STneed }[1]{}\) \(\newcommand {\LWRldelimtwo }[1][]{\text {#1}~\LWRbigdelim }\) \(\newcommand {\LWRldelimone }[2][]{\LWRldelimtwo }\) \(\def \ldelim #1#2{\def \LWRbigdelim {#1}\LWRldelimone }\) \(\newcommand {\LWRrdelimtwo }[1][]{\LWRbigdelim ~\text {#1}}\) \(\newcommand {\LWRrdelimone }[2][]{\LWRrdelimtwo }\) \(\def \rdelim #1#2{\def \LWRbigdelim {#1}\LWRrdelimone }\) \(\let \symnormal \mathit \) \(\let \symliteral \mathrm \) \(\let \symbb \mathbb \) \(\let \symbbit \mathbb \) \(\let \symcal \mathcal \) \(\let \symscr \mathscr \) \(\let \symfrak \mathfrak \) \(\let \symsfup \mathsf \) \(\let \symsfit \mathit \) \(\let \symbfsf \mathbf \) \(\let \symbfup \mathbf \) \(\newcommand {\symbfit }[1]{\boldsymbol {#1}}\) \(\let \symbfcal \mathcal \) \(\let \symbfscr \mathscr \) \(\let \symbffrak \mathfrak \) \(\let \symbfsfup \mathbf \) \(\newcommand {\symbfsfit }[1]{\boldsymbol {#1}}\) \(\let \symup \mathrm \) \(\let \symbf \mathbf \) \(\let \symit \mathit \) \(\let \symsf \symsfit \) \(\let \symtt \mathtt \) \(\let \symbffrac \mathbffrac \) \(\newcommand {\mathfence }[1]{\mathord {#1}}\) \(\newcommand {\mathover }[1]{#1}\) \(\newcommand {\mathunder }[1]{#1}\) \(\newcommand {\mathaccent }[1]{#1}\) \(\newcommand {\mathbotaccent }[1]{#1}\) \(\newcommand {\mathalpha }[1]{\mathord {#1}}\) \(\def\Alpha{\unicode{x1D6E2}}\) \(\def\Beta{\unicode{x1D6E3}}\) \(\def\Gamma{\unicode{x1D6E4}}\) \(\def\Digamma{\mathit{\unicode{x03DC}}}\) \(\def\Delta{\unicode{x1D6E5}}\) \(\def\Epsilon{\unicode{x1D6E6}}\) \(\def\Zeta{\unicode{x1D6E7}}\) \(\def\Eta{\unicode{x1D6E8}}\) \(\def\Theta{\unicode{x1D6E9}}\) \(\def\Vartheta{\unicode{x1D6F3}}\) \(\def\Iota{\unicode{x1D6EA}}\) \(\def\Kappa{\unicode{x1D6EB}}\) \(\def\Lambda{\unicode{x1D6EC}}\) \(\def\Mu{\unicode{x1D6ED}}\) \(\def\Nu{\unicode{x1D6EE}}\) \(\def\Xi{\unicode{x1D6EF}}\) \(\def\Omicron{\unicode{x1D6F0}}\) \(\def\Pi{\unicode{x1D6F1}}\) \(\def\Rho{\unicode{x1D6F2}}\) \(\def\Sigma{\unicode{x1D6F4}}\) \(\def\Tau{\unicode{x1D6F5}}\) \(\def\Upsilon{\unicode{x1D6F6}}\) \(\def\Phi{\unicode{x1D6F7}}\) \(\def\Chi{\unicode{x1D6F8}}\) \(\def\Psi{\unicode{x1D6F9}}\) \(\def\Omega{\unicode{x1D6FA}}\) \(\def\alpha{\unicode{x1D6FC}}\) \(\def\beta{\unicode{x1D6FD}}\) \(\def\varbeta{\unicode{x03D0}}\) \(\def\gamma{\unicode{x1D6FE}}\) \(\def\digamma{\mathit{\unicode{x03DD}}}\) \(\def\delta{\unicode{x1D6FF}}\) \(\def\epsilon{\unicode{x1D716}}\) \(\def\varepsilon{\unicode{x1D700}}\) \(\def\zeta{\unicode{x1D701}}\) \(\def\eta{\unicode{x1D702}}\) \(\def\theta{\unicode{x1D703}}\) \(\def\vartheta{\unicode{x1D717}}\) \(\def\iota{\unicode{x1D704}}\) \(\def\kappa{\unicode{x1D705}}\) \(\def\varkappa{\unicode{x1D718}}\) \(\def\lambda{\unicode{x1D706}}\) \(\def\mu{\unicode{x1D707}}\) \(\def\nu{\unicode{x1D708}}\) \(\def\xi{\unicode{x1D709}}\) \(\def\omicron{\unicode{x1D70A}}\) \(\def\pi{\unicode{x1D70B}}\) \(\def\varpi{\unicode{x1D71B}}\) \(\def\rho{\unicode{x1D70C}}\) \(\def\varrho{\unicode{x1D71A}}\) \(\def\sigma{\unicode{x1D70E}}\) \(\def\varsigma{\unicode{x1D70D}}\) \(\def\tau{\unicode{x1D70F}}\) \(\def\upsilon{\unicode{x1D710}}\) \(\def\phi{\unicode{x1D719}}\) \(\def\varphi{\unicode{x1D711}}\) \(\def\chi{\unicode{x1D712}}\) \(\def\psi{\unicode{x1D713}}\) \(\def\omega{\unicode{x1D714}}\) \(\def\upAlpha{\unicode{x0391}}\) \(\def\upBeta{\unicode{x0392}}\) \(\def\upGamma{\unicode{x0393}}\) \(\def\upDigamma{\unicode{x03DC}}\) \(\def\upDelta{\unicode{x0394}}\) \(\def\upEpsilon{\unicode{x0395}}\) \(\def\upZeta{\unicode{x0396}}\) \(\def\upEta{\unicode{x0397}}\) \(\def\upTheta{\unicode{x0398}}\) \(\def\upVartheta{\unicode{x03F4}}\) \(\def\upIota{\unicode{x0399}}\) \(\def\upKappa{\unicode{x039A}}\) \(\def\upLambda{\unicode{x039B}}\) \(\def\upMu{\unicode{x039C}}\) \(\def\upNu{\unicode{x039D}}\) \(\def\upXi{\unicode{x039E}}\) \(\def\upOmicron{\unicode{x039F}}\) \(\def\upPi{\unicode{x03A0}}\) \(\def\upVarpi{\unicode{x03D6}}\) \(\def\upRho{\unicode{x03A1}}\) \(\def\upSigma{\unicode{x03A3}}\) \(\def\upTau{\unicode{x03A4}}\) \(\def\upUpsilon{\unicode{x03A5}}\) \(\def\upPhi{\unicode{x03A6}}\) \(\def\upChi{\unicode{x03A7}}\) \(\def\upPsi{\unicode{x03A8}}\) \(\def\upOmega{\unicode{x03A9}}\) \(\def\itAlpha{\unicode{x1D6E2}}\) \(\def\itBeta{\unicode{x1D6E3}}\) \(\def\itGamma{\unicode{x1D6E4}}\) \(\def\itDigamma{\mathit{\unicode{x03DC}}}\) \(\def\itDelta{\unicode{x1D6E5}}\) \(\def\itEpsilon{\unicode{x1D6E6}}\) \(\def\itZeta{\unicode{x1D6E7}}\) \(\def\itEta{\unicode{x1D6E8}}\) \(\def\itTheta{\unicode{x1D6E9}}\) \(\def\itVartheta{\unicode{x1D6F3}}\) \(\def\itIota{\unicode{x1D6EA}}\) \(\def\itKappa{\unicode{x1D6EB}}\) \(\def\itLambda{\unicode{x1D6EC}}\) \(\def\itMu{\unicode{x1D6ED}}\) \(\def\itNu{\unicode{x1D6EE}}\) \(\def\itXi{\unicode{x1D6EF}}\) \(\def\itOmicron{\unicode{x1D6F0}}\) \(\def\itPi{\unicode{x1D6F1}}\) \(\def\itRho{\unicode{x1D6F2}}\) \(\def\itSigma{\unicode{x1D6F4}}\) \(\def\itTau{\unicode{x1D6F5}}\) \(\def\itUpsilon{\unicode{x1D6F6}}\) \(\def\itPhi{\unicode{x1D6F7}}\) \(\def\itChi{\unicode{x1D6F8}}\) \(\def\itPsi{\unicode{x1D6F9}}\) \(\def\itOmega{\unicode{x1D6FA}}\) \(\def\upalpha{\unicode{x03B1}}\) \(\def\upbeta{\unicode{x03B2}}\) \(\def\upvarbeta{\unicode{x03D0}}\) \(\def\upgamma{\unicode{x03B3}}\) \(\def\updigamma{\unicode{x03DD}}\) \(\def\updelta{\unicode{x03B4}}\) \(\def\upepsilon{\unicode{x03F5}}\) \(\def\upvarepsilon{\unicode{x03B5}}\) \(\def\upzeta{\unicode{x03B6}}\) \(\def\upeta{\unicode{x03B7}}\) \(\def\uptheta{\unicode{x03B8}}\) \(\def\upvartheta{\unicode{x03D1}}\) \(\def\upiota{\unicode{x03B9}}\) \(\def\upkappa{\unicode{x03BA}}\) \(\def\upvarkappa{\unicode{x03F0}}\) \(\def\uplambda{\unicode{x03BB}}\) \(\def\upmu{\unicode{x03BC}}\) \(\def\upnu{\unicode{x03BD}}\) \(\def\upxi{\unicode{x03BE}}\) \(\def\upomicron{\unicode{x03BF}}\) \(\def\uppi{\unicode{x03C0}}\) \(\def\upvarpi{\unicode{x03D6}}\) \(\def\uprho{\unicode{x03C1}}\) \(\def\upvarrho{\unicode{x03F1}}\) \(\def\upsigma{\unicode{x03C3}}\) \(\def\upvarsigma{\unicode{x03C2}}\) \(\def\uptau{\unicode{x03C4}}\) \(\def\upupsilon{\unicode{x03C5}}\) \(\def\upphi{\unicode{x03D5}}\) \(\def\upvarphi{\unicode{x03C6}}\) \(\def\upchi{\unicode{x03C7}}\) \(\def\uppsi{\unicode{x03C8}}\) \(\def\upomega{\unicode{x03C9}}\) \(\def\italpha{\unicode{x1D6FC}}\) \(\def\itbeta{\unicode{x1D6FD}}\) \(\def\itvarbeta{\unicode{x03D0}}\) \(\def\itgamma{\unicode{x1D6FE}}\) \(\def\itdigamma{\mathit{\unicode{x03DD}}}\) \(\def\itdelta{\unicode{x1D6FF}}\) \(\def\itepsilon{\unicode{x1D716}}\) \(\def\itvarepsilon{\unicode{x1D700}}\) \(\def\itzeta{\unicode{x1D701}}\) \(\def\iteta{\unicode{x1D702}}\) \(\def\ittheta{\unicode{x1D703}}\) \(\def\itvartheta{\unicode{x1D717}}\) \(\def\itiota{\unicode{x1D704}}\) \(\def\itkappa{\unicode{x1D705}}\) \(\def\itvarkappa{\unicode{x1D718}}\) \(\def\itlambda{\unicode{x1D706}}\) \(\def\itmu{\unicode{x1D707}}\) \(\def\itnu{\unicode{x1D708}}\) \(\def\itxi{\unicode{x1D709}}\) \(\def\itomicron{\unicode{x1D70A}}\) \(\def\itpi{\unicode{x1D70B}}\) \(\def\itvarpi{\unicode{x1D71B}}\) \(\def\itrho{\unicode{x1D70C}}\) \(\def\itvarrho{\unicode{x1D71A}}\) \(\def\itsigma{\unicode{x1D70E}}\) \(\def\itvarsigma{\unicode{x1D70D}}\) \(\def\ittau{\unicode{x1D70F}}\) \(\def\itupsilon{\unicode{x1D710}}\) \(\def\itphi{\unicode{x1D719}}\) \(\def\itvarphi{\unicode{x1D711}}\) \(\def\itchi{\unicode{x1D712}}\) \(\def\itpsi{\unicode{x1D713}}\) \(\def\itomega{\unicode{x1D714}}\) \(\let \lparen (\) \(\let \rparen )\) \(\newcommand {\cuberoot }[1]{\,{}^3\!\!\sqrt {#1}}\,\) \(\newcommand {\fourthroot }[1]{\,{}^4\!\!\sqrt {#1}}\,\) \(\newcommand {\longdivision }[1]{\mathord {\unicode {x027CC}#1}}\) \(\newcommand {\mathcomma }{,}\) \(\newcommand {\mathcolon }{:}\) \(\newcommand {\mathsemicolon }{;}\) \(\newcommand {\overbracket }[1]{\mathinner {\overline {\ulcorner {#1}\urcorner }}}\) \(\newcommand {\underbracket }[1]{\mathinner {\underline {\llcorner {#1}\lrcorner }}}\) \(\newcommand {\overbar }[1]{\mathord {#1\unicode {x00305}}}\) \(\newcommand {\ovhook }[1]{\mathord {#1\unicode {x00309}}}\) \(\newcommand {\ocirc }[1]{\mathord {#1\unicode {x0030A}}}\) \(\newcommand {\candra }[1]{\mathord {#1\unicode {x00310}}}\) \(\newcommand {\oturnedcomma }[1]{\mathord {#1\unicode {x00312}}}\) \(\newcommand {\ocommatopright }[1]{\mathord {#1\unicode {x00315}}}\) \(\newcommand {\droang }[1]{\mathord {#1\unicode {x0031A}}}\) \(\newcommand {\leftharpoonaccent }[1]{\mathord {#1\unicode {x020D0}}}\) \(\newcommand {\rightharpoonaccent }[1]{\mathord {#1\unicode {x020D1}}}\) \(\newcommand {\vertoverlay }[1]{\mathord {#1\unicode {x020D2}}}\) \(\newcommand {\leftarrowaccent }[1]{\mathord {#1\unicode {x020D0}}}\) \(\newcommand {\annuity }[1]{\mathord {#1\unicode {x020E7}}}\) \(\newcommand {\widebridgeabove }[1]{\mathord {#1\unicode {x020E9}}}\) \(\newcommand {\asteraccent }[1]{\mathord {#1\unicode {x020F0}}}\) \(\newcommand {\threeunderdot }[1]{\mathord {#1\unicode {x020E8}}}\) \(\newcommand {\Bbbsum }{\mathop {\unicode {x2140}}\limits }\) \(\newcommand {\oiint }{\mathop {\unicode {x222F}}\limits }\) \(\newcommand {\oiiint }{\mathop {\unicode {x2230}}\limits }\) \(\newcommand {\intclockwise }{\mathop {\unicode {x2231}}\limits }\) \(\newcommand {\ointclockwise }{\mathop {\unicode {x2232}}\limits }\) \(\newcommand {\ointctrclockwise }{\mathop {\unicode {x2233}}\limits }\) \(\newcommand {\varointclockwise }{\mathop {\unicode {x2232}}\limits }\) \(\newcommand {\leftouterjoin }{\mathop {\unicode {x27D5}}\limits }\) \(\newcommand {\rightouterjoin }{\mathop {\unicode {x27D6}}\limits }\) \(\newcommand {\fullouterjoin }{\mathop {\unicode {x27D7}}\limits }\) \(\newcommand {\bigbot }{\mathop {\unicode {x27D8}}\limits }\) \(\newcommand {\bigtop }{\mathop {\unicode {x27D9}}\limits }\) \(\newcommand {\xsol }{\mathop {\unicode {x29F8}}\limits }\) \(\newcommand {\xbsol }{\mathop {\unicode {x29F9}}\limits }\) \(\newcommand {\bigcupdot }{\mathop {\unicode {x2A03}}\limits }\) \(\newcommand {\bigsqcap }{\mathop {\unicode {x2A05}}\limits }\) \(\newcommand {\conjquant }{\mathop {\unicode {x2A07}}\limits }\) \(\newcommand {\disjquant }{\mathop {\unicode {x2A08}}\limits }\) \(\newcommand {\bigtimes }{\mathop {\unicode {x2A09}}\limits }\) \(\newcommand {\modtwosum }{\mathop {\unicode {x2A0A}}\limits }\) \(\newcommand {\sumint }{\mathop {\unicode {x2A0B}}\limits }\) \(\newcommand {\intbar }{\mathop {\unicode {x2A0D}}\limits }\) \(\newcommand {\intBar }{\mathop {\unicode {x2A0E}}\limits }\) \(\newcommand {\fint }{\mathop {\unicode {x2A0F}}\limits }\) \(\newcommand {\cirfnint }{\mathop {\unicode {x2A10}}\limits }\) \(\newcommand {\awint }{\mathop {\unicode {x2A11}}\limits }\) \(\newcommand {\rppolint }{\mathop {\unicode {x2A12}}\limits }\) \(\newcommand {\scpolint }{\mathop {\unicode {x2A13}}\limits }\) \(\newcommand {\npolint }{\mathop {\unicode {x2A14}}\limits }\) \(\newcommand {\pointint }{\mathop {\unicode {x2A15}}\limits }\) \(\newcommand {\sqint }{\mathop {\unicode {x2A16}}\limits }\) \(\newcommand {\intlarhk }{\mathop {\unicode {x2A17}}\limits }\) \(\newcommand {\intx }{\mathop {\unicode {x2A18}}\limits }\) \(\newcommand {\intcap }{\mathop {\unicode {x2A19}}\limits }\) \(\newcommand {\intcup }{\mathop {\unicode {x2A1A}}\limits }\) \(\newcommand {\upint }{\mathop {\unicode {x2A1B}}\limits }\) \(\newcommand {\lowint }{\mathop {\unicode {x2A1C}}\limits }\) \(\newcommand {\bigtriangleleft }{\mathop {\unicode {x2A1E}}\limits }\) \(\newcommand {\zcmp }{\mathop {\unicode {x2A1F}}\limits }\) \(\newcommand {\zpipe }{\mathop {\unicode {x2A20}}\limits }\) \(\newcommand {\zproject }{\mathop {\unicode {x2A21}}\limits }\) \(\newcommand {\biginterleave }{\mathop {\unicode {x2AFC}}\limits }\) \(\newcommand {\bigtalloblong }{\mathop {\unicode {x2AFF}}\limits }\) \(\newcommand {\arabicmaj }{\mathop {\unicode {x1EEF0}}\limits }\) \(\newcommand {\arabichad }{\mathop {\unicode {x1EEF1}}\limits }\)

Chapter 8

Solution to Exercise 8.1

For simplicity, we assume that levels are stored as arrays of Strings, for example as follows:

public static String[] sokoban1 = {
        "    #####",
        "    #   #",
        "    #$  #",
        "  ###  $##",
        "  #  $ $ #",
        "### # ## #   ######",
        "#   # ## #####  ..#",
        "# $  $          ..#",
        "##### ### #@##  ..#",
        "    #     #########",
        "    #######"
};

The parse() method in Listing C.62 constructs an instance of Level from such an array of strings. The function first determines the level’s width and height by counting the number of columns and rows in the textual description and then iterates over the rows a second time to place the individual objects.

Listing C.62ch8 / Level

public static Level parse(String[] rows) {
    int width = 0;
    for (String row : rows)
        width = Math.max(width, row.length());
    int height = rows.length;
    var level = new Level(width, height);
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < rows[y].length(); x++) {
            level.setCode(x, y, rows[y].charAt(x));
        }
    }
    return level;
}

Solution to Exercise 8.2

Like the other methods defined in GameState, the toString() method shown in Listing C.63 takes an additional argument of type Level. It iterates over the the rows and columns of the level and computes the correct character code for each square.

Listing C.63ch8 / GameState

// Return the ASCII representation of this game state.
public String toString(Level level) {
    var sb = new StringBuilder();
    for (int y = 0; y < level.height(); y++) {
        for (int x = 0; x < level.width(); x++) {
            char charCode;
            int index = level.index(x, y);
            if (level.walls().contains(index)) {
                charCode = '#';
            } else if (index == workerPos) {
                charCode = level.goals().contains(index) ? '+' : '@';
            } else if (crates.contains(index)) {
                charCode = level.goals().contains(index) ? '*' : '$';
            } else {
                charCode = level.goals().contains(index) ? '.' : ' ';
            }
            sb.append(charCode);
        }
        sb.append('\n');
    }
    return sb.toString();
}

Solution to Exercise 8.3

A level is closed if no positions on the boundary of the level can be reached from the worker’s starting position. The solution in Listing C.64 first constructs the move graph of the level with all crates removed and then uses breadth-first search to check whether it is possible to reach any position on the boundary.

Listing C.64ch8 / LevelClosed

public static boolean isLevelClosed(Level level) {
    var moveGraph = new MoveGraph(level, new BitSet());
    Integer posOutside = moveGraph.scan(
            level.workerStart(),
            pos -> level.getX(pos) == 0 || level.getY(pos) == 0
                    || level.getX(pos) == level.width() - 1
                    || level.getY(pos) == level.height() - 1);
    return posOutside == null;
}

Solution to Exercise 8.4

We first compute the interior of the level using breadth-first search. For each interior position that is not occupied by a crate and not already in a known component, we then use breadth-first search again to find all the nodes it is connected to, which gives us the next component. For an implementation, see Listing C.65.

Listing C.65ch8 / Components

static List<BitSet> findComponents(Level level, BitSet crates) {
    var interior = new BitSet();
    new MoveGraph(level, new BitSet())
            .visitNodes(level.workerStart(), interior::add);
    var inComponent = new BitSet();
    var components = new ArrayList<BitSet>();
    for (int pos : interior) {
        if (!crates.contains(pos) && !inComponent.contains(pos)) {
            var component = new BitSet();
            new MoveGraph(level, crates)
                    .visitNodes(pos, component::add);
            components.add(component);
            inComponent.addAll(component);
        }
    }
    return components;
}

Solution to Exercise 8.5

A function compressMoves() that compresses a string of movement commands is shown in Listing C.66. The compressed solution of Level 1 is:

u3l3uLUllDDuuruurDldldll3dr12RurD
14lulld15R
13l3urrdD3uruul4Dull3dr11RurD
13l3urrdDuull3dr11R
7l3ulLul3D4urrDlldll3dr10RdrUluRR
lld6l3uLLul3Duull3dr10RdrUluR

Listing C.66ch8 / SokobanSolver

// Replace runs of identical letters with an integer followed
// by a single letter
static String compressMoves(String moves) {
    var sb = new StringBuilder();
    for (int i = 0; i < moves.length(); i++) {
        char move = moves.charAt(i);
        int count = 1;
        while (i < moves.length() - 1 && moves.charAt(i + 1) == move) {
            i++;
            count++;
        }
        if (count > 2)
            sb.append(count);
        else if (count == 2)
            sb.append(move);
        sb.append(move);
    }
    return sb.toString();
}

Solution to Exercise 8.6

Changing the order of neighbors doesn’t affect the length of the shortest path through the push graph, but it does cause breadth-first search to discover a different solution first. With the standard order, the solver favors nearby crates, which leads to a solution in which the total distance traveled by the worker is fairly small (but not minimal, as we will discuss in Section 8.5). Reversing the list of neighbors, on the other hand, favors far-away crates, which produces a solution in which the worker constantly alternates between different crates. In the case of Level 1, the resulting solution requires 926 steps and starts as follows:

u3l3uLUluurDldlDll3drRll3urrDull3drr4R6l3urrdDuull3drRdd4ruu

This solution also requires the minimum 97 pushes.

Solution to Exercise 8.7

Node E has a total of eight neighbors that correspond to moving the left or the right crate in each of four directions. Moving the left crate up brings us back to the starting node S. The remaining options are moving the left crate down (E1), right (E2), left (E3), and moving the right crate up (E4), down (E5), left (E6), or right (E7).

Solution to Exercise 8.8

a)Figure C.14 marks all dead squares in the level using an X.

Figure C.14 The positions marked with an X are dead: it is impossible to push a crate from any of those positions to one of the two goal squares.

b)One way to show that a position \(p\) is dead is to place a single crate at \(p\) and show that, regardless of the worker’s position, the resulting level cannot be solved. (The only positions of the worker that must be checked are the four squares next to \(p\).) If we repeat this for all positions \(p\) inside the level, we obtain the list of all dead squares.

We can solve the problem more efficiently by considering the reverse problem: Which positions in a level are reachable by pulling a crate that starts at one of the goal squares? Similar to the push graph, we can define a pull graph in which two positions are adjacent if the worker can pull a crate from one position to the other. To compute the list of dead squares, we first determine all reachable positions in the level and then successively remove positions that are reachable by repeatedly pulling a crate from each of the goals. The positions that remain are the level’s dead squares. An implementation is shown in Listing C.67.

Listing C.67ch8 / DeadSquares

public static BitSet computeDeadSquares(Level level) {
    // An edge x -> y in the following graph indicates that a
    // crate can be pulled from position x to position y.
    var pullGraph = new Graph<Integer>() {
        public List<Integer> neighbors(Integer pos) {
            var neighbors = new ArrayList<Integer>();
            for (var direction : Board.ALL_DIRECTIONS) {
                int neighbor = level.moveIndex(pos, direction);
                if (neighbor == -1)
                    continue;
                int worker = level.moveIndex(neighbor, direction);
                if (worker == -1)
                    continue;
                if (!level.walls().contains(neighbor) &&
                        !level.walls().contains(worker)) {
                    neighbors.add(neighbor);
                }
            }
            return neighbors;
        }
    };
    // Start with the interior of the level, then remove squares that
    // can be reached by pulling a crate from any of the goal squares.
    var deadSquares = new BitSet();
    new MoveGraph(level, new BitSet())
            .visitNodes(level.workerStart(), deadSquares::add);
    for (int goal : level.goals())
        pullGraph.visitNodes(goal, deadSquares::remove);
    return deadSquares;
}

Solution to Exercise 8.9

a)The UKACD is stored as a text file that contains one entry per line. The readWords() method in Listing C.68 reads the entire file and creates a list of entries that contain only alphabetic characters and have the correct length wordLength. As a special case, the functions returns all words if the wordLength parameter is negative.

Listing C.68ch8 / words / WordList

// Read all words of the given length from the file at 'path'.
// Each line is assumed to contain a single word.
public static Collection<String> readWords(
        String path, int wordLength) throws IOException {
    var words = new ArrayList<String>();
    var reader = new BufferedReader(new FileReader(path));
    while (reader.ready()) {
        String entry = reader.readLine().toLowerCase();
        if (entry.matches("[a-zA-Z]*") &&
                (entry.length() == wordLength || wordLength < 0)) {
            words.add(entry);
        }
    }
    return words;
}

b)The neighbors of HAPPY are contained in four buckets: APPY, HPPY, HAPY, and HAPP. (The bucket HAPY corresponds to deleting either occurrence of the letter P.) HARPY belongs to five buckets: ARPY, HRPY, HAPY, HARY, and HARP.

c)A word \(w\) of length \(n\) must be added to \(n\) buckets, and the key of the \(k\)th bucket is obtained by deleting the \(k\)th letter of \(w\); see Listing C.69. Likewise, to find the neighbors of a word \(w\), we inspect all matching buckets and pick those entries that differ from \(w\) in exactly one letter.

Listing C.69ch8 / words / SimilarWords

private void addWord(String word) {
    for (int i = 0; i < word.length(); i++) {
        String key = deleteLetter(word, i);
        buckets.computeIfAbsent(key, k -> new HashSet<>()).add(word);
    }
}

public Collection<String> findSimilarWords(String word) {
    var result = new ArrayList<String>();
    for (int i = 0; i < word.length(); i++) {
        for (String n : buckets.get(deleteLetter(word, i))) {
            int distance = 0;  // number of letters that differ
            for (int j = 0; j < n.length() && distance <= 1; j++) {
                if (n.charAt(j) != word.charAt(j))
                    distance++;
            }
            if (distance == 1)
                result.add(n);
        }
    }
    return result;
}

private static String deleteLetter(String word, int index) {
    var sb = new StringBuilder(word);
    sb.deleteCharAt(index);
    return sb.toString();
}

d)The WordLadderGraph class shown in Listing C.70 computes the word ladder graph for an arbitrary set of words. The nodes of this graph are stored in the words field, and its edges are computed on the fly.

Listing C.70ch8 / words / WordLadderGraph

public class WordLadderGraph implements Graph<String> {
    private final Set<String> words;
    private final SimilarWords similar;

    public WordLadderGraph(Collection<String> words) {
        this.words = new HashSet<>(words);
        similar = new SimilarWords(words);
    }

    @Override
    public Collection<String> nodes() {return words;}

    @Override
    public Collection<String> neighbors(String word) {
        if (!words.contains(word))
            return Collections.emptyList();
        return similar.findSimilarWords(word);
    }
}

e)Four steps are necessary to transform ROCK into GOLD:

\[ \text {ROCK}\to {}\text {ROOK}\to {}\text {GOOK}\to {}\text {GOOD}\to {}\text {GOLD}. \]

To compute the list of words that cannot be transformed into GOLD, traverse the graph starting at GOLD and afterward report all nodes that weren’t reached; there are 90 such words. The words ETNA and ODIN have the largest distance 11 from GOLD.

f)The longest word ladder is the one between ISLA and ZEBU:

\begin{gather*} \text {ISLA}\to {}\text {ISLE}\to {}\text {IDLE}\to {}\text {IDLY}\to {}\text {ILLY}\to {}\text {ALLY}\to {}\text {ALAY}\to {}\text {FLAY}\to {}\text {FLEY}\to {}\\ \text {GLEY}\to {}\text {GOEY}\to {}\text {GOBY}\to {}\text {GOBO}\to {}\text {ZOBO}\to {}\text {ZOBU}\to {}\text {ZEBU} \end{gather*} There are four pairs of words that can be transformed into their reverse: REVILER/RELIVER, REVILED/DELIVER, DEIFIER/REIFIED, STENNED/DENNETS.

Solution to Exercise 8.10

a)The distribution of light is shown in Fig. C.15.

Figure C.15 Final distribution of light

b)Every object either emits light by itself or reflects incoming light. To model this behavior, we use the interface LaserPiece defined in Listing C.71, which defines two methods: emit() returns the directions in which incoming light is emitted and reflect() the directions in which light is reflected. We use the Direction class defined in Listing 8.3 to represent the four directions up, down, left, and right. The listing also defines two simple pieces: the empty square (EMPTY), which transmits incoming light unchanged, and the solid block (BLOCKER), which absorbs all incoming light. EMPTY is implemented as a function that returns a list that contains just the direction of the incoming light ray, and BLOCKER as a function that returns an empty list regardless of the incoming light.

Listing C.71ch8 / lasers / LaserPiece

public interface LaserPiece {
    default List<Board.Direction> emit() {
        return List.of();
    }

    List<Board.Direction> reflect(Board.Direction incoming);

    LaserPiece EMPTY = List::of;
    LaserPiece BLOCKER = incoming -> List.of();
}

JDK: List
Board: Direction

A laser is another simple LaserPiece: it emits light in a single fixed direction but doesn’t reflect any incoming light (Listing C.72).

Listing C.72ch8 / lasers / Emitter

record Emitter(Board.Direction direction) implements LaserPiece {
    @Override
    public List<Board.Direction> reflect(Board.Direction incoming) {
        return List.of();
    }

    @Override
    public List<Board.Direction> emit() {
        return List.of(direction);
    }
}

A more complex object is the transparent mirror because the direction of the outgoing rays depends both on the direction of the incoming ray and the orientation of the mirror. To implement reflect(), we create a table that maps all possible combinations of mirror orientations and incoming rays to the resulting outgoing directions (Listing C.73). For instance, the first key “|l” represents a vertical mirror and an incoming ray that moves towards the left, and the associated value is a list of two directions that indicates that the ray splits into two and continues to the left and to the right. The other orientations of the mirror are encoded as “\”, “-”, and “/”. The reflect() method returns the list of directions in which an incoming light ray is split; this is either one of the values stored in map or the empty list when the light ray is blocked.

Listing C.73ch8 / lasers / TransparentMirror

record TransparentMirror(String orientation) implements LaserPiece {
    static Map<String, List<Board.Direction>> map = Map.ofEntries(
            Map.entry("|l", List.of(LEFT, RIGHT)),
            Map.entry("|r", List.of(LEFT, RIGHT)),
            Map.entry("-u", List.of(UP, DOWN)),
            Map.entry("-d", List.of(UP, DOWN)),
            Map.entry("/r", List.of(UP, RIGHT)),
            Map.entry("/u", List.of(UP, RIGHT)),
            Map.entry("/l", List.of(LEFT, DOWN)),
            Map.entry("/d", List.of(LEFT, DOWN)),
            Map.entry("\\u", List.of(UP, LEFT)),
            Map.entry("\\l", List.of(UP, LEFT)),
            Map.entry("\\r", List.of(RIGHT, DOWN)),
            Map.entry("\\d", List.of(RIGHT, DOWN)));

    @Override
    public List<Board.Direction> reflect(Board.Direction incoming) {
        return map.getOrDefault(orientation + incoming.charCode(),
                List.of());
    }
}

c)The key idea is to model the problem as a graph in which each square on the board is represented by four nodes, one for each of its four sides. We can label the nodes using tuples of the form \((p,d)\), where \(p\) is the position of the square and \(d\) a direction (up, down, left, or right). The node \((p,d)\) represents a ray of light that leaves the square \(p\) in direction \(d\).

An implementation of this idea is shown in Listing C.74. The LaserBoard class extends the Board class we developed for representing Sokoban levels, which simplifies the task of computing with positions on the board and directions. It also implements the Graph interface: Each node represents a ray of light that starts at a certain position moves in a certain direction.

Listing C.74ch8 / lasers / LaserBoard

// A graph for simulating the propagation of light on a rectangular board.
public class LaserBoard extends Board
        implements Graph<LaserBoard.Ray> {
    public record Pos(int x, int y) {}
    public record Ray(Pos pos, Direction direction) {}

    private Map<Pos, LaserPiece> pieces = new HashMap<>();

    public LaserBoard(int width, int height) {
        super(width, height);
    }

    public void setPiece(int x, int y, LaserPiece piece) {
        pieces.put(new Pos(x, y), piece);
    }

    // ...
}

To compute the neighbors of a node ray in this graph, we first look up the object the ray hits next and then reflect it depending on the object’s type and the ray’s current direction (Listing C.75).

Listing C.75ch8 / lasers / LaserBoard

// Each ray is connected to the rays it spawns in neighboring squares.
@Override
public List<Ray> neighbors(Ray ray) {
    Pos neighbor = new Pos(ray.pos.x + ray.direction.xOff(),
            ray.pos.y + ray.direction.yOff());
    if (!isInside(neighbor.x(), neighbor.y()))
        return List.of();
    var newRays = new ArrayList<Ray>();
    LaserPiece piece =
            pieces.getOrDefault(neighbor, LaserPiece.EMPTY);
    for (var direction : piece.reflect(ray.direction))
        newRays.add(new Ray(neighbor, direction));
    return newRays;
}

We can now simulate the propagation of light as shown in Listing C.76. For every LaserPiece on the board, we first call emit() to determine the outgoing rays of light, and then follow each such ray by traversing the graph using breadth-first search. Every Ray discovered by visitNodes() is stored in a set rays that represents the final distribution of light on the board. For example, the resulting set of rays for the board in Fig. 8.9 can be visualized as follows:

.... .d.. .... .... .d.. .... 
.... udl. ..l. ..l. udlr ...r 
.... ud.. .... .... ud.. .... 
..l. udlr ..lr ..lr u.l. .... 

Listing C.76ch8 / lasers / LaserBoard

// Simulate the propagation of light by following the rays emitted
// by each piece on the board.
public Set<Ray> simulateLight() {
    var rays = new HashSet<Ray>();
    for (Pos p : pieces.keySet()) {
        var piece = pieces.get(p);
        for (var direction : piece.emit()) {
            var ray = new Ray(p, direction);
            visitNodes(ray, rays::add);
        }
    }
    return rays;
}

Solution to Exercise 8.11

a)We can model the board as a weighted graph in which each node corresponds to a position on the board. Using the Board and WeightedGraph types developed in this chapter, we define a graph CivBoard that models the movement on the board (Listing C.77). The terrain field holds the type of terrain for every square on the board: We use “␣” for grasslands, “f” for forests, “w” for water, and “m” for mountains.

Listing C.77ch8 / civ

public class CivBoard extends Board
        implements WeightedGraph<CivBoard.Pos> {
    public record Pos(int x, int y) {}

    private final List<Character> terrain;

    public CivBoard(int width, int height) {
        super(width, height);
        terrain = new ArrayList<>(
                Collections.nCopies(width * height, ' '));
    }

    char getTerrain(Pos p) {
        return terrain.get(index(p.x(), p.y()));
    }

    // ...
}

For a given position on the board, the outgoing edges point to neighboring positions that are reachable, and the weight of each edge reflects the cost of moving to that position (Listing C.78).

Listing C.78ch8 / civ / CivBoard

public List<Edge<Pos>> edges(Pos pos) {
    var edges = new ArrayList<Edge<Pos>>();
    for (var dir : ALL_DIRECTIONS) {
        Pos neighbor = new Pos(pos.x + dir.xOff(), pos.y + dir.yOff());
        if (!isInside(neighbor.x(), neighbor.y()))
            continue;
        int weight = switch (getTerrain(neighbor)) {
            case ' ' -> 1;
            case 'f' -> 2;
            case 'w' -> getTerrain(pos) == 'w' ? 1 : 3;
            case 'm' -> Integer.MAX_VALUE;
            default -> throw new RuntimeException("Invalid terrain");
        };
        if (weight != Integer.MAX_VALUE) {
            edges.add(new Edge<>(neighbor, weight));
        }
    }
    return edges;
}

b)Figure C.16 shows the distance of every square from G2.

.
A B C D E F G H I J K L M N O P
0 11 9 7 5 4 3 4 5 7 9 11 10 11 12 13 14
1 10 8 6 4 3 2 1 4 6 8 9 9 10 11 12 14
2 10 9 7 5 3 1 0 3 4 6 7 8 9 11 13 15
3 10 9 8 6 4 2 3 4 5 6 7 11 12 13 14
4 11 10 6 4 3 4 5 6 7 9 13 14 15
5 10 7 5 4 5 7 8 9 14 15 16
6 13 12 11 9 8 6 7 9 11 10 11 12 13 15 16
7 13 12 11 10 10 8 9 11 13 14 12 12 13 15 18 17
8 14 13 12 11 11 10 11 13 15 16 14 13 14 15 17 18
9 15 14 13 13 13 12 13 15 16 17 15 14 15 17 18 20
10 16 15 15 15 15 13 14 15 16 17 16 15 16 17 19 21
Figure C.16 The distance from G2 to every square on the board.

There several similar shortest paths of length 13 from G2 to M7. One is

\[ \text {G2}\to {}\text {H2}\to {}\text {H3}\to {}\text {H4}\to {}\text {I4}\to {}\text {J4}\to {}\text {J5}\to {}\text {K5}\to {}\text {K6}\to {}\text {L6}\to {}\text {L7}\to {}\text {M7}. \]