Работа с текстом в языке Ада. Решение тематических задач

Для решения задач этого раздела рекомендую предварительно ознакомится с материалами раздела "Работа с текстом в языке Ада". Краткая информация по теме "Работа с текстом" содержится на странице "Шпаргалка"

  • Написать программу, которая запрашивает имя пользователя и здоровается с ним.

  • Как тебя зовут? (Введите свои имя и фамилию, затем нажмите <Enter>): Иван Иванов
    Привет, Иван Иванов!
  • Так как решение этой задачи с использованием типа String мы рассмотрели в прошлом разделе, воспользуемся типом Unbounded_String

    with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Strings.Unbounded;
     
    procedure main is
        --Эта строка необязательна, но тогда почти перед каждым использованием name
        --(см. следующее объявление переменной) придётся писать Ada.Strings.Unbounded
        package ASU renames Ada.Strings.Unbounded;
        name : ASU.Unbounded_String; --Если бы не было предыдущей строки то объявление
                                     --выглядело бы так:
                                     --name : Ada.Strings.Unbounded.Unbounded_String
    begin
        Put("Как тебя зовут? (Введите свои имя и фамилию, затем нажмите <Enter>): ");
        --Ada.Text_IO.Get_Line считывает обычную строку, а затем происходит её преобразование
        --к типу Unbounded:
        name := ASU.To_Unbounded_String(Ada.Text_IO.Get_Line);
        --Перед выводом преобразовываем Unbounded к обычной строке:
        Put_Line("Привет, " & ASU.To_String(name) & "!");
    end main;


  • Написать программу, которая запрашивает у пользователя имя и отчество, затем здоровается с ним. Имя и отчество считываются в разные переменные.

  • Введите своё имя: Иван

    Введите свое отчество: Иванович

    Привет, Иван Иванович!

  • Решим задачу с учётом того, что пользователь может ввести строку длиннее, чем под неё выделяется позиций:

    with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Strings; use Ada.Strings;
     
    procedure main is
        name : String(1..10);       --Под имя выделяем 10 символов
        patronymic : String(1..12); --Под отчество выделяем 12 символов
        name_len : Integer;
        patronymic_len : Integer;
     
    begin
        Put("Введите своё имя: ");
        Get_Line(name, name_len);
        --Если имя пользователя больше 10 символов, то следующие 3 строки позволяют
        --отбросить остаток ввода и стереть его из буфера клавиатуры
        --Здесь name'Last равно 10 - количеству позиций, выделенных под строку:
        if name_len = name'Last then
            Skip_Line; --Отбросить остаток ввода
        end if;
     
        Put("Введите свое отчество: ");
        Get_Line(patronymic, patronymic_len);
        if patronymic_len = patronymic'Last then
            skip_line;
        end if;
     
        Put_Line("Привет, " & name(1..name_len) & " " & patronymic(1..patronymic_len) & "!");
    end main;


  • Напишите программу, которая выводит на экран сообщение в "телеграфном" стиле: буквы сообщения должны появляться по одной, с некоторой задержкой.

  • Для решения задачи я возьму Unbounded-Length Strings. Решение задачи с использованием обычных строк аналогично приведённому.

    with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Strings.Unbounded;
     
    procedure main is
        package ASU renames Ada.Strings.Unbounded;
        str : ASU.Unbounded_String;
    begin
        Put_Line("Введите строку:");
        --Считать строку. Вместо Ada.Text_IO.Get_line можно просто написать Get_Line
        str := ASU.To_Unbounded_String(Ada.Text_IO.Get_Line);
        for i in 1..ASU.Length(str) loop --Для вывода строки посимвольно воспользуемся циклом.
                                         --Функция ASU.Length(str) вычисляет длину строки str
            Put(ASU.To_String(str)(i));  --Посимвольный вывод: сначала преобразовываем
                                         --unbounded к обычной строке, а затем берём один символ
                                         --по индексу.
            delay 0.5; --Задержка вывода 0,5 сек.
        end loop;
    end main;


  • Напишите программу, которая выводит код введенного пользователем символа. Программа должна завершать работу в результате ввода, например, точки.

  • Введите символ и нажмите <Enter>.
    Для завершения введите точку.
    -> 1
    Символ: 1 Код: 49
    -> 2
    48
    Символ: 2 Код: 50
    -> ы
    Символ: ы Код: 235
    ->.
  • with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
     
    procedure main is
        ch : Character;
    begin
        Put_Line("Введите символ и нажмите <Enter>");
        loop
            Put("-> ");
            Get(ch);
            exit when ch = '.';
                Put("Символ " & ch & " Код:" & Integer'image(Character'Pos(ch)));
                --Атрибут Character'Pos(ch) возвращает код символа.
                --Обратное ему действие даёт атрибут Val 
            New_Line;
        end loop;
    end main;


  • Написать программу, показывающую "стоимость" карты из колоды. Цифровые карты (от 2 до 10) имеют "стоимость", эквивалентную названию, т.е. от 2 до 10. A (туз) - 11, K, Q, J (Король, Дама, Валет) - 10. Пользователь вводит карту, программа выводит стоимость карты.

  • Введите карту: А
    Стоимость карты: 11
  • with    Ada.Text_IO,
            Ada.Characters.Handling; --Чтобы работать с функциями символьного типа
     
    procedure main is
        bufer : String(1..2); --Сюда будет считываться карта
        bufer_Len : Integer;  --Сколько символов прочитано
        val : Integer;        --Стоимость карты
    begin
        Ada.Text_IO.Put("Введите карту: ");
        Ada.Text_IO.Get_Line(bufer, bufer_len); --Считать карту
     
        --Если карта - число, то
        if Ada.Characters.Handling.Is_Digit(bufer(1)) then
            --Преобразовать название карты в цифровой эквивалент
            val := Integer'Value(bufer(1..bufer_Len));
        else
            --Если карта - A, K, Q, J, то приводим название к верхнему регистру (если нужно)
            bufer(1) := Ada.Characters.Handling.To_Upper(bufer(1));
            --Код символа ('Pos), т.к. case работает с числовым типом:
            case Character'Pos(bufer(1)) is
                when Character'Pos('A') => val := 11;
                when Character'Pos('Q') | Character'Pos('J') | Character'Pos('K') => val := 10;
                when others => val := 0;
            end case;
        end if;
     
        Ada.Text_IO.Put("Стоимость карты " & Integer'Image(val));
    end main;


  • Написать программу, которая вычисляет среднюю (за неделю) температуру воздуха. Исходные данные должны вводиться во время работы программы.

  • Введите температуру воздуха за неделю.
    Понедельник -> 12
    Вторник -> 10
    Среда -> 16
    Четверг -> 18
    Пятница -> 17
    Суббота -> 16
    Воскресенье -> 14
    Средняя температура за неделю: 14.71 град.
  • with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Float_Text_IO; use Ada.Float_Text_IO;
    with Ada.Strings.Unbounded; --Будут использованы строки неопределённой длины.
     
    procedure main is
        package UStr renames Ada.Strings.Unbounded; --Сокращаем название пакета для удобства
        N : constant Integer := 7;
        j : Integer;
     
        type Vector is array(1..N) of Float;
        temp : Vector;
        --Массив строк неопределённой длины:
        type Week is array(1..N) of UStr.Unbounded_String;
        weekday : Week;
     
        mid : Float := 0.0;
    begin
        --Заполняем массив, применяя к каждой строке преобразование:
        weekday := (Ustr.To_Unbounded_String("Понедельник"),
                    Ustr.To_Unbounded_String("Вторник"),
                    Ustr.To_Unbounded_String("Среда"),
                    Ustr.To_Unbounded_String("Четверг"),
                    Ustr.To_Unbounded_String("Пятница"),
                    Ustr.To_Unbounded_String("Суббота"),
                    Ustr.To_Unbounded_String("Воскресенье"));
        Put_Line("Введите температуру воздуха за неделю:");
        j := 1;
        for i in temp'First..temp'Last loop
            --Вывод строк (с предварительным преобразованием)
            Put(Ustr.To_String(weekday(j)) & " -> ");
            --Put(" -> ");
            Get(temp(i));
            j := j + 1;
        end loop;
     
        for i in temp'First..temp'Last loop
            mid := mid + temp(i);
        end loop;
        mid := mid / Float(N);
        Put("Средняя температура за неделю ");
        Put(Item => mid, Fore => 1, Aft => 2, Exp => 0);
         Put_Line(" град.");
    end main;


  • Написать программу, реализующую игру "угадай число". Правила игры следующие. Играют двое. Один задумывает число, второй — угадывает. На каждом шаге угадывающий делает предположение, а задумавший число — говорит, сколько цифр числа угаданы и сколько из угаданных цифр занимают правильные позиции в числе. Например, если задумано число 725 и выдвинуто предположение, что задумано число 523, то угаданы две цифры (5 и 2) и одна из них (2) занимает верную позицию.

  • Компьютер задумал трехзначное число. Вы должны его отгадать. После очередного числа вам будет сообщено, сколько цифр угадано и сколько из них находятся на своих местах.
    Для завершения игры нажмите <Esc>.
    Ваш вариант -> 123 Угадано: 0. На своих местах: 0
    Ваш вариант -> 456 Угадано: 1. На своих местах: 0
    Ваш вариант -> 654 Угадано: 2. На своих местах: 2
    Ваш вариант -> 657 Угадано: 2. На своих местах: 2
    Ваш вариант -> 658 Угадано: 3. На своих местах: 3
    *** ВЫ УГАДАЛИ! ***

  • with Ada.Text_IO; use Ada.Text_IO;
    --Будем использовать генератор случайных чисел (для целых)
    with Ada.Numerics.Discrete_Random;
    with Ada.Strings; use Ada.Strings;
     
    procedure main is
        type Plan_Number is new Integer range 100..999; --Будем генерировать трёхзначное число
        --Дженерик (создаем пакет для генерации переменной нашего типа Plan_Number):
        package ANDR is new Ada.Numerics.Discrete_Random(Plan_Number);
        --Тип для хранения загаданного и угадываемого чисел
        type Number is array(1..3) of Positive;
     
        g : ANDR.generator; --Генератор
        num : Plan_Number := 100; --Здесь будет храниться результат генерации
        etalon : String(1..3) := (others => '0'); --Здесь хранится загаданное число.
        --Этот массив тоже хранит загаданное число, но его можно преобразовывать, т.е.
        --нужен для текущих операций:
        tmp_etalon : String(1..3);
        user_input : String(1..3); --Сюда сохраняется пользовательский ввод
        --Эти переменные нужны для проверки корректности ввода (если, например,
        --пользователь вводит буквы):
        succ, is_number : Boolean := false;
        --Сколько цифр угадано и сколько из них находятся на корректных позициях
        find, on_position : Integer range 0..3;
        ch : Character; --Сюда посимвольно считывается пользовательский ввод
     
    begin
        Put("Компьютер задумал трехзначное число. Вы должны его отгадать. После очередного ");
        Put("числа вам будет сообщено, сколько цифр угадано и сколько из них находятся на ");
        Put_Line("своих местах.");
        Put_Line("Для завершения игры нажмите <Esc>.");
        ANDR.reset(g);         --Запуск генератора случайных чисел
        num := ANDR.random(g); --Непосредственно генерация числа
        --Сохраняем загаданное число в строке. Индекс 2..4, т.к. под индексом 1 стоит пробел
        etalon(1..3) := Integer'Image(Integer(num))(2..4);
     
        --Следующие 4 строки - вывод загаданного числа (подсказка для проверки)
        --for i in etalon'First..etalon'Last loop
        --    Put(etalon(i));
        --end loop;
        --New_Line;
     
        --<Основной цикл: будет повторяться, пока не угадано число или не нажата клавиша ESC>
        Main_Loop: loop        
            --<Get_Number - цикл ввода пользователем числа>
            Get_Number: loop
                Put("Ваш вариант -> ");
                for i in user_input'First..user_input'Last loop
                    --Ввод делаем посимвольный и небуферизованный, т.к. нужно обработать выход
                    --по ESC и нажатие пользователем "ненужных" клавиш:
                    Get_Immediate(ch);
                    --К сведению: функция Get_Immediate() работает корректно как в терминале
                    --Windows, так и Linux (у С/С++ с этим проблемы)
                    --Обрабатываем нажатие ESC
                    if Character'Pos(ch) = 27 then
                        exit Main_Loop; --Выход из основного цикла
                    --Обрабатываем корректный ввод (Выставляем признак, что ввод корректный)
                    elsif ch >= '0' and ch <= '9' then
                        Put(ch);
                        is_number := True;
                    --Обрабатываем некорректный ввод
                    else
                        is_number := False;
                        exit;
                    end if;
                    --Запоминаем символ (цифру), если ввод был корректным
                    user_input(i) := ch;
                end loop;
     
                if user_input(1) = '0' then
                    Put_Line("Число не может начинаться с 0! Попробуйте ещё!");
                elsif not is_number then
                    Put_Line(" Некорректный ввод! Попробуйте ещё!");
                else
                    exit;
                end if;
            end loop Get_Number;
            --</Get_Number - цикл ввода пользователем числа>
     
            --<Проверка, сколько из введённых пользователем чисел есть в загаданном числе>
            find := 0;
            tmp_etalon := etalon;
            for i in etalon'First..etalon'Last loop
                for j in user_input'First..user_input'Last loop
                    if user_input(j) = etalon(i) then
                        if user_input(j) = tmp_etalon(i) then
                            find := find + 1;
                            --Помечаем во временной строке, что текущую цифру мы уже
                            --посчитали (на случай, если во введённом числе есть ещё
                            --такая же цифра):
                            tmp_etalon(i) := 'a';
                        end if;
                    end if;
                end loop;
            end loop;
            --</Проверка, сколько из введённых пользователем чисел есть в загаданном числе>
     
            --<Проверка, сколько из введённых пользователем чисел стоят на своих позициях
            --(позиции угаданы)>:
            on_position := 0;
            for i in etalon'First..etalon'Last loop
                if etalon(i) = user_input(i) then
                    on_position := on_position + 1;
                end if;
            end loop;
            --</Проверка, сколько из введённых пользователем чисел стоят на своих позициях
            --(позиции угаданы)>
     
            --<Вывод результата>
            Put_Line(" Угадано:" & Integer'image(find) & ". На своих местах:" & Integer'Image(on_position) & ".");
            if find = etalon'Last and then on_position = etalon'Last then
                Put_Line("*** ВЫ УГАДАЛИ! ***");
                succ := True; --Устанавливаем признак выхода из основного цикла
            end if;
            --</Вывод результата>
     
            exit when succ; --Выход из основного цикла
        end loop Main_Loop;
        --</Основной цикл: будет повторяться, пока не угадано число или не нажата клавиша ESC>
    end main;


2 comments on “Работа с текстом в языке Ада. Решение тематических задач

  1. Отличная статья! Много полезного для себя подчерпнула!
    Да и вообще, adacode.ru - очень хороший сайт!
    Спасибо Вам и хорошего всем настроения!
    картинка для настроения

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *