6. Логические выражения
Занятие 8. Логика: И, ИЛИ, НЕ — и Задание 2
Цель занятия: обучающиеся вычисляют логические выражения через таблицу истинности и сдают Задание 2.
Разминка-вспоминание (5 мин)
- Как определить чётность отрицательного числа надёжно?
- Первое действие с датчиком освещённости на новом месте? (интервальный возврат: занятие 3)
- Какие варианты пар карточек разыгрываются жеребьёвкой в Задании 2?
Разбор (worked example): полное решение Задания 2 регламента — 30 баллов
Условие (Приложение 1). Датчик вертикально, 0,5–1 см над столом. Жеребьёвка задаёт пару карточек (Ч-Ч, Ч-Б, Б-Ч, Б-Б); белая = 1, чёрная = 0. По команде судьи: ввести карточкой A, по кнопке вывести (5 б.); ввести карточкой B, по кнопке вывести (5 б.); по кнопке вывести значение (B И A) ИЛИ НЕ A (5 б.). Две проверки с разными парами, между ними перезапуск разрешён. Итого 30.
Сначала — таблица истинности на бумаге
| A | B | B И A | НЕ A | (B И A) ИЛИ НЕ A |
|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 0 | 1 |
Проверка себя алгеброй: (B∧A)∨¬A = B∨¬A — выражение ложно только при A=1, B=0. Таблица, посчитанная до сдачи, — ваш контроль судейского результата: услышали вариант жеребьёвки — уже знаете ответ.
Эталонный код (C++, ESP32)
#include "stend.h"
#include <algorithm>
int reflMedian(int n = 5) {
int v[9];
for (int i = 0; i < n; i++) v[i] = reflection();
std::sort(v, v + n);
return v[n / 2];
}
void waitPress(Btn b = BTN_R) { // ждать нажатие И отпускание — иначе одно нажатие сработает дважды
while (!pressed(b)) delay(10);
while (pressed(b)) delay(10);
}
void show(int v) {
Serial.println(v);
screen(String(v));
}
int readCard(int porog, const char* imya) {
Serial.printf("Карточка %s → правая кнопка\n", imya);
waitPress();
int v = reflMedian() > porog ? 1 : 0;
show(v); // вывод введённого значения = 5 баллов
return v;
}
void setup() {
Serial.begin(115200);
stendBegin();
// Калибровка на месте (левая кнопка подтверждает каждую карточку)
Serial.println("Калибровка: белая → левая кнопка"); waitPress(BTN_L);
int w = reflMedian();
Serial.println("Калибровка: чёрная → левая кнопка"); waitPress(BTN_L);
int b = reflMedian();
int porog = (w + b) / 2;
Serial.printf("POROG = %d\n", porog);
int a = readCard(porog, "A"); // 5 баллов
int bb = readCard(porog, "B"); // 5 баллов
waitPress();
bool rez = (bb && a) || !a; // (B И A) ИЛИ НЕ A
show(rez ? 1 : 0); // 5 баллов; формат 0/1 — как вводили
}
void loop() {}Разбор: калибровка на левой кнопке, ввод на правой — судья видит две разные процедуры и не путает их; bb вместо b — имя b уже занято чёрным калибровочным значением (классический баг «переменная перезаписана»); в C++ выражение (bb && a) || !a даёт bool — выводим явно 0 или 1, чтобы формат совпал с форматом ввода; вторая проверка — просто перезапуск программы, это разрешено условием.
Практика
Прогнать все 4 варианта жеребьёвки
Партнёр-судья разыгрывает Ч-Ч, Ч-Б, Б-Ч, Б-Б; результат сверяется с таблицей истинности. 4 из 4.
Контрольная точка: сдача Задания 2
Наставник-судья, две проверки с разными парами, полный протокол. Цель — 30/30.
Чужое выражение
Партнёр придумывает выражение из А, В, И, ИЛИ, НЕ (пример компетенции 6.1: (А ИЛИ В) И НЕ А). Таблица на бумаге → правка одной строки кода → прогон 4 вариантов.
Типичные ошибки.
- Переменная калибровки перезаписала переменную ввода (
b) — результат «случайно» верен в части вариантов и незаметен без полного прогона 4 комбинаций. - Вывод
Trueпри вводе0/1— судья вправе спросить соответствие; держите один формат от ввода до результата. - Кодирование выражения «на слух» без таблицы — при A=0 ошибку не видно (ответ 1 в обеих строках), она всплывает только на A=1, B=0.
- Пропущенная калибровка на месте сдачи — свет зала другой, оба ввода читаются как 1.
Мини-проверка выхода
Задание 2 сдано на 30/30; блиц: «при каком единственном наборе (A, B) выражение дня ложно и почему?»