Čtvrtá série dvacátého pátého ročníku KSP

I v této sérii můžete získat sladkou odměnu! Každému, kdo vyřeší všechny vstupy v CodExu rychleji než vzorové řešení (a správně), pošleme čokoládu.

Termín odeslání Vašich řešení této série jest určen na 25. března 2013 8:00. Termín odevzdání CodExové úlohy je pak 26. března 2013 8:00. Řešení můžete odevzdávat jak elektronicky, tak klasickou poštou na známou adresu.

Dotazy ohledně zadání můžete posílat na adresu ksp@mff.cuni.cz, nebo se ptát přímo na diskusním fóru KSP.

Zadání úloh

Deníky japonského velvyslance v ČR p. Yamady. Dešifrováno a přeloženo v NSA 2023-11-15.

To byl zase den. Nakonec všechno dobře dopadlo, ale jsem opravdu vyčerpaný. Tak vyčerpaný, že bych snad odložil dnešní zápis až na zítřek. Ale to bych měl špatné spaní a vůbec bych si neodpočinul. Na tom doporučení psychologa něco bude, vypsat se ze svých starostí. Tak tedy do toho.

Den začal jako každý jiný. Nějaké nepodstatné schůzky, podepisování, uklánění a potřásání. Ti Evropané jsou divní. Tohle musí přispívat k šíření nemocí.

Pak ale přišlo první vytržení ze stereotypu. Kódovaná zpráva od jednoho kontaktu u místní policie. Budu si muset promluvit se svými lidmi. Taková jednoduchá šifra, primitivní prohazování písmen. Takto mi ty kontakty dlouho nevydrží, někdo je určitě objeví.


25-4-1 Přesmyčky (10 bodů)


Každé slovo je zašifrované jako posloupnost písmen a číslo k. Písmena jsou ze zašifrovaného slova, jen přeházená. Nalezněte původní slovo, což je k-tá přesmyčka v lexikografickém pořadí z daných písmen. Například pro vstup

acb 3
je výsledkem bac, neboť přesmyčky v lexikografickém pořadí jsou: abc acb bac bca cab cba.

Pozor, písmena se mohou opakovat. V takovém případě jsou stejná písmena nerozlišitelná, tedy třeba slovo aaa má jedinou přesmyčku, slovo baa má přesmyčky tři, konkrétně aab aba baa.

Lehčí variantaLehčí varianta (za 7 bodů): Vyřešte úlohu za předpokladu, že se písmena opakovat nemohou.

Řešení

Po dekódování se o mě však pokusil infarkt. Naštěstí jsem jej kratičkou meditací zažehnal. Na víc než 5 minut jsem však čas neměl. Ve zprávě totiž stálo, že policie má tip na jeden z mých skladů zboží a chystají dnes razii. Díky varování mám naštěstí několik hodin náskok, začnu tedy plánovat, jak zachránit jak sklad, tak své lidi.

Plán byl jednoduchý. Je to totiž prodejní sklad, takže má i místnost pro styk s veřejností. A ta je maskovaná jako levné čínské bistro. Stačí tedy zboží naložit a odvézt. Až dorazí policie, najde jen kuchařku a číšnice. Jediný háček byl tedy v odvozu.

Má organizace má, samozřejmě, k dispozici dostatečné množství rychlých vozů. Pokud jsou ale naložené, musí v zatáčce přibrzdit. A to zdržuje. A čím déle budou vozy na cestě, tím větší je šance, že je někdo odhalí. Vzal jsem tedy mapu Prahy a začal plánovat trasu s co nejméně zatáčkami.


25-4-2 Plánování trasy (9 bodů)


Představme si Prahu jako čtvercovou síť. Na některých políčkách stojí překážky (budovy, policisté a podobně), těmi ostatními jde projíždět. Dále máme na mapě vyznačeno startovní a cílové políčko. Obě tato políčka jsou průjezdná.

Vůz se vydá ze startovního políčka některým ze čtyř směrů a pokračuje stále rovně, až kam to jde (tedy, kdyby pokračoval ještě jedno políčko, najel by na překážku, případně by vyjel z mapy). Zde si opět vybere jeden ze zbylých tří směrů a pokračuje, kam až to jde. Tedy, nikdy není ochotný zatočit, pokud před sebou má volné místo. Pokud se ocitne na cílovém políčku, zastaví se.

Nalezněte trasu, která obsahuje co nejméně zatáček. Z takových, pokud jich bude víc, vyberte tu nejkratší.

Řešení

Po tak náročné činnosti jsem se šel projít na zahradu. Ale klid mi to nepřineslo. Napřed tam dělali hluk ti zahradníci, co sekali zahradu. A všude nechávali hrozně moc posekané trávy. Doufám, že se zítra nadřou při jejím svážení. Oni si určitě budou chtít práci usnadnit, takže bych jim měl dát za úkol posvážet trávu z nějaké části, kde to ani tak nebudou mít příliš jednoduché. Pozorovat je při práci mi totiž zítra jistě zvedne náladu.


25-4-3 Rozpis svozu (13 bodů)


Trávník je obdélníkový a rozdělený na čtverce o straně 1 metr. Víme, kolik posekané trávy se nachází na každém ze čtverců.

Jsou dány rozměry trávníku N, M. Dále dostaneme K oblastí (určených svým levým horním a pravým dolním rohem). Chceme pro každou z těchto oblastí určit nejmenší nutnou práci pro svoz trávy z celé oblasti na nějaké jedno políčko.

Práce se spočítá jako hmotnost trávy na čtverci vynásobená vzdáleností, kam se veze, s tím, že vozit smíme jen vodorovně nebo svisle. Tedy vzdálenost mezi čtverci (0, 0) a (3, 4) je 7, nikoliv 5.

Pro každou oblast určete políčko, kam trávu svézt, aby celková práce byla nejmenší možná, a příslušné množství práce. Pokud existuje takových nejlepších políček více, vypište libovolné z nich. Složitost algoritmu optimalizujte pro případy, kdy K je řádově stejně velké jako N.

Příklad: (První řádek obsahuje rozměry trávníku, dalších M řádků popisuje hmotnosti trávy na jednotlivých čtvercích, pak následuje číslo K a K řádků popisujících oblasti.)

3 5
8  2  1  5  3
6  9  1  2  7
1  1  3  2  10
3
1 1 3 3
3 2 5 3
2 1 4 2
Nejvýhodnější políčka s příslušnou prací jsou následující:
2 2 36
5 3 22
2 2 24

Poznámka: Pokud vám to připadá téměř jako zadání úlohy 25-3-3, jen na dvojrozměrném trávníku, pak máte zcela správný pocit.

Řešení

Než jsem stihl rozmyslet, kterou část jim vyberu, objevila se mi tu nějaká ženská. Nepamatuji se, že bych takové kdy poskytl audienci a rozhodně jsem to ani neplánoval. Ona však měla tolik drzosti, že se mě hned začala vyptávat na mé soukromé obchody. A, považte, dokonce japonsky. Takové neúcty bych se ve svém rodném Japonsku rozhodně nedočkal.

Bohužel, ve zdejších končinách není přípustné nosit samurajský meč a zastrašovat jím drzé zvědavce. Nezbylo mi tedy než sáhnout po telefonu a požádat o laskavost jednoho z mých věrných lidí u policie. Když jsem se tenkrát sázel se svým čínským kolegou, kdo dokáže podplatit i posledního policistu, nikdy jsem netušil, jak moc se to bude hodit.


25-4-4 Podplácení (8 bodů)


Policejní hierarchie je jakási pyramida. Úplně nahoře se nachází jeden kapitán. Ten má k dispozici dva nadporučíky. Dále existují tři poručíci, čtyři podporučíci, atd. až úplně dolů k řadovým policistům. Celá hierarchie o výšce 7 je schematicky znázorněna jako příklad níže. Nedivte se, že někteří policisté mají dva přímé nadřízené, v naší zemi je možné cokoliv.

Příklad k 25-4-4

V podplácení soutěží dva velvyslanci. Ten, který je na řadě, si vybere jednoho policistu, který ještě nebyl podplacen, a předá mu zavazadlo naplněné penězi. Tento policista obejde všechny své ještě nepodplacené nadřízené (přímé i nepřímé) a peníze jim spravedlivě rozdělí. Tím je podplatí. Takto by tedy vypadala hierarchie po jednom podplacení:

Příklad k 25-4-4

Vyhrává ten velvyslanec, který podplatí posledního policistu.

Pokud je zadaná výška celé hierarchie, určete, který z velvyslanců má vyhrávající strategii. Začíná Japonec.

Řešení

A opravdu, po kratičké chvilce se objevil policista a zbavil mě jí. Asi jí začal docela zatápět, což je jedině dobře. Po chviličce se zcela zřejmě pokusila přechytračit policistu nějakým trikem s kalkulačkou. Nemínil jsem čekat na to, až se jí to podaří, a raději jsem zmizel opět dovnitř. Už mi v kanceláři stačili připravit čaj.

Jak jsem si tak sedal, uvědomil jsem si, že to byl úplně stejný typ kalkulačky, na jaké jsem se učil vyššímu účetnictví. V tomto účetnictví bylo mnoho kliček a triků, jak v něm schovat výdělky, do kterých nikomu nic není. Můj nejoblíbenější byl ten, že úředníci neuměli počítat s velkými čísly, proto pracovali jen se zbytky po vydělení svým inteligenčním maximem. To skýtalo opravdu mnoho možností, jak je přimět si myslet, že vlastně nikdo nevydělal nic, a tedy že ani nemá platit žádné daně.


25-4-5 Účetnictví (12 bodů)


Praktická CodExová úlohaNa začátku nemáme na účtu nic (svítí na něm tedy hezká 0). Budeme provádět transakce po dobu k dní. V i-tém dni provedeme transakci v hodnotě i. Umíme ovlivnit, jestli peníze přijdou na účet, nebo z něj odejdou.

Úředníci berňáku počítají mod n. Zvolme například n = 50. Máme-li na účtu 20 Kč, můžeme si na něj nechat převést od kamaráda 30 Kč a berňák si bude myslet, že nemáme nic. Kdybychom naopak z prázdného účtu kamarádovi 30 Kč odvedli, skončíme s 20 korunami.

Zajímalo by nás, kolika způsoby můžeme rozvrhnout všechny transakce tak, abychom na konci měli opět „prázdný“ účet. Počet způsobů ale roste velmi rychle, stačí tedy počet „cest z nuly do nuly“ počítat modulo 109 + 7.

Tato úloha je praktická a řeší se ve vyhodnocovacím systému CodEx. Přesný formát vstupu a výstupu, povolené jazyky a další technické informace jsou uvedeny v CodExu přímo u úlohy.

Řešení

Odpoledne se opět neslo ve znamení nepodstatných potřásání a uklánění. Tedy, s výjimkou dvou telefonátů. Jeden mi sděloval, samozřejmě smluveným kódem, že se přesun skladiště zdařil.

Druhý telefonát oznamoval radostnou zprávu, že nové zboží z domoviny zdárně dorazilo. Samozřejmě, maskované jako skupinka turistů s foťáky. Můj nevlastní bratranec z třetího kolena Mashiro je opravdu třída. Turisté nic netušili, a dokonce jako maskování poslal i svého vlastního synovce. Jak jsem se nasmál, když mi předevčírem vyprávěl na videohovoru, že se malý Tanaka tak moc těší.

Večer byl ale opět namáhavý. Obchodní jednání s jedním z klientů. Dožadoval se množstevní slevy. Nakonec se mi takovou katastrofu podařilo zažehnat, ale jen díky tomu, že jsem ho obehrál v prastarých japonských Triádách.


25-4-6 Triády (12 bodů)


Triády jsou karetní hra. Celá pravidla jsou komplikovaná, nám bude stačit jen základní princip. Na stůl se vždy vyloží n karet. Každá karta nese k různých vlastností (kde k může být velké) a každá vlastnost může mít jednu ze 3 různých hodnot.

Trojici vyložených karet nazveme triádou, pokud se v každé vlastnosti všechny tři karty shodují, nebo se v ní navzájem liší. Pokud bude n = 4, k = 3 a vyložené karty (1, 2, 3), (1, 2, 1), (1, 3, 2) a (1, 1, 3), tak potom druhá, třetí a čtvrtá karta tvoří triádu. V první vlastnosti se shodují a ve druhých dvou se liší.

Vaším úkolem je mezi zadanými kartami najít triádu, nebo zjistit, že mezi nimi žádná není (samozřejmě rychleji než soupeř).

Řešení

Tak to by byl další namáhavý den. Pro jistotu musím ještě svůj deník zašifrovat, aby se k němu nedostal někdo, kdo by jej mohl zneužít ve svůj prospěch. Jak tak prohlížím to šifrovací zařízení s knoflíky, přemýšlím, jak dlouho by někomu trvalo, než by vyzkoušel všechna možná hesla. Heslo se zadává nastavením knoflíků do správných pozic. Na mé verzi je celých 20 knoflíků, každý s 12 pozicemi. To by mohlo i takové NSA trvat aspoň 100 let, a tou dobou už to nebude můj problém.


25-4-7 Šifrovací knoflíky (10 bodů)


Šifrovací zařízení na sobě má k otočných knoflíků a každý jde nastavit do n různých pozic (knoflíky se chovají cyklicky, tedy je možné je protočit). Těmito knoflíky se nastavuje šifrovací klíč, a to jak k zašifrování, tak poté k dešifrování.

My klíč neznáme, proto bychom rádi vyzkoušeli všechny možnosti nastavení knoflíků. Nechceme se však zdržovat, a proto chceme každý klíč nastavit právě jednou. V jednom kroku umíme otočit jedním knoflíkem o jednu pozici.

Popište způsob, jak knoflíky otáčet, abychom nastavili každý klíč právě jednou. Zároveň požadujeme, aby na konci byly knoflíky ve výchozích pozicích.

Lehčí variantaLehčí varianta (za 5 bodů): Vyřešte úlohu bez požadavku, aby se knoflíky vrátily do výchozích pozic.

Řešení

V archivu NSA nalezl

Michal „vorner“ Vaner


25-4-8 TeXgramy (14 bodů)


SeriálUpozornění: Přesný vzhled vysázených konstrukcí je v PDF verzi! Ve webové verzi mohou být různé nepřesnosti, zvláště u vzhledu vysázených vzorců. Pokud si tedy chcete být jisti tím, jak něco vypadá, sáhněte prosím po verzi v PDF.

Ve čtvrtém dílu seriálu o TeXu si ukážeme pokročilé programování. Potkáte proměnné, podmínky, čtení souboru i zápis. Naučíme se, jak automaticky číslovat nadpisy, tabulky, obrázky i cokoli jiného.

Čísla, rozměry a skipy

TeX nabízí uživateli 256 celočíselných registrů, ke kterým se přistupuje primitivem \count stejně jako ke \catcode. S číselným registrem se dá pracovat stejně jako s \catcode, jen \count má větší rozsah (32bitové celé číslo se znaménkem).

Na ukládání rozměrů poslouží \dimen. Je to ve skutečnosti také celočíselný registr, jehož základní jednotkou je ovšem 1 sp (1 pt = 65536 sp). TeX nepracuje s rozměry většími než 230sp = 16384  pt, což je něco přes 570 cm, takže by vám to do začátku mělo stačit, pokud zrovna nenavrhujete billboard obludných rozměrů.

Registry typu \skip pak slouží k ukládání pružných rozměrů (s roztažností). Jejich omezení je stejné jako u pevných rozměrů.

Kromě vypisování primitivem \the a přiřazení umí tyto typy registrů také základní aritmetické operace. Primitivum \advance například slouží ke sčítání.

\count0=1 % přiřaď 1 do \count0
\advance\count0 by 1 % zvyš o 1
\the\count0 % vysázej 2
\advance\count0 by -15 % sniž o 15
\the\count0 % vysázej -13
\dimen0=1in
\advance\dimen0 by 1cm
\the\dimen0 % vysázej 100.72273pt

Klíčové slovo by je možno vynechat, ale pro přehlednost se hodí.

Celočíselné registry umí také celočíselně násobit a dělit, stejně tak rozměry a skipy.

\count0=30
\multiply\count0 by 5
\the\count0 % vysázej 150
\divide\count0 by 7
\the\count0 % vysázej 21

\skip0=1pt plus 2pt minus 3pt
\multiply\skip0 by 3
\the\skip0 % 3pt plus 6pt minus 9pt

Rozměry můžeme také násobit číselnou konstantou uvedenou před nimi (skipy ani celočíselné konstanty ne). Pozor, pokud se použije skip tam, kde se očekává rozměr, TeX mlčí jako hrob a jako rozměr vezme základní velikost skipu.

\dimen0=1pt
\skip0=\dimen0 plus 0.3\dimen0
\the\skip0 % 1pt plus 0.3pt
\dimen0=0.6\skip0
\the\dimen0 % 0.6pt

Pokud si ukázku opravdu spustíte, zjistíte, že některé vypsané rozměry nejsou přesné. TeX je totiž počítá všechny celočíselně a zaokrouhluje. Nicméně 1 sp ≈ 5,36 nm, takže případné rozdíly jsou zanedbatelné (vlnová délka viditelného světla je řádově 100 sp). Je však vhodné o zaokrouhlování vědět.

Mnoho interních hodnot TeXu jsou čísla nebo rozměry; kompletní seznam můžete najít v TeXbooku na straně 272 a následujících.

Přiřazení do všech registrů i interních hodnot je lokální v rámci skupiny, není-li uvedeno primitivum \global:

\dimen0=5pt\dimen1=\dimen0
\the\dimen0 \the\dimen1 % 5pt 5pt
{\dimen0=10pt\global\dimen1=\dimen0
\the\dimen0 \the\dimen1} % 10pt 10pt
\the\dimen0 \the\dimen1 % 5pt 10pt

Boxy

TeX poskytuje 256 boxových registrů. Můžete si do nich uložit libovolný hbox nebo vbox a nad nimi pak provádět další operace. Přiřazení do boxu se provádí primitivem \setbox a jeho vysázení/použití primitivem \box.

\setbox0=\vbox{Ahoj Karle\par Jak se máš?}
Něco mezi.\par
\box0 % Box s pozdravem se vloží sem.

Po použití primitiva \box se registr vyprázdní. Pokud potřebujete, aby tam box zůstal, použijte na to primitivum \copy.

\def\fivetimes#1{{\setbox0\vbox{#1}%
\copy0\copy0\copy0\copy0\box0}}

TeX zná rozměry uloženého boxu. Dostanete se k nim (a dají se i změnit!) použitím primitiv \ht (výška), \dp (hloubka) a \wd (šířka).

\def\measure#1{{\setbox0\vbox{#1}%
(\the\ht0\ + \the\dp0) $\times$ \the\wd0}}
\def\nullbox#1{{\setbox0\vbox{#1}%
\ht0=0pt\dp0=0pt\wd0=0pt\box0}}
\quad R1\par
\setbox1\vbox{\hrule
  \quad\quad R2\par
  \quad\quad\quad R3\par\hrule}
\measure{\copy1}\par
\nullbox{\box1}
\quad\quad\quad\quad R4\par
\quad\quad\quad\quad\quad R5\par

Všimněte si, že takto nelze natahovat nebo smršťovat samotný obsah boxu. To TeX neumí. (pdfTeX to ve skutečnosti umí, ale není to úplně přímočaré. Řekněte si kdyžtak na fóru o pohádku o transformačních maticích.) Umí však předstírat, že box má jinou velikost, než je ta skutečná. Toho jste si jistě všimli v příkladu. Možné využití jistě vymyslíte sami.

Rozbalování boxů

Čas od času je potřeba box rozbalit. Například si v boxu poskládáte kousek stránky a chcete, aby se TeX mohl rozhodnout, že uprostřed něj zlomí stránku. V takovém případě se vám můžou hodit primitiva \unvbox a \unhbox, kterými se vloží obsah odkazovaného boxu. Pokud potřebujete, aby se box akcí nevyprázdnil, použijte primitiva \unvcopy nebo \unhcopy.

Ještě vyšší liga je pak dělení vboxu primitivem \vsplit:

% Do vboxu vložíme několik odstavců textu
\setbox0\vbox{...}

% Uřízneme z něj a vložíme prvních 10cm
\vsplit0 to 10cm
\hrule % například čára na oddělení

% Vložíme zbytek
\box0

Uříznutí obsahu z boxu se koná na rozhraní boxů uvnitř. Takže obvykle se netrefíte přesně na rozměr. TeX zde používá naprosto stejný algoritmus jako na lámání stránky (ten nás v hrubých rysech čeká příště). Dostanete tedy box vysoký přesně zadaný rozměr se správně roztahanými mezerami.

Úmyslně zde píšu box. Následující konstrukce je totiž povolena:

% Do vboxu vložíme několik odstavců textu
\setbox0\vbox{...}

% Uřízneme z něj prvních 10cm do boxu 1
\setbox1\vsplit0 to 10cm

% ... a nakopírujeme dvakrát hned pod sebe
\copy1\box1

Pojmenované registry

Ve složitějším dokumentu je vhodné pojmenovat si proměnné, neboť mezi očíslovanými boxy se dá jednoduše ztratit. K tomu slouží sada maker \new.... Povšimněte si rozdílu mezi prací s boxem a s číselnými veličinami.

\newcount\pocitadlo
\newdimen\velikost
\newskip\guma
\newbox\krabicka

\pocitadlo = 5\relax
\the\pocitadlo

\velikost = 5mm
\the\velikost

\guma = 5cm plus 1cm minus 1cm
\the\guma

\setbox\krabicka\vbox{obsah boxu}
\copy\krabicka
\unvcopy\krabicka
\vsplit\krabicka to \velikost
\box\krabicka

Vypíše toto:

Plain TeX rezervuje některé registry pro svá makra a některé registry pro vaše makra (přes \new...). Pokud se vám nechce si rezervovat registr, který používáte jenom jako dočasné úložiště někde uvnitř složitých maker, jsou vám k dispozici registry s jednocifernými čísly. I na ně si však dejte pozor – pokud se v takovém místě začne lámat stránka, nebo pokud je změníte globálně, dočkáte se velmi nepříjemných překvapení.

Pokud si chcete být jisti, používejte vždy a na všechno pojmenované registry.

Podmínka

TeX nabízí sadu podmínek \if..., které umožňují větvit kód a psát mocnější makra. Nejprve si ukážeme možnosti, které nám TeX nabízí, a potom detailně prozkoumáme, jak zpracovává zdrojový kód, který obsahuje podmínku.

  • \if expanduje následující tokeny, dokud to jde. Pokud jsou ve výsledku první dva tokeny stejné, je podmínka splněna. (\if aa je pravda, \if ab je lež)
  • \ifx vezme dva následující tokeny bez expanze. Pokud jsou identické (stejný znak, stejná kategorie, případně stejně definované makro nebo stejné primitivum), je podmínka splněna. Tahle podmínka se hodí zvlášť ve chvíli, kdy potřebujete detekovat například prázdný parametr:
    \def\x#1{\def\p{#1}\ifx\p\empty...}
  • \ifnum porovnává dvě čísla. Povolené operace jsou >, < a =, přičemž se také parametr expanduje; \ifnum\count1>5\xy nemusí být kompletní podmínka, neboť za pětkou může pokračovat číslo, tedy i \xy za pětkou bude expandováno (a případně i další makra).
  • \ifodd je pravda, pokud je uvedené číslo liché.
  • \ifdim porovnává dva rozměry analogickým způsobem jako podmínka \ifnum.
  • \ifvoid, \ifhbox nebo \ifvbox detekuje, jestli je boxový registr prázdný, zaplněný hboxem nebo vboxem. Jako parametr čte jedno číslo.
  • \ifhmode, \ifvmode, \ifmmode a \ifinner slouží ke zjištění, v jakém módu zrovna jsme (horizontálním, vertikálním, matematickém, případně vnitřním). První tři se vzájemně vylučují, čtvrtý je nezávislý (podmínka \ifinner je splněna, pokud jsme uvnitř explicitního vboxu, hboxu, nebo uvnitř jednodolarové matematiky).

Také si můžete definovat vlastní podmínku makrem \newif, kterou si pak můžete přepínat dle libosti.

\newif\ifbagr % všechny podmínky mají začínat if
\bagrtrue % nastavím, že je podmínka splněna
\bagrfalse % nastavím, že podmínka není splněna

Ještě jsme ale neukázali kompletní syntaxi podmínky. TeX, když uvidí \if..., vyhodnotí podmínku a rozhodne se, jestli je pravdivá, nebo nepravdivá. Pokud je pravdivá, bude pokračovat dále ve zpracovávání, dokud nenajde \else. Od této chvíle jen čte tokeny a zahazuje je, dokud nenajde \fi. TeX dodržuje uzávorkování podmínek, takže pokud je v zahazovaném seznamu tokenů \if..., zahodí i příslušné \fi.

Pokud je podmínka nepravdivá, zahodí se všechno do \else nebo \fi, co nastane dřív. Větev \else je totiž nepovinná.

Dejte si pozor na to, že tokeny \if..., \else a \fi ukončují například načítání čísla nebo rozměru. Není tedy možné napsat \count\if... 5 \else 6\fi apod. Podmínky ovšem nevytvářejí skupinu, jsou tedy běžné například takovéto konstrukce:

\ifnum\count0>10
  \def\next{...}
\else
  \let\next\relax
\fi\next

Úkol 1 [4b]

Vymyslete, jak automaticky číslovat nadpisy. Definujte sadu maker pro tři úrovně nadpisů. Makro nesmí brát za parametry nic jiného než text nadpisu. Nadpisy se automaticky číslují (od jedné), čísla nadpisů nižší úrovně začínají vždy od jedné po každém nadpisu vyšší úrovně.

Rozmyslete a vhodně ošetřete situaci, kdy bude text nadpisu příliš dlouhý, takže se nevejde na řádek. V řešení úkolu se zkuste obejít bez primitiva \global.

Vzhledem k tomu, že už jste poměrně zkušení, připravte makra včetně vhodného nastavení mezer a velikosti písma (vizte dále). Estetická kvalita výstupu bude zahrnuta do hodnocení.

Soubory: Vstup a výstup

Během sazby je možno pracovat i s jinými soubory než tím vstupním. Je vhodné si je nejprve pojmenovat, to se provádí makrem \newread (pro vstup) a \newwrite (pro výstup). Přesněji řečeno, tímhle si pojmenujete ukazatel na soubor. Jeden ukazatel nemůže zároveň ukazovat na vstup i výstup a jeden soubor není možno otevřít zároveň pro čtení i pro zápis.

Soubor otevřete primitivem \openin nebo \openout, pak je z něj možno číst nebo do něj zapisovat primitivem \read nebo \write a nakonec je vhodné soubor zavřít primitivem \closein nebo \closeout.

\newread\cti
\newwrite\pis
\openin\cti=in % in je jméno vstupního souboru
\openout\pis=out % out je jméno výst. souboru

\read\cti to \neco
\write\pis{\neco}

\closein\cti
\closeout\pis

Čtecí operace se odehrávají ihned, zapisovací však až ve chvíli, kdy se definitivně skládá stránka. Pokud však vložíte před takovou operaci primitivum \immediate, provede se hned. Důvod je jednoduchý – občas potřebujete při zapisování do souboru vědět, na které stránce nakonec skončí okolní text.

Primitivum \write svůj argument před zapsáním kompletně expanduje; potřebujete-li do výstupu propašovat přímo něco s backslashem (například pokud budete ten soubor za chvíli vkládat primitivem \input), předřaďte \noexpand.

Úkol 2 [4b]

Rozšiřte řešení úkolu 1 o sazbu obsahu. Tedy přidejte příslušná makra a upravte stávající. Uvažujte sazbu obsahu na konci i na začátku, nezapomeňte rozmyslet sazbu příliš dlouhých nadpisů (které se nevejdou na řádek obsahu, takže bude potřeba je rozdělit) apod.

Obsah vypadá tak, že na každém řádku je na začátku číslo nadpisu, pak text nadpisu a na konci řádku číslo stránky.

Pokud budete sázet obsah na začátku, počítejte s víceprůchodovým zpracováním (na jeden průchod to nejde).

K vyřešení tohoto úkolu se bude hodit vědět, že číslo aktuální strany se nachází v číselném registru jménem \pageno.

Úkol 3 [6b]

Vytvořte makro \multicolumn{X}, kterému předáte jako X jedno celé číslo. Všechno mezi „začátkem“ \multicolumn{X} a „koncem“ \endmulticolumn bude vysázeno v X sloupcích stejné šířky vedle sebe (dohromady včetně mezer dají šířku sazby mimo toto prostředí).

Mezi sloupci nechť je mezera, jejíž celkovou šířku bude určovat registr \newdimen\multicolumngap, uprostřed ní nechť je svislá čára oddělující sloupce široká \multicolumnline.

Předpokládejte, že výsledná sazba se vejde na jednu stránku, tedy neřešte stránkový zlom. Vyhněte se načítání vnitřku prostředí do parametru makra. \multicolumn nechť prostředí inicializuje a \endmulticolumn nechť prostředí uzavře a vysází příslušný počet sloupců.

Za řešení, které bude zvládat jen X=2, dostanete maximálně 3 body.

Různé druhy písem

Primitivní metoda, jak pracovat s písmem, je načtení a použití jednoho fontu. Konstrukcí \font\xyz=csr10 jste řídící sekvenci \xyz ztotožnili s použitím běžného počeštěného desetibodového patkového fontu z rodiny Computer Modern.

Uvedená konstrukce může být doplněna ještě upřesněním typu at 15pt, což vezme původní vkládaný font a zvětší jej na uvedený rozměr.

Počeštěné fonty z rodiny Computer Modern se jmenují následovně:

Číslo u jména fontu udává základní velikost v bodech (pt). U běžnějších fontů (csr, csbx) se obvykle dodávají i jiné základní velikosti, neboť například v menších velikostech je font širší – fontům se různě mění proporce, zvětšení fontu není prosté geometrické natažení.

Také je nutno poznamenat, že základní velikost fontu není velikost písmenek. Obvykle se jedná o součet maximální výšky a maximální hloubky písmene.

Rozsah dodávaných fontů záleží na distribuci a na balíkách, které máte nainstalované. V případě CM fontů navíc existuje tzv. Sauterova parametrizace, to je generátor všech základních velikostí v rozsahu cca 2 pt50 pt.

Běžná instalace csplainu obsahuje obvykle font csr velikostí 5, 6, 7, 8, 10, 12 a 17.

Po nastavení fontu je také potřeba správně nastavit některé další hodnoty, typicky \baselineskip.

Matematické fonty zůstávají nedotčeny; pokud potřebujete měnit i velikost písma v matematice, zkuste se podívat do TeXbooku (od strany 153) nebo do TBN (sekce 5.3), případně použít nějaký sofistikovaný systém, třeba OFS.

Olšákův systém fontů (OFS)

Pokud potřebujete seriózně pracovat s fonty a nechce se vám zabíhat do detailů, je vhodné použít nějaký balík, který práci s fonty abstrahuje. Osobně doporučím prostudovat dokumentaci k OFS. Je to velmi chytře napsaný a mocný systém, který sám běžně používám v sazbě a který používáme i v KSP.

Jan „Moskyto“ Matějka

TeXající hroch
Za obrázek TeXajícího hrocha děkujeme Petře Pelikánové.
Pokud i v sobě máte výtvarného ducha, budeme rádi, pokud ho také probudíte :-)

Řešení