В этой группе заданий, используется, конструкция с ключевым словом CASE. Она удобно структурирует код и повышает читабельность программ, разумеется, все примеры можно переделать с применением оператора IF, так часть программистов придерживается этого варианта, считая CASE плохим стилем программирования, но они не правы, плохой код можно написать с любыми конструкциями, операторами и на любом языке программирования, к тому же, чем больше конструкций вы будете знать, тем лучше вы будете понимать программирование.
Для работы ключевых слов конструкции CASE на SP-Forth нужно подключить библиотеку, в которой она определена, написав следующий код в начале файла:
S" C:\Program Files (x86)\SP-Forth\devel\~moleg\lib\util/case.f" INCLUDED
В вашем случае часть пути до SP-Forth может быть другой, в зависимости от того куда вы установили свою Форт систему. Или по относительному пути:
S" \devel\~moleg\lib\util/case.f" INCLUDED
Синтаксис этой конструкции прост, начинается ключевым словом CASE и заканчивается ENDCASE. Внутри этих операторных скобок пишем значение и действия, которые нужно выполнить, в случае если наш параметр, ему соответствует. Опишем более подробно: сначала идёт значение параметра, затем ключевое слово OF и ENDOF, это тоже операторные скобки, внутри которых будет код, для данного значении параметра, то есть операторы языка Forth и/или вызов других слов, уже определенных ранее. Ниже приведём схему шаблона:
Значение_Параметра OF < операторы языка и/или определённые ранее слова > ENDOF
Окончательно структура конструкции CASE примет вид:
CASE
Вариант-1 OF <действия при вариант-1> ENDOF
Вариант-2 OF <действия при вариант-2> ENDOF
И т.д.
ENDCASE
Если все выглядит слишком абстрактно и не понятно, то на примерах все должно стать наглядным и очевидным. Сначала подключим две библиотеки которые будем использовать во всех примерах, в этой группе заданий, во избежание ошибок «-2003 WORD OR FILE NOT FOUND», что значит слово не определено.
S" C:\Program Files (x86)\SP-Forth\devel\~moleg\lib\util/case.f" INCLUDED
S" lib/include/float2.f" INCLUDED
Первая библиотека, как было сказано выше, определяет работу конструкции CASE, а вторая вам должна быть знакома из предыдущих заданий, как и прежде для работы с числами вещественного типа.
В первом примере по номеру дня недели вывести его название.
: CASE1 ( DAY-> ) \ SLOVESNOE_OPISANIE. - точка после SLOVESNOE_OPISANIE означает печать на экран
CASE
1 OF ." Понедельник" ENDOF
2 OF ." Вторник" ENDOF
3 OF ." Среда" ENDOF
4 OF ." Четверг" ENDOF
5 OF ." Пятница" ENDOF
6 OF ." Суббота" ENDOF
7 OF ." Воскресенье" ENDOF
ENDCASE ;
Примеры работы слова CASE1
1 CASE1
Понедельник Ok
2 CASE1
Вторник Ok
7 CASE1
Воскресенье Ok
8 CASE1
Ok Ok
Так как в условии сказано диапазон ввода, мы не стали делать «защиту от дурака» - обработку некорректных данных, но это предусмотрено системой, что покажем далее, в случае такой необходимости. У нас же при вводе восьмерки программа никак не реагирует, игнорируя некорректный, непредусмотренный условиями задачи случай.
А вот в примере два нам предстоит обработать некорректный ввод, недопустимый по логике задачи, в котором нужно вывести названия оценки 1 – «плохо», 2- «неуд», 3 – «уд», 4 – «хор» и 5 – «отл». Действия, при некорректных данных пишутся перед ключевым словом ENDCASE, но после ENDOF последнего варианта. Во избежание будущих проблем с кодировкой, вы можете перевести текст на английский или использовать русский с кодировкой вашей консоли, иначе будут выведены на экран непонятные символы. Если еще остались вопросы по логике работы слова CASE, то разберём, подытожив, переведя на язык IF. CASE берет со стека число и сравнивает с первым вариантом, при совпадении выполняя соответствующий ему код и все работа слова завершена, в случае отличия сравнивает со вторым и так далее пока не будет равенства одному из предусмотренных вариантов. Когда ни один из вариантов не подошел, выполняется «дефолтный» код (если он есть) между ENDCASE и последним ENDOF, завершая описание конструкции.
: CASE2 ( OCENKA -> ) \ SLOVESNOE_OPISANIE.
CASE
1 OF ." Плохо" ENDOF
2 OF ." Неудовлетворительно" ENDOF
3 OF ." Удовлетворительно" ENDOF
4 OF ." Хорошо" ENDOF
5 OF ." Отлично" ENDOF
." Ошибка"
ENDCASE ;
Тест программы на различных данных
-1 CASE2
Ошибка Ok
0 CASE2
Ошибка Ok
1 CASE2
Плохо Ok
2 CASE2
Неудовлетворительно Ok
3 CASE2
Удовлетворительно Ok
4 CASE2
Хорошо Ok
5 CASE2
Отлично Ok
6 CASE2
Ошибка Ok
Практически полный разбор всех вариантов, показывает корректность работы кода на всех тестовых данных.
В примере три по номеру месяца нужно определить время года и вывести это на экран: зима – декабрь (12), январь (1), февраль (2), аналогично для весны, лета и осени.
: CASE3 ( MONTH -> ) \ SEASON.
CASE
12 OF ." Зима" ENDOF
3 < uOF ." Зима" ENDOF
6 < uOF ." Весна" ENDOF
9 < uOF ." Лето" ENDOF
12 < uOF ." Осень" ENDOF
ENDCASE ;
Сперва сравниваем с 12 (декабрь), и выводим Зиму в случае истинности, затем вводится новая конструкция сравнения – меньше трех. Результат будет истинным если введено 1 (январь) или 2 (февраль) и соответственно также печатаем Зиму. Далее идет проверка меньше шести, то есть если номер месяца 3,4 или 5 (март, апрель, май соответственно), то печатаем весна. И так далее для лета и осени.
Если вам не понятен пример со сравнениями, то можно писать, как раньше:
: CASE3 ( MONTH -> ) \ SEASON.
CASE
12 OF ." Зима" ENDOF
1 OF ." Зима" ENDOF
2 OF ." Зима" ENDOF
3 OF ." Весна" ENDOF
4 OF ." Весна" ENDOF
5 OF ." Весна" ENDOF
6 OF ." Лето" ENDOF
7 OF ." Лето" ENDOF
8 OF ." Лето" ENDOF
9 OF ." Осень" ENDOF
10 OF ." Осень" ENDOF
11 OF ." Осень" ENDOF
ENDCASE ;
Этот вариант хуже, из-за большого количества сравнений, он приведён исключительно для понимания. Освоившись, такой «говнокод» не пишите.
Для проверки работы этого примера напишем тест- слово (который в цикле перебирает параметр I от 1 включительно до 13 не включительно – это особенность работы цикла в SP-Forth, с работой которого мы познакомимся далее в соответствующей группе заданий, затем вызываем слово CASE3 для каждого случая и после выводов результата слово CR переводит курсор на новую строчку, чтобы данные были красиво структурированы):
: TEST-CASE3 13 1 DO I . I CASE3 CR LOOP ;
TEST-CASE3
1 Зима
2 Зима
3 Весна
4 Весна
5 Весна
6 Лето
7 Лето
8 Лето
9 Осень
10 Осень
11 Осень
12 Зима
Ok
Все варианты отрабатываются правильно.
В примере четыре, по номеру месяца определить количество дней для не високосного года.
: CASE4 ( MONTH -> ) \ N. – Количество дней в месяце
CASE
1 OF ." 31" ENDOF
2 OF ." 28" ENDOF
3 OF ." 31" ENDOF
4 OF ." 30" ENDOF
5 OF ." 31" ENDOF
6 OF ." 30" ENDOF
7 OF ." 31" ENDOF
8 OF ." 31" ENDOF
9 OF ." 30" ENDOF
10 OF ." 31" ENDOF
11 OF ." 30" ENDOF
12 OF ." 31" ENDOF
ENDCASE ;
Ничего нового здесь нет, перебираем все номера и печатаем соответствующее количество дней. Можно заменить вывод строк (типа <." 31">) на <31 .> (печать числа отправленного на стек), то есть:
: CASE4 ( MONTH -> ) \ N. – Количество дней в месяце
CASE
1 OF 31 ENDOF
2 OF 28 ENDOF
3 OF 31 ENDOF
4 OF 30 ENDOF
5 OF 31 ENDOF
6 OF 30 ENDOF
7 OF 31 ENDOF
8 OF 31 ENDOF
9 OF 30 ENDOF
10 OF 31 ENDOF
11 OF 30 ENDOF
12 OF 31 ENDOF
ENDCASE . ;
Проверим, написав тест-слово, на всех допустимых значениях (которое можно использовать для обоих вариантов):
: TEST-CASE4 13 1 DO I DUP . CASE4 CR LOOP ;
Итоговый вывод:
TEST-CASE4
1 31
2 28
3 31
4 30
5 31
6 30
7 31
8 31
9 30
10 31
11 30
12 31
Ok
В примере пять совершаем одно из четырех арифметических действия над двумя действительными числами, зашифрованные числами 1 – сложение, 2 – вычитание, 3 – умножение, 4 – деление. Разумеется, второе число нельзя вводить нулевым, чтобы не спровоцировать ошибку деления на ноль. Так как здесь мы работаем сразу с двумя стеками одновременно (целочисленным и вещественным), то в двух скобках описаны две стековые нотации, которые обозначены соответственно «I:» (Integer) и «F:» (Float).
: CASE5 ( I: N -> ) ( F: A B -> ) \ A[N]B. – результат работы, выводимый на экран, 1 1E 2E CASE5 – формат работы слова
CASE
1 OF F+ ENDOF
2 OF F- ENDOF
3 OF F* ENDOF
4 OF F/ ENDOF
ENDCASE F. ;
1 1E-1 2E-1 CASE5
0.3000000 Ok
2 1E-1 2E-1 CASE5
-0.1000000 Ok
3 1E-1 2E-1 CASE5
0.0200000 Ok
4 1E-1 2E-1 CASE5
0.5000000 Ok
Результат операций над данными вещественными числами верны, тест успешный.
Если просто, то в примере шесть длину отрезка в дециметрах (зашифрованное 1), километрах (2), метрах (3), миллиметрах (4) и сантиметрах (5) нужно перевести в метры. Достигается результат соответственно делением на 10, умножение на 1000, изменения не требуются, делением на 1000 и 100 соответственно. Кодируется все просто, единственное отличие от предыдущих задач этого блока, мы снова стали работать с вещественными числами.
: CASE6 ( I: N -> ) ( F: L -> ) \ Ln.
CASE
1 OF 10E F/ ENDOF
2 OF 1000E F* ENDOF
3 OF ENDOF
4 OF 1000E F/ ENDOF
5 OF 100E F/ ENDOF
ENDCASE F. ;
\ Тест CASE6
1 1234E-2 CASE6
1.2340000 Ok
2 1234E-2 CASE6
12340.000 Ok
3 1234E-2 CASE6
12.340000 Ok
4 1234E-2 CASE6
0.0123400 Ok
5 1234E-2 CASE6
0.1234000 Ok
Переводим 12.340000 и получаем 1.2340000, 12340.000, 12.340000, 0.0123400 и 0.1234000 соответственно.
Пример семь полностью аналогичен предыдущему и поэтому подробные объяснения опустим.
: CASE7 ( I: N -> ) ( F: M -> ) \ Mn.
CASE
1 OF ENDOF
2 OF 1000000E F/ ENDOF
3 OF 1000E F/ ENDOF
4 OF 1000E F* ENDOF
5 OF 100E F* ENDOF
ENDCASE F. ;
1 1234E-2 CASE7
12.340000 Ok
2 1234E-2 CASE7
0.0000123 Ok
3 1234E-2 CASE7
0.0123400 Ok
4 1234E-2 CASE7
12340.000 Ok
5 1234E-2 CASE7
1234.0000 Ok
В примере восемь определяем предыдущую дату, если дано D M (день и месяц не високосного года). Если день D > 1, то просто D уменьшаем на единицу и результат готов, иначе поменяется месяц, тогда нужно определить сколько дней в месяце, как в примере четыре. Во второй строке мы проверяем, чтобы месяц не стал равным нулю, тогда заменяем на декабрь, то есть пишем 12.
: CASE8 ( D M -> ) \ D2M2. - Предыдущая дата
OVER 1 >
IF SWAP 1- . . ELSE
1- DUP 0 = IF DROP 12 THEN DUP
CASE
1 OF ." 31 " ENDOF
2 OF ." 28 " ENDOF
3 OF ." 31 " ENDOF
4 OF ." 30 " ENDOF
5 OF ." 31 " ENDOF
6 OF ." 30 " ENDOF
7 OF ." 31 " ENDOF
8 OF ." 31 " ENDOF
9 OF ." 30 " ENDOF
10 OF ." 31 " ENDOF
11 OF ." 30 " ENDOF
12 OF ." 31 " ENDOF
ENDCASE . DROP
THEN ;
В тест-слове переберем все первые числа двенадцати месяцев, ибо в остальных случаях результат не так интересен, проверку произведите сами.
: TEST-CASE8 13 1 DO 1 DUP . I DUP . CASE8 CR LOOP ;
TEST-CASE8
1 1 31 12
1 2 31 1
1 3 28 2
1 4 31 3
1 5 30 4
1 6 31 5
1 7 30 6
1 8 31 7
1 9 31 8
1 10 30 9
1 11 31 10
1 12 30 11
Ok
Первые два числа исходная дата, а вторые два предыдущий день.
Пример девять. Отличается от примера восемь заменой предыдущего дня на следующий. Увеличиваем номер дня на единицу и сравниваем с количеством дней в месяце, если стал больше, то заменяем на первый день следующего месяца. Если номер месяца стал больше двенадцати, то заменяем на один (январь), иначе все в порядке ничего делать не надо просто печатаем результаты.
: CASE9 ( D M -> ) \ D2M2. - следующая дата
OVER 1+ OVER \ D M -> D M (D+1) M
CASE
1 OF 31 ENDOF \ D M (D+1) M -> D M (D+1) (Последний День Месяца)
2 OF 28 ENDOF
3 OF 31 ENDOF
4 OF 30 ENDOF
5 OF 31 ENDOF
6 OF 30 ENDOF
7 OF 31 ENDOF
8 OF 31 ENDOF
9 OF 30 ENDOF
10 OF 31 ENDOF
11 OF 30 ENDOF
12 OF 31 ENDOF
ENDCASE
> IF SWAP DROP 1+ 1 ELSE SWAP 1+ THEN
\ Если (D+1)>(Последний День Месяца), то
\ D M -> (M+1) 1 , иначе
\ D M -> M (D+1)
. DUP \ Печатаем День ,
12 > IF DROP 1 THEN . ; \ если месяц стал больше 12, то заменяем на 1
31 1 CASE9
1 2 Ok
28 2 CASE9
1 3 Ok
31 3 CASE9
1 4 Ok
30 4 CASE9
1 5 Ok
31 5 CASE9
1 6 Ok
30 6 CASE9
1 7 Ok
31 7 CASE9
1 8 Ok
31 8 CASE9
1 9 Ok
30 9 CASE9
1 10 Ok
31 10 CASE9
1 11 Ok
30 11 CASE9
1 12 Ok
31 12 CASE9
1 1 Ok
Выше приведены тесты, при смене месяца, в остальных случаях поэкспериментируйте самостоятельно.
Пример десять. Здесь мы управляем роботом, перемещающийся в четырёх направлениях (Север, Запад, Юг, Восток) и управляемый по трём командам «0» - вперёд, «1» - поворот налево, «-1» - поворот направо. По исходному направлению C и команде N определить направление робота после выполнения команды. Код получился с двумя вложенными друг в друга конструкциями «CASE». Во внешнем мы обрабатываем команду N, а во вложенном (внутреннем) направление «C».
: CASE10 ( N C -> ) \ C2. «N CASE10 C» - формат работы слова
CHAR SWAP \ переводим символ в код
CASE
0 OF EMIT ENDOF \ команда «0» не меняет направления
-1 OF \ команда «-1» меняет направление
CASE
78 OF 69 EMIT ENDOF \ N -> E
69 OF 83 EMIT ENDOF \ E -> S
83 OF 87 EMIT ENDOF \ S -> W
87 OF 78 EMIT ENDOF \ W -> N
ENDCASE
ENDOF
1 OF
CASE
78 OF 87 EMIT ENDOF \ N -> W
87 OF 83 EMIT ENDOF \ W -> S
83 OF 69 EMIT ENDOF \ S -> E
69 OF 78 EMIT ENDOF \ E -> N
ENDCASE
ENDOF
ENDCASE ;
Тест работы слова при команде «0» (не меняется направление):
0 CASE10 N
N Ok
0 CASE10 E
E Ok
0 CASE10 S
S Ok
0 CASE10 W
W Ok
При повороте на лево.
1 CASE10 N
W Ok
1 CASE10 W
S Ok
1 CASE10 S
E Ok
1 CASE10 E
N Ok
При повороте на право.
-1 CASE10 N
E Ok
-1 CASE10 W
N Ok
-1 CASE10 S
W Ok
-1 CASE10 E
S Ok
Улучшенный вариант
: CASE10 ( C N -> C2 ) ( N CASE10 C ) CHAR SWAP
CASE
0 OF ENDOF
1 OF
CASE
78 OF 87 ENDOF \ N -> W
69 OF 78 ENDOF \ E -> N
83 OF 69 ENDOF \ S -> E
87 OF 83 ENDOF \ W -> S
ENDCASE
ENDOF
-1 OF
CASE
78 OF 69 ENDOF \ N -> E
69 OF 83 ENDOF \ E -> S
83 OF 87 ENDOF \ S -> W
87 OF 78 ENDOF \ W -> N
ENDCASE
ENDOF
ENDCASE EMIT ;
Мы подчистили лишние повторения и получили чистый код (Вынеся «EMIT»).
Пример одиннадцать. В отличии от предыдущего примера добавлена еще одна команда, и «0» - продолжение движения вперёд, заменён поворотом на 180 градусов. Для решения этого примера сначала изменим пример десять, скорректировав команду «0» и обозначив через «COM» (сокращение от COMMAND).
: COM \ Переделанный CASE11
CASE
1 OF
CASE
78 OF 87 ENDOF \ N -> W
69 OF 78 ENDOF \ E -> N
83 OF 69 ENDOF \ S -> E
87 OF 83 ENDOF \ W -> S
ENDCASE
ENDOF
-1 OF
CASE
78 OF 69 ENDOF \ N -> E
69 OF 83 ENDOF \ E -> S
83 OF 87 ENDOF \ S -> W
87 OF 78 ENDOF \ W -> N
ENDCASE
ENDOF
2 OF
CASE
78 OF 83 ENDOF \ N -> S
69 OF 87 ENDOF \ E -> W
83 OF 78 ENDOF \ S -> N
87 OF 69 ENDOF \ W -> E
ENDCASE
ENDOF
ENDCASE ;
: CASE11 ( C N1 N2 -> ) \ C2. - N1 N2 CASE11 C - формат работы команды
CHAR
SWAP COM
SWAP COM
EMIT ;
Примеры тестов:
1 1 CASE11 N
S Ok
-1 -1 CASE11 N
S Ok
2 2 CASE11 N
N Ok
Пример двенадцать. Элементы окружности закодированы числами: 1 - радиус, 2 – диаметр, 3 – длина и 4 – площадь. По одному из них вычислить и вывести на экран остальные в том же порядке. Пи брать с точность до двух знаков после запятой. Для этого напишем 3 вспомогательных слова, вычисляющих диаметр, длину и площадь соответственно.
: D. ( R -> 2*R ) ." D=" 2E F* F. ; \ D=2*R
: L. ( R -> 2*3.14*R ) ." L=" 2E F* 3.14E F* F. ; \ L=2*PI*R
: S. ( R -> 3.14*R*R ) ." S=" FDUP F* 3.14E F* F. ; \ S=PI*R*R
Главное слово, решающую условие задачи, в зависимости от номера элемента выполняет соответствующий ему код.
: CASE12 ( I: N -> ) ( F: X -> ) \ {1,2,3,4} 10E CASE12 – формат работы слова
CASE
1 OF
FDUP FDUP \ DANO R - вспомогательные слова решают задачу
D. CR
L. CR
S. CR
ENDOF
2 OF
\ DANO D – вычисляем R, сводим задачу к предыдущему
." R=" 2E F/ FDUP FDUP F. CR
L. CR
S. CR
ENDOF
3 OF
\ DANO L – аналогично, вычисляем R через L
." R=" 2E 3.14E F* F/ FDUP FDUP F. CR
D. CR
S. CR
ENDOF
4 OF
\ DANO S - идентично, вычисляем R теперь через S
." R=" 3.14E F/ FSQRT FDUP FDUP F. CR
D. CR
L. CR
ENDOF
ENDCASE ;
В первом случае уже написаны все вспомогательные слова, в остальных сначала вычисляется радиус (через D во втором, через L в третьем и через S в четвертом случае), затем задача сводится к первому. И в конце парочка тестов.
1 10E CASE12
D=20.000000
L=62.800000
S=314.00000
Ok
2 10E CASE12
R=5.0000000
L=31.400000
S=78.500000
Ok
3 10E CASE12
R=1.5923567
D=3.1847134
S=7.9617834
Ok
4 10E CASE12
R=1.7845765
D=3.5691531
L=11.207141
Ok
Пример тринадцать. Полностью аналогична предыдущему, с такой же логикой работы. Напишем без дополнительных слов сразу код для каждого случая. Отличие только в формулах.
: CASE13 ( I: N -> ) ( F: X -> ) \ {1,2,3,4} 10E CASE13 – формат работы слова
CASE
1 OF
\ DANO A
." C=" 2E FSQRT F* FDUP F. CR ( C )
." H=" 2E F/ FDUP F. CR ( H )
." S=" FDUP F* F. CR
ENDOF
2 OF
\ DANO C
." A=" FDUP 2E FSQRT F/ F. CR ( C )
." H=" 2E F/ FDUP F. CR ( H )
." S=" FDUP F* F. CR
ENDOF
3 OF
\ DANO H
." A=" 2E F* FDUP 2E FSQRT F/ F. CR ( C )
." C=" FDUP F. CR ( C )
." S=" FDUP F* 4E F/ F. CR
ENDOF
4 OF
\ DANO S
." A=" FSQRT FDUP 2E F* FDUP 2E FSQRT F/ F. CR ( H C )
." C=" F. CR ( H )
." H=" F. CR
ENDOF
ENDCASE ;
Пример четырнадцать. Аналогичен примеру тринадцать, как и примеру двенадцать, также отличается только формулами.
: CASE14 ( I: N -> ) ( F: X -> ) \ {1,2,3,4} 10E CASE14 - формат работы слова
CASE
1 OF
\ DANO A
." R1=" FDUP 3E FSQRT F* 6E F/ FDUP F. CR ( A R1 )
." R2=" 2E F* F. CR ( A )
." S =" FDUP F* 3E FSQRT F* 4E F/ F. CR
ENDOF
2 OF
\ DANO R1
." A=" FDUP 6E F* 3E FSQRT F/ FDUP F. CR ( R1 A )
." R2=" FSWAP 2E F* F. CR ( A )
." S=" FDUP F* 3E FSQRT F* 4E F/ F. CR
ENDOF
3 OF
\ DANO R2
." A=" FDUP 3E FSQRT F* FDUP F. CR ( R2 A )
." R1=" FSWAP 2E F/ F. CR ( A )
." S=" FDUP F* 3E FSQRT F* 4E F/ F. CR
ENDOF
4 OF
\ DANO S
." A=" 4E F* 3E FSQRT F/ FSQRT FDUP F. CR ( A )
." R1=" 3E FSQRT F* 6E F/ FDUP F. CR ( R1 )
." R2=" 2E F* F. CR
ENDOF
ENDCASE ;
Пример пятнадцать довольно простой. Даны два номера: номер масти и номер карты. Вывести сообщение, описывающее название карты, например, «шестёрка пик».
: CASE15 ( 6<=N<=14 1<=M<=4 -> ) SWAP \ «Шестерка пик»
CASE
6 OF ." Шестерка " ENDOF
7 OF ." Семерка " ENDOF
8 OF ." Восьмерка " ENDOF
9 OF ." Девятка " ENDOF
10 OF ." Десятка " ENDOF
11 OF ." Валет " ENDOF
12 OF ." Дама " ENDOF
13 OF ." Король " ENDOF
14 OF ." Туз " ENDOF
." Ошибка карты "
ENDCASE
CASE
1 OF ." пик" ENDOF
2 OF ." треф" ENDOF
3 OF ." бубен" ENDOF
4 OF ." червей" ENDOF
." ошибка масти"
ENDCASE ;
Тест слово TEST-CASE15 проверяет все корректные варианты работы слова CASE15.
: TEST-CASE15 15 6 DO 5 1 DO J DUP . I DUP . CASE15 CR LOOP LOOP ;
В чем можно убедится запустив её.
TEST-CASE15
6 1 Шестерка пик
6 2 Шестерка треф
6 3 Шестерка бубен
6 4 Шестерка червей
7 1 Семерка пик
7 2 Семерка треф
7 3 Семерка бубен
7 4 Семерка червей
8 1 Восьмерка пик
8 2 Восьмерка треф
8 3 Восьмерка бубен
8 4 Восьмерка червей
9 1 Девятка пик
9 2 Девятка треф
9 3 Девятка бубен
9 4 Девятка червей
10 1 Десятка пик
10 2 Десятка треф
10 3 Десятка бубен
10 4 Десятка червей
11 1 Валет пик
11 2 Валет треф
11 3 Валет бубен
11 4 Валет червей
12 1 Дама пик
12 2 Дама треф
12 3 Дама бубен
12 4 Дама червей
13 1 Король пик
13 2 Король треф
13 3 Король бубен
13 4 Король червей
14 1 Туз пик
14 2 Туз треф
14 3 Туз бубен
14 4 Туз червей
Ok
Пример шестнадцать, предполагает небольшое знание русского языка. В целом логика работы также проста.
: CASE16 ( A-> )
10 /MOD \ A -> [A MOD 10] [A/10]
\ Сначала выводим десятки
CASE
2 OF ." Двадцать " ENDOF
3 OF ." Тридцать " ENDOF
4 OF ." Сорок " ENDOF
5 OF ." Пятьдесят " ENDOF
6 OF ." Шестьдесят " ENDOF
7 OF ." Семьдесят " ENDOF
." Ошибка ввода, нужно ввести возраст от 20 до 69 "
ENDCASE
\ затем единицы
CASE
0 OF ." Лет " ENDOF
1 OF ." один год" ENDOF
2 OF ." два года" ENDOF
3 OF ." три года" ENDOF
4 OF ." четыре года" ENDOF
5 OF ." пять лет" ENDOF
6 OF ." шесть лет" ENDOF
7 OF ." семь лет" ENDOF
8 OF ." восемь лет" ENDOF
9 OF ." девять лет" ENDOF
ENDCASE ;
Тест слово, проверяющее все варианты ввода, в указанном диапазоне:
: TEST-CASE16 70 20 DO I DUP . CASE16 CR LOOP ;
Тест слово выводит большой объем текста, который здесь не приводится, поэкспериментируйте самостоятельно.
Пример семнадцать. Как и в предыдущем делим исходное число на десятки и единицы, затем производим анализ. Сперва рассматриваем случай, когда один десяток («1 OF»), полный перебор с выходом. Затем отрабатываем десятки, и в конце единицы.
: CASE17 ( N[10-40] -> )
10 /MOD
CASE ( Десятки )
1 OF
CASE
0 OF ." Десять учебных заданий " ENDOF
1 OF ." Одиннадцать учебных заданий " ENDOF
2 OF ." Двенадцать учебных заданий " ENDOF
3 OF ." Тринадцать учебных заданий " ENDOF
4 OF ." Четырнадцать учебных заданий " ENDOF
5 OF ." Пятнадцать учебных заданий " ENDOF
6 OF ." Шестнадцать учебных заданий " ENDOF
7 OF ." Семнадцать учебных заданий " ENDOF
8 OF ." Восемнадцать учебных заданий " ENDOF
9 OF ." Девятнадцать учебных заданий " ENDOF
ENDCASE
EXIT
ENDOF
2 OF ." Двадцать " ENDOF
3 OF ." Тридцать " ENDOF
4 OF ." Сорок " ENDOF
ENDCASE
CASE
0 OF ." учебных заданий " ENDOF
1 OF ." одно учебное задание " ENDOF
2 OF ." два учебных задания " ENDOF
3 OF ." три учебных задания " ENDOF
4 OF ." четыре учебных задания " ENDOF
5 OF ." пять учебных заданий " ENDOF
6 OF ." шесть учебных заданий " ENDOF
7 OF ." семь учебных заданий " ENDOF
8 OF ." восемь учебных заданий " ENDOF
9 OF ." девять учебных заданий " ENDOF
ENDCASE ;
: TEST-CASE17 50 10 DO I DUP . CASE17 CR LOOP ;
Ошибки в грамматике (если таковые есть) надеюсь исправите самостоятельно. Логика работы программа не должна вызвать сложностей.
Пример восемнадцать. Для вывода чисел в диапазоне от 100 до 999, необходима сначала поделить на сто, получив частное, выводим количество сотен, остаток будет десятки с единицами, которые получим в отдельности снова поделив, уже на 10. Делим с помощью команды «/MOD», которая оставляет на стеке одновременно и остаток, и частное. В случае если ноль десятков, то ничего не печатаем (этот вариант можно пропустить и не рассматривать, здесь в коде он написан для целостности картины), отдельно рассматриваем число десятков равное единице, и в конце каждой выходим из слова. Далее ничего нового, перебираем остальные варианты десяток, и затем заканчиваем единицами.
: CASE18 ( A -> )
100 /MOD
CASE \ Сотни
1 OF ." Сто " ENDOF
2 OF ." Двести " ENDOF
3 OF ." Триста " ENDOF
4 OF ." Четыреста " ENDOF
5 OF ." Пятьсот " ENDOF
6 OF ." Шестьсот " ENDOF
7 OF ." Семьсот " ENDOF
8 OF ." Восемьсот " ENDOF
9 OF ." Девятьсот " ENDOF
ENDCASE
10 /MOD
CASE \ Десятки
0 OF ENDOF \ число десяток ноль, ничего не делаем (можно удалить его)
1 OF \ число десяток один, обрабатываем каждую в отдельности и завершаем
CASE
0 OF ." десять" EXIT ENDOF
1 OF ." одиннадцать" EXIT ENDOF
2 OF ." двенадцать" EXIT ENDOF
3 OF ." тринадцать" EXIT ENDOF
4 OF ." четырнадцать" EXIT ENDOF
5 OF ." пятнадцать" EXIT ENDOF
6 OF ." шестнадцать" EXIT ENDOF
7 OF ." семнадцать" EXIT ENDOF
8 OF ." восемнадцать" EXIT ENDOF
9 OF ." девятнадцать" EXIT ENDOF
ENDCASE
ENDOF
2 OF ." двадцать " ENDOF
3 OF ." тридцать " ENDOF
4 OF ." сорок " ENDOF
5 OF ." пятьдесят " ENDOF
6 OF ." шестьдесят " ENDOF
7 OF ." семьдесят " ENDOF
8 OF ." восемьдесят " ENDOF
9 OF ." девяносто " ENDOF
ENDCASE
CASE \ Единицы
1 OF ." один" ENDOF
2 OF ." два" ENDOF
3 OF ." три" ENDOF
4 OF ." четыре" ENDOF
5 OF ." пять" ENDOF
6 OF ." шесть" ENDOF
7 OF ." семь" ENDOF
8 OF ." восемь" ENDOF
9 OF ." девять" ENDOF
ENDCASE ;
Тест слово для вывода всех чисел в диапазоне от ста до Девятьсот девяносто девять. Надеюсь с грамматикой все в порядке, иначе не сложно исправить, ибо логика работы не должна вызвать сложности в работе.
: TEST-CASE18 1000 100 DO I CASE18 CR LOOP ;
Пример девятнадцать. Заметим, что цвета с животными будут сочетаться в двух вариантах (зеленой, зеленого, красной, красного …), для этого напишем два варианта слова вывода цвета - COLOR1, COLOR2. Поделим 1984 на 60, получим остаток 4. Прибавим к 1984 число 56, тогда поделив (1984+56)=2040 на 60 получим 34 ровно, без остатка. Код «60 MOD» выделяет шестидесятилетний цикл, а «12 /MOD» двенадцатилетний под цикл с цветом. Выполнив следующее «1984 56 + 60 MOD 12 /MOD SWAP», мы получим ( «0 0» ), то есть цвет ноль (зеленый), и животное 0 (крыса), так мы синхронизировали с календарем по году 1984 (год зеленой крысы). Далее дело техники просто обрабатываем все варианты двенадцати животных и пяти цветов.
: COLOR1 ( COLOR -> ) \ COLOR.
CASE
0 OF ." зеленой " ENDOF
1 OF ." красной " ENDOF
2 OF ." желтой " ENDOF
3 OF ." белой " ENDOF
4 OF ." черной " ENDOF
ENDCASE ;
: COLOR2 ( COLOR -> ) \ COLOR.
CASE
0 OF ." зеленого " ENDOF
1 OF ." красного " ENDOF
2 OF ." желтого " ENDOF
3 OF ." белого " ENDOF
4 OF ." черного " ENDOF
ENDCASE ;
: CASE19 ( Y -> )
\ 1984 - Год зеленой крысы
56 + 60 MOD 12 /MOD SWAP ( цвет животное )
." Год "
CASE ( животное )
0 OF COLOR1 ." крысы " ENDOF
1 OF COLOR1 ." коровы " ENDOF
2 OF COLOR2 ." тигра " ENDOF
3 OF COLOR2 ." зайца " ENDOF
4 OF COLOR2 ." дракона " ENDOF
5 OF COLOR1 ." змеи " ENDOF
6 OF COLOR1 ." лошади" ENDOF
7 OF COLOR1 ." овцы" ENDOF
8 OF COLOR1 ." обезьяны " ENDOF
9 OF COLOR1 ." курицы " ENDOF
10 OF COLOR1 ." собаки " ENDOF
11 OF COLOR1 ." свиньи " ENDOF
." Неправильная дата"
ENDCASE ;
: TEST-CASE19 2000 1983 DO I DUP . CASE19 CR LOOP ;
Пример двадцать. Месяц умножаем на сто и прибавляем день. Таким образом мы получаем шифровку дня и месяца в одном числе, смысл которого в том, что теперь мы можем сравнивать дату и месяц не по отдельности два раза, а одной операцией (упрощаем себе жизнь). Так все дни января будут от 101 до 131. Например, для козерога пограничная дата 19,01 – это, по-нашему, 119-ый день, и все даты до него (от 101 до 119) гарантированно меньше, чем 120 – первое значение в «CASE», в результате чего будет выведено «знак Зодиака - Козерог» для любого значения дня в этом диапазоне. Аналогично выглядят сравнения для остальных знаков. Последнее значение «1221 > uOF» для полной проверки Козерога, и замыкания всех возможных, корректно введенных, дат.
: CASE20 ( D M -> ZOD. )
100 * +
CASE
120 < uOF ." Козерог " ENDOF
219 < uOF ." Водолей " ENDOF
321 < uOF ." Рыбы " ENDOF
420 < uOF ." Овен " ENDOF
521 < uOF ." Телец " ENDOF
622 < uOF ." Близнецы " ENDOF
723 < uOF ." Рак " ENDOF
823 < uOF ." Лев " ENDOF
923 < uOF ." Дева " ENDOF
1023 < uOF ." Весы " ENDOF
1123 < uOF ." Скорпион " ENDOF
1222 < uOF ." Стрелец " ENDOF
1221 > uOF ." Козерог " ENDOF
ENDCASE ;
Тест слова показывает корректность ее работы на правильных датах.
1 1 CASE20
Козерог Ok
19 1 CASE20
Козерог Ok
20 1 CASE20
Водолей Ok
18 2 CASE20
Водолей Ok
19 2 CASE20
Рыбы Ok
20 3 CASE20
Рыбы Ok
21 3 CASE20
Овен Ok
19 4 CASE20
Овен Ok
20 4 CASE20
Телец Ok
20 5 CASE20
Телец Ok
21 5 CASE20
Близнецы Ok
21 6 CASE20
Близнецы Ok
22 6 CASE20
Рак Ok
22 7 CASE20
Рак Ok
23 7 CASE20
Лев Ok
22 8 CASE20
Лев Ok
23 8 CASE20
Дева Ok
22 9 CASE20
Дева Ok
23 9 CASE20
Весы Ok
22 10 CASE20
Весы Ok
23 10 CASE20
Скорпион Ok
22 11 CASE20
Скорпион Ok
23 11 CASE20
Стрелец Ok
21 12 CASE20
Стрелец Ok
22 12 CASE20
Козерог Ok
Так как мы не реализовали «защиту от дурака» и при вводе, например, даты 35 января, получим в результате:
35 1 CASE20
Водолей Ok