PascalABC.NET официальный канал
الذهاب إلى القناة على Telegram
Официальный канал языка и системы программирования PascalABC.NET
إظهار المزيد1 860
المشتركون
-424 ساعات
-97 أيام
-2530 أيام
أرشيف المشاركات
Почему PascalABC.NET лучше C#
Заголовок конечно провокационный. Но действительно - C# при всех огромных ресурсах на его разработку содержит дыры в безопасности.
В теории типов хорошо известен факт: если тип String является подтипом object, то тип "массив string" не должен быть подтипом "массив object"
Язык C# это нарушает. Проблема, которая при этом возникает - на скрине. Программа падает в невинном коде неожиданно в рантайме.
PascalABC.NET отслеживает эту хорошо известную ошибку на этапе компиляции.
#типы
Новый метод
AdjacentGroupBy для последовательностей
Теперь в PascalABC.NET появился метод AdjacentGroupBy, который группирует подряд идущие элементы последовательности по ключу (автор - Сергей Латченко).
В отличие от обычного GroupBy, который собирает все элементы с одинаковым ключом, AdjacentGroupBy сохраняет порядок и делит на группы при смене значения.
Пример
type
ActionData = auto class
Action: string;
Page: string
end;
begin
var actions := [
new ActionData('Клик', 'Главная'),
new ActionData('Клик', 'Каталог'),
new ActionData('Клик', 'Корзина'),
new ActionData('Прокрутка', 'Каталог'),
new ActionData('Прокрутка', 'Оформление заказа'),
new ActionData('Клик', 'Оформление заказа')
];
foreach var g in actions.AdjacentGroupBy(x -> x.Action) do
begin
Println($'Действие = {g.Key}');
g.PrintLines(a -> ' ' + a.Page);
end;
end.
📌 В этом примере элементы разбиваются на группы подряд идущих одинаковых действий ('Клик', 'Прокрутка', 'Клик').
Полезно, если нужно анализировать поведение пользователей, логи или последовательности событий.
#новоеSPython - map, filter, sorted
Стандартные функции Питона реализованы в SPython на PascalABC.NET.
Тем, кому нравится писать вложенные вызовы функций, а также всем настоящим питонистам этот код - золото!
А мы имеем в сухом остатке обязательные аннотации типов, что приучает к строгости, контроль ошибок на этапе компиляции и скорость выполнения как в C#.
Здравствуй, дивный новый старый мир!
#SPython
Интеграция SPython и PascalABC.NET в лице GraphWPF
Скоро сказка сказывается, да не скоро дело делается.
Вот и в SPython наконец-то завезли модуль GraphWPF - подключаем, пользуемся, радуемся синтаксису Питона без этих ваших begin-end и точек с запятой, зато с проверкой ошибок на этапе компиляции
#SPython
Парсер выражений с построением AST - дерева
Ниже представлен парсер выражений с предварительным построением AST-дерева - на 127 строк.
Интерфейсы, автоклассы, короткие функции - всё как мы любим.
https://rosettacode.org/wiki/Arithmetic_evaluation#PascalABC.NET
Тут много реализаций на разных языках, НО! Не стоит нас учить, как писать парсеры :)
А мы в Rosetta Code на 57 месте с 609 решениями. Еще немного - и обойдем Swift.
Обход ориентированного графа в глубину
Пусть граф задан списками смежности:
0 → 1, 2
1 → 3
2 → 1, 4
3 → 5
4 → 6
5 → 4, 7
6 →
7 →
Данный рекурсивный алгоритм демонстрирует, в какие вершины можно попасть, начав с некоторой вершины x и перемещаясь только по ребрам графа.
Такой способ посещения вершин называется обходом в глубину (DFS).
// Обход ориентированного графа в глубину
procedure TraverseDepth(gr: array of array of integer; p: array of boolean; x: integer);
begin
Print(x);
p[x] := True;
foreach var y in gr[x] do
if not p[y] then
TraverseDepth(gr,p,y);
end;
begin
var gr := [[1, 2], [3], [1, 4], [5], [6], [4, 7], [], []];
var p := [False] * gr.Count;
TraverseDepth(gr,p,0);
end.
#алгоритмыИнициализация массива пустой коллекцией
В версии 3.10.3.3635 от 12.06.25 уточнен механизм инициализации пустой коллекцией.
Теперь пустую коллекцию можно использовать в качестве первого элемента массива.
#новое
// Уточнение инициализации элемента массива пустой коллекцией
begin
var a: array of array of integer := [[],[],[1]];
Println(a,TypeName(a));
var b := [[],[1],[]];
Println(b,TypeName(b));
var aa: array of array of array of integer := [[[],[2]],[]];
Print(aa,TypeName(aa));
end.Замечательные Кубики для всех
Замечательная, потрясающая, многогранная головоломка Кубики для всех, описанная в книге Мартина Гарднера "Математические головоломки и развлечения".
Мы реализовали ее с помощью модуля Graph3D. Теперь вы можете собирать фигуры в интерактивном 3D-режиме
Изящно сделаны вращения - с помощью алгоритмической анимации
Весь код - порядка 350 строк, в комментарии
Рисование по клеткам в модуле Coords
Модуль Coords можно использовать по-разному, в том числе для рисования на нем как в тетради в клетку.
Особенность здесь в том, что мышью мы рисуем точки в целочисленных координатах.
Конечно, модуль Coords не предназначен для такой задачи - внутренности в виде объекта fso не очень хорошо смотрятся. Но как прототип - вполне компактная программа.
uses Coords,GraphWPF;
var (prevx, prevy) := (-1.0,-1.0);
begin
Scale := 49;
Origin := (7,5);
OnMouseDown := (x,y,mb) -> begin
if mb = 2 then
begin
(prevx, prevy) := (-1.0,-1.0);
exit;
end;
var p := fso.ScreenToReal(Pnt(x,y));
var xx := Round(p.X);
var yy := Round(p.Y);
Coords.DrawCircle(xx,yy,0.05);
if (prevx, prevy) <> (-1.0,-1.0) then
DrawLine(prevx, prevy, xx, yy);
(prevx, prevy) := (xx,yy);
end;
end.Кубики для всех - задачи
Перед вами - программа, позволяющая визуализировать задачи увлекательной головоломки Кубики для всех или Кубики Сома.
Отличная возможность модуля Graph3D - возможность увеличить головоломку, посмотреть на нее с разных сторон и под разными углами.
В архиве помимо самой программы - набор из 100 задач, а также возможность создавать новые задачи.
Клавиши
1,2,3 - отображение разными цветами
С - очистка
L - загрузка случайного задания
Исходники - в комментарии
Распаковка KeyValuePair в переменные
В последней версии реализована распаковка KeyValuePair в переменные как в C#. В том числе в цикле foreach по словарю.
Распаковка еще делается для кортежей и последовательностей. Для последовательности если элементов в ней недостаточно, распаковка упадет в рантайме.
#новое
begin
var t := 2 to 3.5;
var (a,b) := t;
Println(a,b);
foreach var (a1,b1) in Dict(1 to 7, 22 to 555) do
Println(a1,b1);
end.InRange - изменение поведения и внешняя функция
InRange метод расширения - поведение изменено - теперь [6.,2] считается пустым диапазоном.
Появилась внешняя функция inRange, которая работает с любыми типами, поддерживающими IEnumerable<T> - например, DateTime.
begin
// Поведение изменено!! Теперь диапазон [6,2] считается пустым
5.InRange(6,2).Println;
// Универсальная InRange. Должен поддерживаться интерфейс IComparable<T>
InRange(5,2,6).Println;
var dt1 := DateTime.Create(2025,04,16);
var dt2 := DateTime.Create(2025,04,29);
var dt3 := DateTime.Now;
InRange(dt2,dt1,dt3).Println;
end.
#новоеМетоды IsOrdered, IsOrderedBy, IsOrderedByDescending
Добавлены методы
IsOrdered, IsOrderedBy, IsOrderedByDescending, позволяющие проверить, упорядочена ли последовательность, вычисляемых по заданной лямбде. Поддерживаются любые последовательности.
Пример:
type
Player = auto class
Name: string; Points: integer;
end;
function GetPlayers := [
new Player('Alice', 120),
new Player('Bob', 95),
new Player('Charlie', 130),
new Player('Diana', 110)
];
begin
var leaderboard := GetPlayers;
if not leaderboard.IsOrderedByDescending(p -> p.Points) then
Println('Рейтинг составлен неверно!');
leaderboard := leaderboard.OrderByDescending(p -> p.Points).ToArray;
if leaderboard.IsOrderedByDescending(p -> p.Points) then
Println('Теперь рейтинг составлен правильно!');
end.
Метод возвращает true, если каждый следующий элемент не больше предыдущего с точки зрения переданной функции.
Аналогично работает метод IsOrderedBy для проверки по возрастанию.
#новоеНовый оператор exit(param) в PascalABC.NET
В PascalABC.NET появился оператор exit(param), который давно присутствовал в Delphi.
Он аналогичен оператору
return n в C++ и позволяет возвращать значение с одновременным выходим из функции.
Во многих случаях это позволяет написать более элегантный код:
Пример 1.
function IsPrime(n: integer): boolean;
begin
for var i:=2 to n.Sqrt.Round do
if n.Divs(i) then
exit(False);
exit(True);
end;
begin
IsPrime(17).Print;
end.
Пример 2.
function FastPower(a: real; n: integer): real;
begin
if n = 0 then exit(1); // a^0 = 1
if n = 1 then exit(a); // a^1 = a
if n < 0 then exit(1 / FastPower(a, -n)); // отрицательная степень
var half := FastPower(a, n div 2);
if n mod 2 = 0 then exit(half * half); // чётная степень
exit(half * half * a); // нечётная
end;
begin
Writeln('2^10 = ', FastPower(2, 10)); // 1024
Writeln('3^-2 = ', FastPower(3, -2)); // 0.111...
end.
Пример 3.
function FindFirstIndex(arr: array of integer; value: integer): integer;
begin
for var i := 0 to arr.Length - 1 do
if arr[i] = value then exit(i); // нашли — сразу выходим с результатом
exit(-1); // не нашли — возвращаем -1
end;
begin
var a := [5, 3, 8, 10, 2];
Writeln('Индекс числа 8: ', FindFirstIndex(a, 8)); // 2
Writeln('Индекс числа 7: ', FindFirstIndex(a, 7)); // -1
end.
#новоеГенерируем лабиринт на PascalABC.NET
Создаём визуализацию лабиринта с помощью библиотеки GraphWPF! Алгоритм использует рекурсивный обход в глубину и рисует путь, разбивая сетку на клетки. Цвета настроены: чёрные стены, белые коридоры, зелёная точка входа и красная выхода. Лабиринт создаётся с чётким контролем размеров и выглядит аккуратно благодаря масштабированию клеток. Отличный пример для демонстрации работы со структурами данных, графикой и рекурсией.
📌 Полезно для: олимпиад, визуального обучения рекурсии, задач по генерации случайных структур.
uses GraphWPF;
const
w = 60; // ширина в клетках
h = 40; // высота в клетках
cellSize = 10; // размер клетки в пикселях
wallColor = Colors.Black;
pathColor = Colors.White;
startColor = Colors.Green;
endColor = Colors.Red;
var maze := MatrGen(w*2+1, h*2+1, (x,y) -> True);
var dirs := Arr(
(0, -2), // Up
(2, 0), // Right
(0, 2), // Down
(-2, 0) // Left
);
procedure DrawCell(x, y: integer; c: Color)
:= FillRectangle(x*cellSize/2, y*cellSize/2,
cellSize/2, cellSize/2, c);
procedure GenerateMaze(x, y: integer);
begin
maze[x, y] := false;
dirs.Shuffle;
foreach var (dx, dy) in dirs do
begin
var (nx, ny) := (x + dx, y + dy);
if (nx in 1..w*2-1) and (ny in 1..h*2-1) and maze[nx, ny] then
begin
var (wx, wy) := (x + dx div 2, y + dy div 2);
maze[wx, wy] := false;
GenerateMaze(nx, ny);
end;
end;
end;
procedure DrawMaze;
begin
Window.SetSize(w*cellSize + 5, h*cellSize + 5);
Window.Clear(Colors.White);
for var x := 0 to w*2 do
for var y := 0 to h*2 do
if maze[x, y] then
DrawCell(x, y, wallColor)
else DrawCell(x, y, pathColor);
// Вход и выход
DrawCell(0, 1, startColor);
DrawCell(w*2, h*2-1, endColor);
end;
begin
Window.Title := 'Генератор случайного лабиринта';
GenerateMaze(1, 1);
DrawMaze;
end.Строим дерево
С помощью модуля Turtle и рекурсии построим ветвистое дерево
uses Turtle;
procedure DrawTree(length: real; depth: integer);
begin
if depth > 0 then
begin
forw(length);
turn(-35);
DrawTree(length*0.65, depth-1);
turn(70);
DrawTree(length*0.65, depth-1);
turn(-35);
forw(-length);
end;
end;
begin
toPoint(0, -8);
down;
DrawTree(6, 11);
end.
Что происходит?
💠 Черепаха (Turtle) рисует ветку, поворачивается и рекурсивно вызывает себя для меньших веток.
💠 Чем больше глубина (depth), тем детальнее дерево.
💠 Фрактальная природа кода создает красивое самоподобное дерево!
Попробуйте изменить параметры (length, depth, углы) и создайте свой уникальный дизайн!
#рекурсия #графика♟ Рекурсия и N ферзей
Знаменитая задача — расставить N ферзей на шахматной доске так, чтобы они не били друг друга. Классика, идеально подходящая для изучения рекурсии!
const N = 8; // размер доски
function IsSafe(board: array of integer; row, col: integer): boolean;
begin
Result := True;
for var i := 0 to row - 1 do
if (board[i] = col) or // Проверка вертикали
(board[i] - i = col - row) or // Проверка диагонали /
(board[i] + i = col + row) then // Проверка диагонали \
begin
Result := False; // Найден конфликт
exit;
end;
end;
procedure SolveNQueens(board: array of integer; row: integer);
begin
if row = N then
board.Println
else
for var col := 0 to N - 1 do
if IsSafe(board, row, col) then
begin
board[row] := col;
SolveNQueens(board, row + 1);
end;
end;
begin
var board := [0] * N;
SolveNQueens(board, 0);
end.
🔹 Массив board[row] хранит номер столбца, в котором стоит ферзь в строке row.
🔹 IsSafe проверяет вертикали и диагонали, чтобы избежать конфликта.
🔹 Рекурсия перебирает все допустимые расстановки.
Попробуйте поменять N и посчитайте, сколько решений получится!Рекурсивный алгоритм генерации перестановок
Хотите вывести все возможные перестановки чисел от 1 до n? Вот рекурсивный алгоритм на PascalABC.NET:
procedure Permute(a: array of integer; k: integer);
begin
if k = 1 then
a.Println
else
for var i := 0 to k-1 do
begin
(a[i], a[k-1]) := (a[k-1], a[i]);
Permute(a, k-1);
(a[i], a[k-1]) := (a[k-1], a[i]);
end;
end;
var n := ReadInteger('Введите n:');
var a := Arr(1..n);
Permute(a, n);
Как это работает:
1. Базовый случай (k=1):
Когда остается 1 элемент, выводим текущую перестановку (массив a)
2. Рекурсивный шаг:
Для каждого элемента от 0 до k-1:
🔹 Меняем текущий элемент (a[i]) с последним (a[k-1])
🔹 Рекурсивно генерируем перестановки для первых k-1 элементов
🔹 Возвращаем элементы на исходные позиции (снова меняем текущий с последним)
3. Важно:
🔹 Глубина рекурсии равна n
🔹 Всего генерируется n! перестановок
🔹 Кортежное присваивание делает код более читаемым
🔹 Алгоритм эффективен только для небольших n (до 10-12), так как факториал растёт очень быстро. Для n=10 уже нужно обработать 3 628 800 перестановок!
Пример работы для n=3:
1 2 3 2 1 3 3 2 1 2 3 1 1 3 2 3 1 2
🔁 Инвертирование словаря в PascalABC.NET
Когда нужно быстро найти ключ по значению (например, перевести слово обратно), пригодится инвертирование словаря — замена местами ключей и значений.
⚠️ Важно: значения должны быть уникальными — иначе данные потеряются!
📌 Решение в одну строку:
var dInv := Dict(d.Select(kv → (kv.Value to kv.Key)));
Как это работает:
- kv → (kv.Value to kv.Key) — создаёт новую пару "значение → ключ"
- Dict(...) — собирает пары в инвертированный словарь
Пример:
var d := Dict('hello' to 'привет',
'dog' to 'собака',
'cat' to 'кошка');
var dInv := Dict(d.Select(kv → (kv.Value to kv.Key)));
Print(dInv);
📤 Результат:
{(привет,hello), (собака,dog), (кошка,cat)}
✅ Плюсы:
- Кратко и наглядно
- Использует LINQ и лямбда-выражения
- Полезно в задачах на обработку данныхRepost from N/a
Старт первого тура олимпиады "Мехмат - PascalABC.NET 2025"
19 апреля в 18.00 стартует первый онлайн тур двухчасовой олимпиады "Мехмат - PascalABC.NET 2025" для школьников.
Данный тур является отборочным перед вторым туром.
Второй тур пройдет в очном формате 26 апреля в 16.00.
Победа во втором туре будет давать 5 баллов ЕГЭ, а призовые места - 3 балла ЕГЭ при поступлении на мехмат ЮФУ!
Официальный телеграм-канал олимпиад PascalABC.NET - https://t.me/Olymp_PABC.
Если вы еще не подписаны, подпишитесь на телеграм-группу - в ней будет вся информация и в ней можно задавать вопросы.
https://t.me/+fM6_OvADfzlkMjky
Если вы еще не регистрировались на наши олимпиады по PascalABC.NET - зарегистрируйтесь на олимпиаду до 19 апреля, используя бот регистрации Телеграм @pascalOlympBot, и пройдите пробный тур.
Для участия в олимпиаде обязательно скачайте и установите свежую версию PascalABC.NET от 11.04.25 или позже!
