• Создание программы временами похоже ругань в соцсетях — с компилятором, отладчиком и… самим собой.

Конвертор PGN файлов для шахматистов

Формат файлов PGN (Portable Game Notation) предназначен для сохранения шахматных партий. Он был разработан Стивеном Эдвардсом в 1994 году, чтобы облегчить обмен партиями (к примеру, через интернет) между шахматными программами. Однако, сразу же возникла элементарная проблема — как обычно, языковая: между русскими и английскими обозначениями фигур. И сейчас одни программы понимают английские обозначения, другие — русские, третьи — вообще ничего не понимают… 🙂

Но передавать информацию как-то надо. Самый простой способ — понять, в чем разница между двумя «почти одинаковыми» форматами и написать свой конвертор, который сможет быстро и без проблем конвертировать файлы из одного формата в другой.

Вот пример партии записанной в русском PGN формате:

1.	e4	e5
2.	d4	exd4
3.	Фxd4	Кc6
4.	Фc4	d6
5.	Кf3	Сe6
6.	Сg5	Сe7
7.	Фd3	Кb4
8.	Фd2	Кc6
9.	Сxe7	Фxe7
10.	Кd4	Кxd4
11.	Фxd4	c5
12.	Фxg7	Фf6
13.	Сb5+	Сd7
14.	Сxd7+	Крxd7
15.	Фg4+	Крe7
16.	O-O	Фxb2
17.	Кd2	Фxc2
18.	Фg5+	f6
19.	Фg7+	Крe6
20.	Фxh8	Фxd2
21.	Фxh7	Фb2
22.	Фh3+	Крe7
23.	Лfe1	Крf7
24.	Фh7+	Крf8
25.	Фxb7	Фxb7
26.	e5	dxe5
27.	f3	Фb2
28.	Лab1	Фxa2
29.	Лbc1	Фb2
30.	Лxc5	Фd2
31.	Лcc1	Кe7
32.	h4	Кd5
33.	Лed1	Фe2
34.	Лe1	Фd2
35.	h5	Кe3
36.	Лxe3	Фxe3+
37.	Крf1	Фxc1+
38.	Крe2	Фc2+
39.	Крe1	Лb8
40.	h6	Лb1#

Такой файл, например, сервис Chess.com «не понимает» — ему нужен английский вариант формата. Ниже приводится простая программа, позволяющая выполнить преобразование русского формата в английский. Если вы вдруг столкнетесь с каким-то другим форматом записи PGN файлов, думаю, не составит большого труда изменить данную программу так, чтобы она смогла конвертировать и этот формат.

Программе нужно передать в параметрах командной строки (перетащить мышкой на значок программы) файл с записанным PGN файлом в «неправильной» кодировке. В результате работы будет создан файл, к имени которого будет добавлен префикс «_EN», содержащий данные в английском PGN коде.

' Программа преобразования файла шахматной нотации формата PGN из русского в английский (например, для Анализатора партий chess.com)

' Функция замены в строке одной подстроки на другую - 1 раз в первом месте, где встретилась искомая подстрока
' P1 - строка, P2 - подстрока для поиска, P3 - подстрока для замены, Ret = итоговая строка, если была замена, иначе = ""
Sub StrReplace
    Ret = ""
    If Text.IsSubText(P1,P2) = "True" Then ' если искомая подстрока присутствует в строке
        StrRepBl = Text.GetLength(P2)  ' Длинна подстроки для поиска
        StrRepAl = Text.GetIndexOf(P1,P2)  '  Позиция начала подстроки в строке
        StrRepA = Text.GetSubText(P1,1,StrRepAl-1) ' Получаем часть строки до начала искомой подстроки, используя позицию начала подстроки в строке
        StrRepC = Text.GetSubTextToEnd(P1,StrRepAl+StrRepBl)  ' Получаем часть строки от начала искомой подстроки
        Ret = Text.Append(StrRepA,P3) ' Собираем часть строки до начала искомой подстроки и замену
        Ret = Text.Append(Ret,StrRepC) ' Собираем часть строки до начала искомой подстроки с заменой и начало части строки от начала искомой подстроки
    EndIf
EndSub
'________________________________________________________________________

' Массив замены:  Sim[][1] - заменяем на Sim[][2]
Sim[1][1] = "Кр"
Sim[1][2] = "K"
Sim[2][1] = "С"
Sim[2][2] = "B"
Sim[3][1] = "Ф"
Sim[3][2] = "Q"
Sim[4][1] = "К"
Sim[4][2] = "N"
Sim[5][1] = "Л"
Sim[5][2] = "R"
Sim[6][1] = "	" ' здесь символ табуляции!!!!
Sim[6][2] = " "
Sim[7][1] = "#"
Sim[7][2] = ""
Sim[8][1] = "+ "
Sim[8][2] = " "
Sim[9][1] = "- "
Sim[9][2] = " "
Sim[10][1] = "  "
Sim[10][2] = " "
SimLen = 10

TextWindow.BackgroundColor = "gray"
TextWindow.Clear()
TextWindow.ForegroundColor = "black"
TextWindow.WriteLine("Программа преобразование русского файла шахматной нотации PGN в английский")
TextWindow.WriteLine("")

If Program.ArgumentCount <> 1 Then  '  Проверяем аргументы:  если не 1
    'TextWindow.ForegroundColor = "red"
    TextWindow.WriteLine("*** Нет файла для обработки! ***") ' сообщаем об ошибке
    TextWindow.ForegroundColor = "darkcyan"  '  пишем хелп
    TextWindow.WriteLine("")
    TextWindow.WriteLine("Формат: PGN.exe PGN_файл - в кодировке UTF-8")
    TextWindow.WriteLine("")
    TextWindow.ForegroundColor = "black"
    TextWindow.WriteLine("Обрабатываем буфер обмена.")
    TextWindow.WriteLine("")
    OutStr = FCClipboard.CopiedText '  получаем буфер обмена
    buf = 1
    Goto work
Else ' если  аргумент 1 - читаем его - это имя файла
    FIn = Program.GetArgument(1) ' Получаем имя входного файла
    buf = 0
    
    ' создать выходной файл с тем же расширением - к имени добавить "_EN"
    p = 0 ' позиция точки
    For k=1 To Text.GetLength(FIn)   ' позиция курсора в имени файла (до длинны имени файла)
        If Text.GetSubText(FIn,k,1) = "." Then   ' найти позицию последней точки в имени файла (читаем один символ из имени файла)
            p = k   ' записываем позицию точки
        EndIf
    EndFor
    If p = 0 Then '  точек не было!
        FOut = FIn + "_EN" '  значит файл без расширения, пишем дополнение в конец
        Goto next1
    EndIf
    
    q = 0 ' позиция бэкслэша
    For k=1 To Text.GetLength(FIn)   ' позиция курсора в имени файла (до длинны имени файла)
        If Text.GetSubText(FIn,k,1) = "\" Then   ' найти позицию последнего бэкслэша в имени файла (читаем один символ из имени файла)
            q = k   ' записываем позицию бэкслэша
        EndIf
    EndFor
    If q > p Then
        FOut = FIn + "_EN" '  значит файл без расширения, пишем дополнение в конец
        Goto next1
    EndIf
    
    If p = Text.GetLength(FIn) Then  ' точка - в самом конце имени! Ошибка!
        TextWindow.ForegroundColor = "red"
        TextWindow.WriteLine("*** Ошибка в имени файла! ***") ' сообщаем об ошибке
        TextWindow.WriteLine("")
        TextWindow.ForegroundColor = "darkcyan"  '  пишем хелп
        TextWindow.WriteLine("Формат: PGN.exe PGN_файл - в кодировке UTF-8")
        TextWindow.WriteLine("")
        TextWindow.ForegroundColor = "black"
        TextWindow.Pause() ' и завершаем работу
        Program.End()
    EndIf
    
    c = Text.GetSubTextToEnd(FIn,p) ' получаем расширение с точкой
    a = Text.GetSubText(FIn,1,p-1)  '  получить весь путь до расширения
    FOut = a + "_EN" + c  '  получили имя выходного файла
    next1:
EndIf

str = " "
i = 1
While str <> ""  ' До пустой строки
    str = File.ReadLine(FIn,i) ' Считываем одну строку из входного файла
    OutStr = OutStr + str + " "  ' В итоговую строку записываем считанную строку и Добавляем пробел в конец
    i = i + 1 ' счётчик строк
EndWhile

work:

For i = 1 To SimLen ' цикл по массиву замены
    P2 = Sim[i][1] '  что заменить в строке
    P3 = Sim[i][2] '  на что заменить
    Ret = " "
    While Ret <> "" '  пока есть, что заменять
        P1 = OutStr  '  строка
        StrReplace() ' вызов функции замены
        If Ret <> "" Then
            OutStr = Ret
        EndIf
    EndWhile
EndFor

If buf = 0 Then
    File.WriteLine(FOut,1,OutStr)  ' записываем в новый файл
EndIf
FCClipboard.CopiedText = OutStr  ' записываем в буфер обмена

q = 0 ' позиция бэкслэша
For k = 1 To Text.GetLength(FOut)   ' позиция курсора в имени файла (до длинны имени файла)
    If Text.GetSubText(FIn,k,1) = "\" Then   ' найти позицию последнего бэкслэша в имени файла (читаем один символ из имени файла)
        q = k   ' записываем позицию бэкслэша
    EndIf
EndFor

TextWindow.WriteLine("Создан файл: " + Text.GetSubTextToEnd(FOut,q+1)) ' Написать, что создан файл - и его имя без пути!
TextWindow.WriteLine("")
TextWindow.WriteLine("Программа успешно завершена.")
TextWindow.WriteLine("")
If buf = 1 Then
    Program.End()
EndIf

 

Поделиться: