Шахматная доска в псевдографике

Я люблю шахматы, и есть некоторые места в интернете, где я не могу просто взять и вставить картинку, чтобы наглядно показать шахматную позицию. До определённого момента это меня не волновало, но однажды космический луч ударил мне в мозг и активировал небольшой нейронный импульс, который лавинообразно активировал сдерживаемые до этого момента мысли. И мне пришла в голову мысль, а почему бы не представить шахматную доску в виде ASCII Art?

TL; DR

Процесс разработки одной функции. Вряд ли интересен опытным программистам, но вполне подойдёт новичкам, чтобы те представляли, как вообще происходит программирование. Опытные программисты найдут много недостатков и для них статья носит больше развлекательных характер.

Что мне нужно? Или Техническое Задание

Шахматная позиция обычно задаётся с помощью нотации Форсайта – Эдвардса. Буквами K, Q, R, B, N, P обозначаются белые фигуры, а в нижнем регистре – чёрные. Косая черта / разделяет горизонтали, а числа обозначают количество пустых клеток. Это всё, что надо мне знать о нотации FEN.

Что мне необходимо? Показать эту позицию наглядно с помощью шахматных фигур на шахматной доске. И всё это используя только символы. Осталось только нарисовать, что я хочу видеть. Точнее напечатать.

Сначала я решил найти готовые решения и они мне не очень понравились. Попытка перевести картинку в псевдографику выглядела убого и получившаяся картинка занимала слишком много места. К тому же я не мог сделать текст моноширинным, чтобы он выглядел красиво.

Поиск решения, наглядное представление

И первым делом я скопипастил скопировал из Википедии юникод символы шахмат в ряд, чтобы посмотреть, как это будет выглядеть:

♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜

На мой дилетантский дизайнерский взгляд это уже выглядит неплохо. Почему бы не сделать шахматную доску просто из пробелов и шахматных символов?

♜ ♞ ♝ ♛ ♚ ♞

♝ ♜

О нет, это выглядит ужасно! Глазу не за что зацепиться, чтобы привязаться к координатам. И есть маленькая проблема с пробелами. Но несущественна на фоне этого ужаса.

Я попытался сделать разделители:

|♜ |♞

Это всё ещё выглядит плохо. Нужно что-то, что я буду воспринимать лучше. Я долго копался в интернете выискивая решение и даже наткнулся на это:

# # #

# #

# # #

Это типа шахматная доска, но я не знаю, как символ рисовать поверх символа средствами символьных команд, точнее знаю, но мне было лень в этом разбираться. Да и где-то в глубинах памяти есть заметка: "наложение символа на символ спецсимволом работает не со всеми символами". Видимо когда-то в прошлом я этим занимался и записал это обобщение в мозг. И как обычно без конкретики, так что придётся гуглить, если мне будет интересно разобраться в этом.

Я не знаю в какой момент, но мой разум обратил внимание на точки. Я нашёл символ широкого пробела, я скопировал его в буфер обмена и принялся рисовать. Результат мне понравился:

. ♜. ♞. ♝. ♛. ♚. ♝. ♞. ♜.

. ♟. ♟. ♟. ♟. ♟. ♟. ♟. ♟.

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. ♙. ♙. ♙. ♙. ♙. ♙. ♙. ♙.

. ♖. ♘. ♗. ♕. ♔. ♗. ♘. ♖.

Это было то, что мне нужно. Минималистично, кратко, понятно. На мой дилетантский дизайнерский взгляд это красиво. Осталось превратить строку в виде "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR" в строку выше.

Макет, интерфейс и обвязка

Первым делом я в виде html странички создал интерфейс. Очень простенький поле ввода и кнопка:

<div>
  <form name="publish">
    <input type="text" name="message" id="input" />
  </form>
<button name="send" id = "click" >Отправить</button>
</div>
<div id="result" ></div>

Как по мне больше ничего не нужно. Это идеальный минималистичный интерфейс для одной функции. Есть поле ввода, есть кнопка, есть поле вывода.

Программирование

Программировал я на js давно и всё позабыл. Пришлось вспоминать на ходу. Я создал небольшую функцию. Она очень простенькая. Get Result:

getres(){};

Так я избавился от проблемы чистого листа и начал думать, что эта функция должна делать. По идее я должен сделать документацию в коде, но я делал её в голове, поскольку не помнил как делают комментарии в js, а искать и разбираться было лень. Итак, функция делает: читает поле ввода, вызывается по нажатию кнопки, пишет результат в div элемент, где выводится результат. И ещё, важная вещь:

//TODO сделать документацию к функции. Даже если она простая и понятная.

Далее я в теле функции добавил необходимые мне переменные с которыми я буду работать:

var m = document.getElementById("input").value;
var result ="";
var l=m.length;

Я считал поле ввода, теперь надо вывести результат:

document.getElementById("result").innerHTML = result;

Отлично, у нас есть переменная m из которой мы читаем по FEN и переменная result, куда мы пишем результат. И первым делом пишем точку:

result += ".";

Тестируем, исправляем ошибки. О, вот тут начинается веселье Так, например у меня была проблема с тем, что при нажатии на кнопку input у меня перезагружалась страница, пришлось вывести кнопку из формы. То что вы видели ранее это уже готовое решение к которому я пришёл через ошибки. Я забыл js и html, поэтому в моём коде было много копирования из других источников. Которые я исправлял и допиливал.

Дальше я просто сделал цикл, чтобы пройтись по всем элементам строки m, но самое главное я внутрь цикла добавил базовую конструкцию из условий:

for (var i=0; i < l; i++)
{
  if (m[i] == "")
  {
    result += "";
  }
  else
}

Я читаю символ из m, сравниваю и пишу результат. Теперь делаем копирование и вставить, копипастим:

for (var i=0; i < l; i++)
{
  if (m[i] == "")
  {
    result += "";
  }
  else if (m[i] == "")
  {
    result += "";
  }
  else if (m[i] == "")
  {
    result += "";
  }
  else
}

Думаю на этом моменте у некоторых более опытных разработчиков где-то в глубине разума раздастся истошный испуганный визг или иная проявится иная негативная реакция, но они опытные разработчики и не такое видели. Но пока ничего плохого не произошло, весь ужас будет дальше. От себя добавлю: при копировании кода нужно быть очень внимательным, иначе будет нечто такое:

x=+w*n;
y=+w*n; //<-тут вместо w должен быть h

Следующим шагом мы делаем зарядку. Разминаем шею, ноги, глаза. И приступаем к заполнению необходимых полей, то есть делаем по символам дешифровку FEN

if (m[i] == "1")
        {
            result += " .";
        }
        else if (m[i] == "2")
        {
            result += " . ."; <- 2 это два больших пробела с точкой :D
        }
        else if (m[i] == "3")
        {...

        ...
        else if (m[i] == "/")
        {
            result += "\n<br>."; <- тут я сначала забыл добавить тэг <br>
        }
        else if (m[i] == " ")
        {
            break;
        };

Думаю вы легко нашли ошибки в стиле программирования и не только.

Тяп-ляп и в продакшн? Почему бы и нет

Осталось опубликовать свой продукт, а именно, маленькое приложение преобразующее FEN в UTF арт. Здесь должна быть история проблем с созданием репозитория и его наполнением путём переноса файлов со смартфона, но я это опущу. В общем, когда всё получилось, то я испытал незабываемое удовольствие, сравнимое с удовольствием от build successful.

Выводы и важные примечания

else if (m[i] == "2")
        {
            result += " . ."; 

Я более чем уверен, что есть более элегантное и красивое решение без дополнительных ветвлений.

Заключение

Мне было приятно написать простенький код для решения одной задачи. Однако вряд ли я его буду поддерживать. Мне достаточно того функционала, что есть на данный момент. Надеюсь вы вынесли для себя что-то полезное, нашли места где я что-то сделал не так, да и просто приятно провели время за чтением. Не говоря уже о том, что некоторые могут попытаться улучшить мой код и попробовать отправить мне изменения, получив первый опыт изменения чужого кода. Благодарю за внимание.

Проект на Github:

https://github.com/Askalite/FenTransform

Страничка с очень маленьким приложением:

https://askalite.github.io/FenTransform/

Пример FEN: 3r1kq1/p2prp1p/5RpP/8/2Q5/1B4P1/P4PK1/8 w - - 1 53

@Askalite
14.11.2022 20:43 UTC
Первоисточник

Комментарии

@baldr
14.11.2022 15:56 UTC
+3

Думаю вы легко ошибки в стиле программирования и не только.

Думаю вы просто смысл и не только.

@lynxp9
14.11.2022 16:05 UTC
+1

Можно пример fen, чтобы посмотреть как оно работает?

@Askalite
14.11.2022 16:12 UTC
0

3r1kq1/p2prp1p/5RpP/8/2Q5/1B4P1/P4PK1/8

14.11.2022 16:23 UTC
0

Классно) Я когда-то давно делал пет-проджект с полезной нагрузкой в виде шашек. Именно по шашкам трудно было найти информацию. А ваша статья может облегчить жизнь какому-то студенту в написании лабораторной или курсовой)

@Rsa97
14.11.2022 17:15 UTC
+11
const figures = {
  'p': '♟', 'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚', 'd': '⛂', 'm': '⛃'
  'P': '♙', 'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔', 'D': '⛀', 'M': '⛁'
  'e': '  ', 'f': '.', '/': "<br>\n",
};
const decodeField = (code) =>
  code.replaceAll(
    /[prnbqk]/ig,
    (c) => `${figures.f}${figures[c]}`,
  ).replaceAll(
    /\d/g,
    (d) => `${figures.f}${figures.e}`.repeat(+d),
  ).replaceAll('/', `${figures.f}${figures['/']}`)
 + figures.f;

decodeField('3r1kq1/p2prp1p/5RpP/8/2Q5/1B4P1/P4PK1/8');

// .  .  .  .♜.  .♚.♛.  .<br>
// .♟.  .  .♟.♜.♟.  .♟.<br>
// .  .  .  .  .  .♖.♟.♙.<br>
// .  .  .  .  .  .  .  .  .<br>
// .  .  .♕.  .  .  .  .  .<br>
// .  .♗.  .  .  .  .♙.  .<br>
// .♙.  .  .  .  .♙.♔.  .<br>
// .  .  .  .  .  .  .  .  .
@infund
14.11.2022 18:16 UTC
+2

Давным-давно была шахматная программа Sargon III. В ранних ее версиях и доска и фигуры отрисовывались досовской псевдографикой. Весь геймплей происходил в текстовом режиме 80х25.

Геймплей

@Nikita_64
14.11.2022 21:56 UTC
0

О да, на Apple II тоже был, кажется, Sargon II.

@LuchS-lynx
15.11.2022 04:58 UTC
0

В MS DOS через ассемблер, да и на Спектруме можно было программировать некоторые символы, заменяя текущее отображение на необходимое, т.е., к примеру, перерисовать шрифт, или использовать символы вместо спрайтов

15.11.2022 06:12 UTC
0

В детстве на 286ом у меня была не помню какая программа, которая позволяла рисовать шрифты под DOS. И не помню какая программа которая позволяла их загружать. Было забавно. Но все умерло на 40мб жестком диске)))

15.11.2022 07:57 UTC
0
Загружались они через mode con cp prep=((NUMBER),,FILE) плюс mode con cp sel=NUMBER вероятнее всего. А программа для шрифтов — досадно, что потерялась.
15.11.2022 10:26 UTC
0

у меня, возможно, осталось... надо будет завтра поднять школьные архивы, но если только в исходниках.

25.11.2022 07:57 UTC
0

Кажется нашел в запасниках
https://disk.yandex.ru/d/T1TsaDxFA_mrew

@1nsan31nsId3
15.11.2022 06:01 UTC
0

Можно использовать ТЕХ формат для этого.

@roqin
15.11.2022 19:12 UTC
0

Да и где-то в глубинах памяти есть заметка: "наложение символа на символ спецсимволом работает не со всеми символами".

А у меня в голове отложилось что это работает только со спецсимволами (Combining Marks или что-то вроде того). Множество чёрных и белых квадратиков есть, только вот как наложение сделать? Там вроде и подходящая диакритика есть, только вот выглядят сейчас не очень: ♔ + ◌⃞ (U+20DE) = ♔⃞. На чёрное поле фигуру только с помощью голого текста поставить не получится.

Эмодзи раскрасить можно (????), только с шахматами это не работает. Пичалька ?