ch
Feedback
PascalABC.NET официальный канал

PascalABC.NET официальный канал

前往频道在 Telegram

Официальный канал языка и системы программирования PascalABC.NET

显示更多
1 860
订阅者
-424 小时
-97 天
-2530 天
帖子存档
Почему PascalABC.NET лучше C# Заголовок конечно провокационный. Но действительно - C# при всех огромных ресурсах на его разра
Почему 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. Тем, кому нравится писать вл
SPython - map, filter, sorted Стандартные функции Питона реализованы в SPython на PascalABC.NET. Тем, кому нравится писать вложенные вызовы функций, а также всем настоящим питонистам этот код - золото! А мы имеем в сухом остатке обязательные аннотации типов, что приучает к строгости, контроль ошибок на этапе компиляции и скорость выполнения как в C#. Здравствуй, дивный новый старый мир! #SPython

Интеграция SPython и PascalABC.NET в лице GraphWPF Скоро сказка сказывается, да не скоро дело делается. Вот и в SPython након
Интеграция SPython и PascalABC.NET в лице GraphWPF Скоро сказка сказывается, да не скоро дело делается. Вот и в SPython наконец-то завезли модуль GraphWPF - подключаем, пользуемся, радуемся синтаксису Питона без этих ваших begin-end и точек с запятой, зато с проверкой ошибок на этапе компиляции #SPython

Парсер выражений с построением AST - дерева Ниже представлен парсер выражений с предварительным построением AST-дерева - на 1
Парсер выражений с построением 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 →
Обход ориентированного графа в глубину Пусть граф задан списками смежности: 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 уточнен механизм инициализации пустой коллекцией. Те
Инициализация массива пустой коллекцией В версии 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 Модуль 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#. В том числ
Распаковка 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 - изменение поведения и внешняя функция 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! Алгоритм использует рекурс
Генерируем лабиринт на 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; dept
Строим дерево С помощью модуля 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 ферзей на шахматной доске так, чтобы они не били друг друга. Классика,
Рекурсия и 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 Когда нужно быстро найти ключ по значению (например, перевести слово обратно), приг
🔁 Инвертирование словаря в 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" 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 или позже!