knightL

BucketProblem

Apr 23rd, 2022 (edited)
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.42 KB | None | 0 0
  1. #include <cstdlib>
  2. #include <gtk/gtk.h>
  3. #include <string>
  4.  
  5. using namespace std;
  6.  
  7. /* Надписи, в которых мы будем отображать текст */
  8. GtkWidget *labelVolume1, *labelVolume2, *label1, *label2, *labelDisplay1, *labelDisplay2;
  9.  
  10. /* Максимальная ёмкость сосудов с жидкостью */
  11. const int MAX_VOLUME_1 = 10;
  12. const int MAX_VOLUME_2 = 23;
  13.  
  14. /* Текущая ёмкость сосудов с жидкостью*/
  15. int v1 = 0;
  16. int v2 = 0;
  17.  
  18. /* Обновить надписи в соответствии с текущей ёмкостью*/
  19. void updateLabels()
  20. {
  21.     /* Буффер, в котором будем формировать строку для надписи */
  22.     char buf[30];
  23.     /* Формируем строку с объёмом первого сосуда в виде v1/MAX_VOLUME_1 */
  24.     sprintf(buf, "%d/%d", v1, MAX_VOLUME_1);
  25.     gtk_label_set_label(GTK_LABEL(labelVolume1), buf);
  26.    
  27.     /* Формируем строку с объёмом первого сосуда в виде v2/MAX_VOLUME_2 */
  28.     sprintf(buf, "%d/%d", v2, MAX_VOLUME_2);
  29.     gtk_label_set_label(GTK_LABEL(labelVolume2), buf);
  30.    
  31.     /* Формируем визуальное отображение первого сосуда */
  32.     /* Тег <tt> делает так, что каждая буква занимает одинаковую ширину */
  33.     /* Тег <span> используем, чтобы покрасить занятую часть в синий цвет */
  34.     string s1 = "<tt>[<span bgcolor='blue'>";
  35.     /* Добавляем вертикальные палочки по количеству жидкости в сосуде */
  36.     for(int i=0;i<v1;i++)
  37.         s1 += '|';
  38.     /* закрываем тег с синим фоном */
  39.     s1 += "</span>";
  40.     /* незанятую часть заполняем символом точка */
  41.     for(int i=v1;i<MAX_VOLUME_1;i++)
  42.         s1 += '.';
  43.     /* закрываем тег <tt> */
  44.     s1 += "]</tt>";
  45.    
  46.     /* Устанавливаем содержимое надписи, указав, что в строке используется язык разметки */
  47.     /* Поскольку s1 это строка, а на вход нужен массив символов, вызываем метод c_str(), чтобы его получить*/
  48.     gtk_label_set_markup(GTK_LABEL(labelDisplay1), s1.c_str());
  49.    
  50.     /* Аналогично форматируем строку для второго сосуда */
  51.     string s2 = "<tt>[<span bgcolor='blue'>";
  52.     for(int i=0;i<v2;i++)
  53.         s2 += '|';
  54.     s2 += "</span>";
  55.     for(int i=v2;i<MAX_VOLUME_2;i++)
  56.         s2 += '.';
  57.     s2 += "]</tt>";
  58.    
  59.     gtk_label_set_markup(GTK_LABEL(labelDisplay2), s2.c_str());
  60.    
  61. }
  62.  
  63. /* Функция, которая обрабатывает нажатие на кнопку "Наполнить 1"*/
  64. void fill1()
  65. {
  66.     /* Заполняем ёмкость 1 до максимального объёма */
  67.     v1 = MAX_VOLUME_1;
  68.    
  69.     /* Обновляем надписи в окне*/
  70.     updateLabels();
  71. }
  72.  
  73. /* Функция, которая обрабатывает нажатие на кнопку "Наполнить 2"*/
  74. void fill2()
  75. {
  76.     /* Заполняем ёмкость 2 до максимального объёма */
  77.     v2 = MAX_VOLUME_2;
  78.    
  79.     /* Обновляем надписи в окне */
  80.     updateLabels();
  81. }
  82.  
  83. /* Функция, которая обрабатывает нажатие на кнопку "Вылить из 1"*/
  84. void empty1()
  85. {
  86.     /* Обнуляем ёмкость 1 */
  87.     v1 = 0;
  88.    
  89.     /* Обновляем надписи в окне */
  90.     updateLabels();
  91. }
  92.  
  93. /* Функция, которая обрабатывает нажатие на кнопку "Вылить из 2"*/
  94. void empty2()
  95. {
  96.     /* Обнуляем ёмкость 1 */
  97.     v2 = 0;
  98.    
  99.     /* Обновляем надписи в окне */
  100.     updateLabels();
  101. }
  102.  
  103. /* Функция, которая обрабатывает нажатие на кнопку "Перелить из 1 в 2"*/
  104. void move1to2()
  105. {
  106.     /* v1 -> v2 */
  107.    
  108.     /* Если v1 целиком поместится в незанятой ёмкости v2*/
  109.     if ( v1 <= MAX_VOLUME_2 - v2 )
  110.     {
  111.         /* переливаем v1 целиком и обнуляем*/
  112.         v2 += v1;
  113.         v1 = 0;
  114.     }
  115.     else
  116.     {
  117.         /* иначе переливаем из v1 столько, сколько в v2 было незанято */
  118.         v1 -= MAX_VOLUME_2 - v2;
  119.         v2 = MAX_VOLUME_2;
  120.     }
  121.    
  122.     /* Обновляем надписи в окне */
  123.     updateLabels();
  124. }
  125.  
  126. /* Функция, которая обрабатывает нажатие на кнопку "Перелить из 2 в 1"*/
  127. void move2to1()
  128. {
  129.     /* v2 -> v1 */
  130.    
  131.     /* Если v1 целиком поместится в незанятой ёмкости v2*/
  132.     if ( v2 <= MAX_VOLUME_1 - v1 )
  133.     {
  134.         /* переливаем v2 целиком и обнуляем*/
  135.         v1 += v2;
  136.         v2 = 0;
  137.     }
  138.     else
  139.     {
  140.         /* иначе переливаем из v2 столько, сколько в v1 было незанято */
  141.         v2 -= MAX_VOLUME_1 - v1;
  142.         /* v1 теперь целиком занят */
  143.         v1 = MAX_VOLUME_1;
  144.     }
  145.    
  146.     /* Обновляем надписи в окне */
  147.     updateLabels();
  148. }
  149.  
  150. /*
  151.  *
  152.  */
  153. int main(int argc, char** argv) {
  154.  
  155.     gtk_init(&argc, &argv);
  156.    
  157.     GtkWidget *window, *vbox, *grid1, *grid2;
  158.     GtkWidget *buttonFill1, *buttonFill2, *buttonEmpty1, *buttonEmpty2, *buttonMove12, *buttonMove21, *exitButton;
  159.    
  160.     /* Создаём окно */
  161.     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  162.     /* Контейнер для вертикального выравнивания компонент окна */
  163.     vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
  164.     /* Контейнер-таблица для надписей */
  165.     grid1 = gtk_grid_new();
  166.     /* Контейнер-таблица для кнопок */
  167.     grid2 = gtk_grid_new();
  168.    
  169.     /* Создаём надписи с номерами ёмкостей*/
  170.     label1 = gtk_label_new("1:");
  171.     label2 = gtk_label_new("2:");
  172.     /* Создаём надписи с текстом о текущем заполнении. Они будут заполнены после вызова updateLabels() */
  173.     labelVolume1 = gtk_label_new("");
  174.     labelVolume2 = gtk_label_new("");
  175.     /* Создаём надписи с визуальным представлением текущего заполнения. Они будут заполнены после вызова updateLabels() */
  176.     labelDisplay1 = gtk_label_new("");
  177.     labelDisplay2 = gtk_label_new("");
  178.    
  179.     /* Создаём кнопки с управлением  */
  180.     buttonFill1 = gtk_button_new_with_label("Наполнить 1");
  181.     buttonFill2 = gtk_button_new_with_label("Наполнить 2");
  182.     buttonEmpty1 = gtk_button_new_with_label("Вылить из 1");
  183.     buttonEmpty2 = gtk_button_new_with_label("Вылить из 2");
  184.     buttonMove12= gtk_button_new_with_label("Перелить из 1 в 2");
  185.     buttonMove21 = gtk_button_new_with_label("Перелить из 2 в 1");
  186.     exitButton = gtk_button_new_with_label("Выход");
  187.    
  188.     /* Размещаем объекты */
  189.     /* Размещаем vbox, чтобы вертикально выстроить все дочерние объекты */
  190.     gtk_container_add(GTK_CONTAINER(window), vbox);
  191.     /* Размещаем в нём сетку с надписями, сетку с кнопками управления и кнопку выход */
  192.     gtk_box_pack_start(GTK_BOX(vbox), grid1, false, false, 1);
  193.     gtk_box_pack_start(GTK_BOX(vbox), grid2, false, false, 1);
  194.     gtk_box_pack_end(GTK_BOX(vbox), exitButton, false, false, 1);
  195.    
  196.     /* Размещаем надписи в сетке grid1 */
  197.     /*        label1 | label2
  198.      * -----------------------------
  199.      * labelDisplay1 | labelDisplay2
  200.      * -----------------------------
  201.      *  labelVolume1 | labelVolume2
  202.      */
  203.     gtk_grid_attach(GTK_GRID(grid1), label1, 0, 0, 1, 1);
  204.     gtk_grid_attach(GTK_GRID(grid1), labelDisplay1, 0, 1, 1, 1);
  205.     gtk_grid_attach(GTK_GRID(grid1), labelVolume1, 0, 2, 1, 1);
  206.     gtk_grid_attach(GTK_GRID(grid1), label2, 1, 0, 1, 1);
  207.     gtk_grid_attach(GTK_GRID(grid1), labelDisplay2, 1, 1, 1, 1);
  208.     gtk_grid_attach(GTK_GRID(grid1), labelVolume2, 1, 2, 1, 1);
  209.    
  210.     /* Размещаем кнопки в сетке grid2 */
  211.     /*  buttonFill1 | buttonFill2
  212.      * -----------------------------
  213.      * buttonEmpty1 | buttonEmpty2
  214.      * -----------------------------
  215.      * buttonMove12 | buttonMove21
  216.      */
  217.     gtk_grid_attach(GTK_GRID(grid2), buttonFill1, 0, 0, 1, 1);
  218.     gtk_grid_attach(GTK_GRID(grid2), buttonEmpty1, 0, 1, 1, 1);
  219.     gtk_grid_attach(GTK_GRID(grid2), buttonFill2, 1, 0, 1, 1);
  220.     gtk_grid_attach(GTK_GRID(grid2), buttonEmpty2, 1, 1, 1, 1);
  221.     gtk_grid_attach(GTK_GRID(grid2), buttonMove12, 0, 2, 1, 1);
  222.     gtk_grid_attach(GTK_GRID(grid2), buttonMove21, 1, 2, 1, 1);
  223.    
  224.     /* Добавляем между колонками отступ в 3 пикселя */
  225.     gtk_grid_set_column_spacing(GTK_GRID(grid1), 3);
  226.    
  227.     /* Добавляем выравнивание сеток по середине окна по горизонтали*/
  228.     gtk_widget_set_halign(grid1, GTK_ALIGN_CENTER);
  229.     gtk_widget_set_halign(grid2, GTK_ALIGN_CENTER);
  230.    
  231.     /* Поворачиваем надписи с уровнем жидкости на 90 градусов */
  232.     gtk_label_set_angle(GTK_LABEL(labelDisplay1), 90);
  233.     gtk_label_set_angle(GTK_LABEL(labelDisplay2), 90);
  234.     /* Выравниваем надписи так, чтобы они прилегали к нижней границе */
  235.     gtk_widget_set_valign(labelDisplay1, GTK_ALIGN_END);
  236.     gtk_widget_set_valign(labelDisplay2, GTK_ALIGN_END);
  237.    
  238.     /* Заполняем содержимое надписей в окне */
  239.     updateLabels();
  240.    
  241.     /* Отображаем окно*/
  242.     gtk_widget_show_all(window);
  243.    
  244.     /* Добавляем функции для обработки нажатия на кнопки управления */
  245.     g_signal_connect(G_OBJECT(buttonFill1), "clicked", (GCallback)fill1, NULL);
  246.     g_signal_connect(G_OBJECT(buttonFill2), "clicked", (GCallback)fill2, NULL);
  247.    
  248.     g_signal_connect(G_OBJECT(buttonEmpty1), "clicked", (GCallback)empty1, NULL);
  249.     g_signal_connect(G_OBJECT(buttonEmpty2), "clicked", (GCallback)empty2, NULL);
  250.    
  251.     g_signal_connect(G_OBJECT(buttonMove12), "clicked", (GCallback)move1to2, NULL);
  252.     g_signal_connect(G_OBJECT(buttonMove21), "clicked", (GCallback)move2to1, NULL);
  253.    
  254.     /* Указываем, что при нажатии кнопки выход и уничтожении окна необходимо прервать цикл обработки событий с помощью gtk_main_quit */
  255.     g_signal_connect(G_OBJECT(exitButton), "clicked", (GCallback)gtk_main_quit, NULL);
  256.     g_signal_connect(G_OBJECT(window), "destroy", (GCallback)gtk_main_quit, NULL);
  257.    
  258.     /* Запускаем цикл обработки событий */
  259.     gtk_main();
  260.    
  261.     return 0;
  262. }
  263.  
  264.  
Add Comment
Please, Sign In to add comment