FuncBall
Программируемый футбол


Главная  •  Скачать  •  Руководство  •  Команды  •  Чемпионат  •  Форум  •  Поддержка: FuncBall@gmail.com
Войти  •  Регистрация
  1. Общие принципы
  2. Основы языка
  3. Поле и система координат
  4. Перемещение игроков
  5. Пасы и удары
  6. Сигналы и флаги
  7. Все функции
  8. Макросы (выражения в квадратных скобках)
  9. Требования к командам для участия в чемпионатах

Общие принципы

  • В команде 4 игрока. Вратарей нет.
  • Мяч всегда вводится в игру с центра поля. Если мяч уходит от игрока за пределы поля, то он вводится в игру противоположной командой. Игрок, который вводит мяч, указывается в настройках команды. При вводе мяча, в центральном круге может находится только вводящий игрок.
  • Игроки могут координировать действия посредством подачи сигналов (только числа), которые видны всем.
  • Нет общей памяти. Память игрока реализуется установкой флагов. Т.е. в пул флагов игрока можно добавлять и удалять определёные значения (только числа).
  • Скорость игроков постоянная. Игрок с мячом бежит чуть медленнее игроков без мяча.
  • Пасы и удары по воротам делаются с погрешностью 15 градусов. Передач по воздуху нет.
  • Программы игроков выполняются в случайном порядке. Код вводящего мяч игрока в момент ввода выполняется первым.
  • Шаг игры - 50 миллисекунд. Скорость воспроизведения можно увеличивать и уменьшать. Есть режим "C", при котором матч высчитывается без воспроизведения. Есть режим "CR" при котором сначала делается вычисление, а потом запускается воспроизведение записи.

    Основы языка

    Для каждого из 4 игроков пишется программа, что и при каких условиях делать. Условия пишутся в обычных скобках, перед которыми стоит слово "Если", а действия пишутся в фигурных скобках, идущих после условий. Пример:

    Если(мяч_у_игрока){бить_по_воротам}

    В данном примере, игрок, если у него есть мяч, сделает удар по воротам. В фигурных скобках, после слова "иначе", можно добавить, что делать игроку в противном случае, т.е. если он не владеет мячом:

    Если(мяч_у_игрока){бить_по_воротам}иначе{бежать_к_мячу}

    Так, если у игрока нет мяча, он будет бежать к нему. Есть форма записи без использования скобок:

    Если мяч_у_игрока, то бить_по_воротам, иначе бежать_к_мячу.

    Если нужно совершить несколько действий, то нужно разделять их точкой с запятой:

    Если(мяч_у_игрока){бить_по_воротам; вернуться_на_старт}иначе{бежать_к_мячу; подать_сигнал:5}

    Без скобок:

    Если мяч_у_игрока, то бить_по_воротам; вернуться_на_старт, иначе бежать_к_мячу; подать_сигнал:5.

    Далее все примеры будут в форме записи со скобками.

    Условия и действия (буду дальше называть их функциями) могут иметь параметры. Например, по команде "бить_по_воротам" производится удар в случайное место ворот. Чтобы задать, куда точно бить, нужно добавить к команде координату Y, в которую послать мяч: "бить_по_воротам:168". Пример:

    Если(мяч_у_игрока){бить_по_воротам:168}

    Многим функциям надо указывать несколько параметров. Например, "отправить_мяч:498,142". В данном примере 498 и 142 это коордиаты X и Y, куда отправить мяч. Можно указать диапазон значений: "отправить_мяч:400-500,140-150". Так мяч будет отправлен на случайную точку с координатой X от 400 до 500, и Y от 140 до 150. Можно указать варианты значений через вертикальную черту: "отправить_мяч:410|430|470,140-150". В этом случае координата X будет 410 или 430 или 470. Примеры:

    Отправить мяч в квадрат 16 или 17: Если(мяч_у_игрока){отправить_мяч_в_квадрат:16|17}
    Если мяч у игрока 3, то бежать в квадрат 11: Если(мяч_у_игрока:3){бежать_в_квадрат:11}

    В этих примарах используется функция "мяч_у_игрока", которая проверяет, у какого игрока мяч. Если параметр не указывать, то она проверяет находится ли мяч у текущего игрока. Есть функции, в которых параметр указывается прямо в названии:

    Если(мяч_у_игрока и игрок3_открыт){пас_игроку:3}

    В данном примере функция "игрок3_открыт" проверяет, открыт ли игрок 3. Тут два условия, и пас игроку 3 будет сделан, только если они оба выполняются. Если надо проверить выполнение хотя бы одного из них, то надо вместо "и" использовать "или": "мяч_у_игрока или игрок3_открыт". Условия могут быть сложными:

    Если(мяч_у_игрока и (игрок3_открыт или ближний_к_чужим_воротам:3)){пас_игроку:3}

    И вложенными:

    Если(мяч_у_игрока){
        Если(игрок3_открыт или ближний_к_чужим_воротам:3){пас_игроку:3}
    }

    Проверить, что условие НЕ выполняется, можно добавив ! перед ним: Если(!мяч_у_игрока:3){бежать_в_квадрат:10}

    Прекращение выполнения текущего скрипта делается символом $:
    Если(!мяч_у_игрока:3){бежать_в_квадрат:10; $}

    Поддерживаются однострочные комментарии, начинающиеся с #:
    Если(ввод_мяча){пас_игроку:3} #пас третьему игроку

    Поле и система координат

    Размер поля: 560x376 пикселей. Y ворот: 154-250. Начало координат (точка 0,0) в левом верхнем углу. Разметка поля (изображение).

    При программировании игроков надо считать, что они начинают на левой половине поля. Номера своих игроков 1-4, а чужих 5-8. При игре справа все координаты, номера квадратов, углы и номера игроков отражаются, т.е. команда будет играть точно так же как и на левой половине.

    Узнать координаты точки на поле можно кликнув по нему, появится всплывающая подсказка. Если кликнуть правой кнопкой мыши, то координаты будут скопированы в буфер обмена.

    Перемещение игроков

    Для того, чтобы игрок бежал к мячу используется команда бежать_к_мячу (нет параметров). Когда игрок добежит до мяча, то завладеет им. GIF.

    Команда находиться_на_одной_линии_с_мячом, делает так, чтобы игрок не меняя положения по оси X перемещался по оси Y на одну линию с мячом. У данной команды есть опциональный (необязательный) параметр для задания координаты X, на которой находиться. GIF (игрок 3). Если мяч находится рядом, то делается захват мяча. Пример:
    Если(!мяч_позади){находиться_на_одной_линии_с_мячом:180}

    Бег в нужном направлении осуществляется командой бежать. Парметрами задаётся точка, в которую бежать. Пример: Если(мяч_у_игрока){бежать:192,263}

    Можно задавать направление бега в градусах. Для этого к первому параметру нужно добавить символ ^. Второй параметр - растояние. Пример: Если(мяч_у_игрока){бежать:45^,70}
    В этом примере игрок будет бежать в направлении 45 градусов на расстояние 70 пикселей.

    Можно задавать маршрут, указывая несколько точек:
    Если(ввод_мяча){бежать:363,182,447,71}
    В этом примере игрок сначала бежит в точку 363,182, а потом в точку 447,71. Ещё пример:
    Если(ввод_мяча){бежать:90^,100,373,234}
    Игрок сначала бежит 100 пикселей в направлении 90 градусов, а потом бежит в точку 373,234. Маршрут можно задавать из любого кол-ва точек.

    В отличие от команд "бежать_к_мячу" и "находиться_на_одной_линии_с_мячом", если во время бега игрок оказывается рядом с мячом захват мяча не делается. Для захвата нужо предусмотреть соответвующий код: Если(расстояние_до_мяча:0-6){бежать_к_мячу}

    Для бега в указанный квадрат можно использовать команду бежать_в_квадрат:
    Если(!игрок_в_квадрате:17){бежать_в_квадрат:17}.
    Игрок будет бежать в случайную точку внтри квадрата. Точка выбирается при каждом вызове команды. Поэтому нужно подавать её один раз, если она ещё не была подана:
    Если(!цель_задана){бежать_в_квадрат:17}
    Иначе игрок будет каждый ход (50 мс) менять направление. Если игрок уже в квадрате, то команда не будет выполняться.

    Пасы и удары

    Для удара по воротам можно использовать команду бить_по_воротам:
    Если(расстояние_до_чужих_ворот:0-100){бить_по_воротам}
    Мяч отправляется в случайную точку ворот. Можно указать координату Y, в которую отправить мяч:
    Если(расстояние_до_чужих_ворот:0-100){бить_по_воротам:159}
    Бить в случайную точку ворот: Если(расстояние_до_чужих_ворот:0-100){бить_по_воротам:154-250}

    Чтобы отправить мяч в любую точку поля, используйте команду отправить_мяч:
    Если(ввод_мяча){отправить_мяч:497,103}
    Мяч будет отправлен в точку 497,103. Скорость будет такова, чтобы мяч остановится примерно в указанной точке. Если надо отправить мяч с максимальной скоростью, то добавьте параметр "1":
    Если(ввод_мяча){отправить_мяч:497,103,1}
    Можно задать направление в градусах: Если(ввод_мяча){отправить_мяч:90^,100}
    В этом примере мяч будет направлен на расстояние 100 пикселей в направлении 90 градусов. Направить в случайном направлении на случайное расстояние: Если(ввод_мяча){отправить_мяч:0-359^,20-150}

    Отправить мяч в случайную точку указанного квадрата можно командой отправить_мяч_в_квадрат:
    Если(ввод_мяча){отправить_мяч_в_квадрат:17}

    Отдать пас игроку можно командой пас_игроку:
    Если(игрок3_открыт){пас_игроку:3}
    Мяч будет отправлен в точку, где находится игрок. Чтобы отдать пас на ход (в точку перед игроком), нужно вторым параметром указать, на сколько пикселей по оси X сместить цель:
    Если(ввод_мяча){пас_игроку:3,50}
    В этом примере пас отдаётся со смещением 50 пикселей.

    Отдать пас игроку, который находится к текущему ближе всех, можно командой пас_ближнему:
    Если(мяч_у_игрока и противник_на_пути){пас_ближнему}
    Ближний игрок определяется из игроков своей команды. Можно отдать пас второму или третьему по близости игроку:
    Если(мяч_у_игрока и противник_на_пути){пас_ближнему:2}

    Сигналы и флаги

    Как и в обычном футболе, игроки могут подавать друг другу сигналы (видны всем игрокам на поле). Для этого есть команда подать_сигнал:
    Если(ввод_мяча){подать_сигнал:5}
    Поддерживаются только числовые сигналы. По умолчанию сигнал подаётся на одну секунду. Можно задать продолжительность, указав её вторым параметром (в миллисекундах):
    Если(ввод_мяча){подать_сигнал:5,2000}
    В этом примере подаётся сигнал 5 на 2 секунды. Не стоит указывать время менее 50 мс , т.к. тогда сигнал будет действовать только в текущем ходе, и может быть считан только игроками, код которых обработается после подачи сигнала. Нужно помнить, что программы игроков выполняются в случайном порядке, а код вводящего мяч игрока в момент ввода выполняется первым. При вводе мяча все сигналы удаляются.

    Проверить сигнал игрока можно функцией игрок*_сигнализирует:
    Если(игрок3_сигнализирует:5){бежать_в_квадрат:16}
    Можно проверить предыдущий подаваемый сигнал функцией игрок*_сигнализировал: Если(игрок3_сигнализировал:22){бежать_в_квадрат:16}

    Сигналы отображаются над игроком, рядом с номером. Сигналы показываются и на записи.


    Память игроков реализуется флагами. Для каждого игрока можно установить до 5 флагов. Нельзя считать флаги другого игрока. Флаг устанавливается командой флаги: Если(игрок3_сигнализирует:5){флаги:+5}
    В этом примере текущему игроку добавляется флаг 5. Время его существования - до следующего ввода мяча, либо до конца матча, если не будет аута или гола. Можно указать время существования флага (мс):
    Если(игрок3_сигнализирует:5){флаги:+5,2000}
    В этом примере флаг 5 будет существовать 2 секунды.
    Можно добавить несколько флагов: Если(игрок3_сигнализирует:5){флаги:+5,2000,777,0}
    В этом примере игроку добавляется флаг 5 на 2 секунды и постоянный флаг 777.
    Удаление флага: Если(игрок_сигнализирует:5){флаги:-5}
    Задать точный набор флагов: Если(игрок_сигнализирует:5){флаги:7,0,9,3000}
    В этом примере устанавливаются флаг 7 (постоянный) и флаг 9 на 3 секунды. Все другие ранее добавленные флаги удаляются.
    Удалить все флаги: Если(игрок_сигнализирует:5){флаги:}

    Флаги отображаются под игроком как при игре, так и на записи. Чтобы на записи флаги не отображались (чтобы другие не знали, какие флаги вы используюте), укажите в файле команды в ExtraParams настройку hide_flags:
    update_number=327
    last_update=31.07.2019
    hide_flags=1

    Все функции

    УсловияДействия
    1. ближний_к_игроку*
    2. ближний_к_мячу
    3. ближний_к_своим_воротам
    4. ближний_к_чужим_воротам
    5. ввод_мяча
    6. действие_длится
    7. задан_флаг
    8. зона_свободна
    9. игрок*_ближний_к_точке
    10. игрок*_в_квадрате
    11. игрок*_открыт
    12. игрок*_сигнализировал
    13. игрок*_сигнализирует
    14. координаты_игрока*
    15. мяч_в_квадрате
    16. мяч_позади
    17. мяч_свободен
    18. мяч_у_игрока
    19. мяч_у_своих
    20. противник_на_пути
    21. расстояние_до_игрока*
    22. расстояние_до_мяча
    23. расстояние_до_своих_ворот
    24. расстояние_до_чужих_ворот
    25. рядом_противник
    26. точка_открыта
    27. точка_свободна
    28. цель_задана
    1. бежать
    2. бежать_в_квадрат
    3. бежать_к_мячу
    4. бить_по_воротам
    5. вернуться_на_старт
    6. находиться_на_одной_линии_с_мячом
    7. отправить_мяч
    8. отправить_мяч_в_квадрат
    9. пас_ближнему
    10. пас_игроку
    11. подать_сигнал
    12. стоять
    13. флаги

    Есть ещё специальная команда "лог", которая записывает в файл указанное значение:
    лог:это_тест
    Для левой команды запись идёт в файл logs\1.txt, а для правой в logs\2.txt.

    Макросы (выражения в квадратных скобках)

    В код можно вставлять макросы, которые во время выполнения скрипта заменяются на значения. Например, [X] заменяется на координату X текущего игрока, а [X0] на координату X мяча. Пример, бежать к мячу:
    Если(мяч_свободен){бежать:[X0],[Y0]}
    Пример, пас на ход игроку 4:
    Если(мяч_у_игрока){отправить_мяч:[X4+50],[Y4]}

    Все макросные переменные и функции:

    1. I - возвращает номер текущего игрока.
    2. B - возвращает номер игрока, который владеет мячом (Ball), либо 0, если мяч ничей. Пример, если мяч у противника, то бежать к мячу:
      Если([B>4]){бежать_к_мячу}
    3. Макросная функция N(сигнал). возвращает номер игрока, который подаёт указанный сигнал, либо 0, если нет такого игрока. Пример, отдать пас игроку, подающему сигнал 555, если таковой имеется:
      Если([N(555)>0]){пас_игроку:[N(555)]}
    4. X0 и Y0 - X и Y мяча.
    5. X1-8 и Y1-8 - возвращает X и Y указанного игрока. Пример, отдать пас игроку 2:
      Если(мяч_у_игрока){отправить_мяч:[X2],[Y2]}
    6. X и Y - возвращает X и Y текущего игрока. Пример, если X игрока меньше 200 и Y больше либо равно 100, бежать в точку 358,182:
      Если([X<200 и Y>=100]){бежать:358,182}
    7. R(от,до) - случайное (Random) число в указанном диапазоне. Пример, бежать в случайную точку с X от 400 до 450, и Y от 150 до 200:
      Если(мяч_у_игрока){бежать:[R(400,450)],[R(150,200)]}
    8. D(x1,y1,x2,y2) - расстояние (Distance) между двумя точками. Пример, если расстояние от игрока до ворот (центр ворот - 559,188) противника менее 150 пикселей, то бить по воротам:
      Если([D(X,Y,559,188)<150]){бить_по_воротам}
    9. C(x,y) - возвращает номер игрока, ближнего (Closest) к указанной точке. Пример, пас игроку ближнему к чужим воротам:
      Если(мяч_у_игрока){пас_игроку:[C(559,188)]}
      В данном примере, учитываются только игроки своей команды. Чтобы учитывать только игроков противника, нужно добавить параметр 1:
      Если(мяч_у_игрока){пас_игроку:[C(559,188,1)]}
      Чтобы учитывать игроков из обеих команд, нужно добавить параметр 2:
      Если(мяч_у_игрока){пас_игроку:[C(559,188,2)]}
      Чтобы получить номер игрока, который находится по близости вторым к воротам, то третьим параметром указжите 2 (либо, например, 3, если нужен третий игрок):
      Если(мяч_у_игрока){пас_игроку:[C(559,188,0,2)]}
      Третий параметр 0 значит, что нужно учитывать только игроков своей команды.
    10. A(x1,y1,x2,y2) - угол (Angle), на котором находится точка x2,y2 относительно точки x1,y1. Пример, бить по воротам с указанием угла:
      Если(мяч_у_игрока){отправить_мяч:[A(X,Y,559,188)]^,200}
      Углы двух игроков относительно игрока с мячом:
    11. S1-8 и P1-8 - сигнал игрока (S) и предыдущий сигнал (P). Пример, если игрок 3 сигнализирует 123, то дать ему пас:
      Если([S3=123]){пас_игроку:3}
    12. S и P - сигнал текущего игрока (S) и предыдущий сигнал (P). Пример, если игрок сигнализирует 0 (ничего не сигнализирует), то подать сигнал равный предыдущему + 1:
      Если([S=0]){подать_сигнал:[P+1]}

    Макросы могут содержать операторы: +, -, *, /, >, <, >=, <=, =, <>, и, или, !. Возвращаемые значения могут быть только целыми числами, либо true, false. [7/3] вернёт 2, а не 2.3333.

    Макросы можно использовать внутри условий. Пример, если ближний к воротам игрок открыт, то отдать ему пас: Если(игрок[C(559,188)]_открыт){пас_игроку:[C(559,188)]}
    Нужно понимать, что ближним игроком может оказаться сам текущий игрок, а значит пас самому себе отдавать не надо. Пример с проверкой этого:
    Если([C(559,188)<>I] и игрок[C(559,188)]_открыт){пас_игроку:[C(559,188)]}

    Макросы можно комбинировать
    Пример, получить X игрока, сигнализирующего 555: XN(555). Сначала заменится N(555) и получится, например, X4, которое заменится на X игрока 4. Подстановка значений идёт справа на лево.
    X игрока с мячом: XB. B заменится на номер игрока, и получится, напрмер, X3, которое заменится на X игрока 3.
    Сигнал игрока с мячом: SB.
    Расстояние от игрока 3 до игрока 4: D(X3,Y3,X4,Y4).
    X ближнего к чужим воротам игрока: XC(559,188).

    Макросы могут быть вложенными: [...[...]...].

    Макросы можно кэшировать

    Допустим, надо отправить мяч в случайную точку, проверив открыта ли она. Если написать:
    Если(точка_открыта:[R(100,150)],[R(200,250)]){отправить_мяч:[R(100,150)],[R(200,250)]}
    , то случайные значения X и Y в условии и действии будут разные. Поэтому нужно закэшировать значения в условии и использовать их в действии:
    Если(точка_открыта:[1@R(100,150)],[2@R(200,250)]){отправить_мяч:[1@],[2@]}
    Как видите, для этого в начале макроса добавляется id макроса и символ @. Значение первого макроса записывается в кэш с id 1, а второго c id 2. Потом они извлекаются из кэша макросами [1@] и [2@].
    Ещё пример, если ближний к воротам игрок открыт, то отдать ему пас:
    Если(игрок[1@C(559,188)]_открыт){пас_игроку:[1@]}
    Можно id макроса не указывать (он будет равен 0): Если(игрок[@C(559,188)]_открыт){пас_игроку:[@]}
    Кэш очищается при каждом выполнении кода.

    Полезный пример использования макросов

    Как сделать, чтобы игрок находился на одной линии от мяча до центра ворот. Игрок 4 бегает вверх-вниз, а игрок 3 перемещается по оси Y так, чтобы преградить путь мячу в случае удара:



    Открыть GIF

    Делается это так: бежать:50,[188-(x*(188-y0))/x0]. 50 - это X на которой находиться игроку, а 188 - это Y центра ворот.

    Объяснение:

    Имеем треугольник C-D-E.

    1. Обозначим сторону E-D как A, а сторону C-E как B.
    2. A = X0 (X мяча). B = 188 - Y0 (Y центра ворот минус Y мяча)
    3. Обозначим X игрока как A2, а расстояние от мяча до игрока по оси Y как B2. A2 = X. B2 = ? (нужно найти)
    4. B относится к B2 так же, как A к A2. Отсюда: B2 = A2 * B / A. Т.е.: B2 = X * (188 - Y0) / X0.
    5. Чтобы получить новую координату Y, надо из Y центра ворот вычесть B2.


    Требования к командам для участия в чемпионатах

    1. Название команды, описание и логотип не должны содержать нецензурной лексики, оскорблений, рекламы, контента 18+ и прочих неуместных материалов.
    2. Код команды должен быть рабочим, эффективным и неизбыточным. Также он должен быть относительно уникальным (нельзя добавлять одну и ту же команду с разными названиями).
    3. Пассивная игра не приветствуется. Не разрешается создавать искусственные блокировки мяча. Не разрешается специально выбивать мяч за пределы поля.




    © 2019 FuncBall.com