Опубликован: 12.02.2014 | Уровень: для всех | Доступ: платный
Лекция 14:

Игры

< Лекция 13 || Лекция 14: 123 || Лекция 15 >
Аннотация: Рассматриваются игры "Ползунок", "Поле чудес" и "Отгадай числа". В топологической игре "Ползунок" пользователь играет с компьютером. Поле для игры невелико, поэтому выигрышные ходы, в случаях, когда они существуют, находятся с помощью перебора возможных продолжений игры. В игре "Поле чудес" пользователь отгадывает слово, загаданное компьютером. "Отгадай числа" – это игра пользователя с компьютером, в которой участники отгадывают наборы чисел, загаданные противниками. Стратегия компьютера реализуется с помощью генерации варианта хода и отбрасывания вариантов, которые не согласуются с результатами предыдущих ходов компьютера.
Ключевые слова: поле, пользователь, слово, игра

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

14.1. Топологическая игра "Ползунок"

Топологическая игра "Ползунок" заключается в следующем. Игра ведется на решетке размером 5 на 6 клеток (рис. 14.1).

 Партия топологической игры "Ползунок"

Рис. 14.1. Партия топологической игры "Ползунок"

Участники ходят по очереди. Игрок проводит отрезок прямой длиной в одну клетку, достраивая ломаную с одного из концов. Получающаяся траектория (ломаная) должна быть непрерывной, причем ход можно делать с любого ее конца. Игрок, который замыкает траекторию, т. е. ходит так, что попадает одним из концов отрезка на ломаную, выигрывает. На рис 14.1 показана позиция, выигрышная для первого игрока (он проводит отрезки светлым карандашом). Ходом в клетку (1; 3) этот игрок замыкает траекторию.

Приведенная ниже программа — это реализация игры человека с компьютером. Для поиска выигрышной стратегии компьютера используется метод ван Эмдена (в [5, 14] он применяется в игре "Ним"): игрок делает выигрышный ход (замыкает траекторию) или ходит так, чтобы его противник не выиграл. Если противник (человек) не знает, каким образом нужно ходить, чтобы выиграть, то компьютер в результате обязательно выигрывает. Если же компьютер находится в проигрышной позиции и не может найти такой ход, то он пытается сходить так, чтобы его противник не выиграл на следующем же шаге. Если противник ошибется хотя бы один раз и не сделает правильный ход, то компьютер выиграет.

    open core, console, console_native

class facts
    humanCell: (coord).

class predicates
    winMove: (positive, positive, coord*, coord*) nondeterm (i,i,i,o).
    step: (coord*, coord*, coord) nondeterm (i,o,o) (i,o,i).
    next: (coord, coord) nondeterm (i,o) (i,i).
    move: (positive, coord*).
    show: (coord*).
    loseMove: (coord*) determ.
clauses
    loseMove(Polyline):-
        step(Polyline, _, Cell),
        list::isMember(Cell, Polyline),
        !.

    winMove(_Player1, _Player2, Polyline, Polyline1):-
        step(Polyline, Polyline1, Cell),
        list::isMember(Cell, Polyline).
    winMove(Player1, Player2, Polyline, Polyline1):-
        step(Polyline, Polyline1, _),
        not(winMove(Player2, Player1, Polyline1, _)).

    move(2, Polyline):-
        step(Polyline, Polyline1, Cell),
        list::isMember(Cell, Polyline),
        !,
        show(Polyline1),
        setLocation(coord(0, 14)),
        write("Компьютер выиграл!\n\n", Polyline1).
    move(2, Polyline):-
        winMove(2, 1, Polyline, Polyline1),
        !,
        move(1, Polyline1).
    move(2, Polyline):-
        step(Polyline, Polyline1, _),
        not(loseMove(Polyline1)),
        !,
        move(1, Polyline1).
    move(2, Polyline):-
        step(Polyline, Polyline1, _),
        !,
        move(1, Polyline1).
    move(1, Polyline):-
        show(Polyline),
        setLocation(coord(0, 14)),
        write(Polyline),
        std::repeat(),
            write("\n\nВаш ход.\nВведите новую клетку в виде"
                " coord(2,3): "),
            hasDomain(coord, Cell),
            Cell = read(), clearInput(),
        step(Polyline, Polyline1, Cell),
        assert(humanCell(Cell)),
        !,
        if list::isMember(Cell, Polyline) then
            write("\nПоздравляю! Вы выиграли!")
        else
            move(2, Polyline1)
        end if.
    move(_, _).

    step([A, B | Polyline], [X, A, B | Polyline], X):-
        next(A, X),
        not(X = B).
    step(Polyline, list::append(Polyline, [X]), X):-
        [A, B | _] = list::reverse(Polyline),
        next(A, X),
        not(X = B).

    next(coord(X, Y), coord(X - 1, Y)):- X > 1.
    next(coord(X, Y), coord(X + 1, Y)):- X < 6.
    next(coord(X, Y), coord(X, Y - 1)):- Y > 1.
    next(coord(X, Y), coord(X, Y + 1)):- Y < 5.

    show(Polyline):-
        clearOutput(),
        foreach I = std::fromTo(1, 6) do
            setLocation(coord(3 * I, 0)), write(I)
        end foreach,
        foreach J = std::fromTo(1, 5) do
            setLocation(coord(0, 2 * J)), write(J)
        end foreach,
        Attr0 = getTextAttribute(),
        foreach coord(X, Y) = list::getMember_nd(Polyline) do
            Attr = if humanCell(coord(X, Y)), ! then 13 else 11 end if,
            setTextAttribute(Attr),
            setLocation(coord(3 * X, 2 * Y)), write("*")
        end foreach,
        setTextAttribute(Attr0).

    run():-
        write("Кто ходит первым? (1 - человек, 2 - компьютер): "),
        Player = read(), clearInput(),
        if Player = 1 then
            write("Введите начало отрезка в виде coord(3,3): "),
            hasDomain(coord, Cell1),
            Cell1 = read(), clearInput(),
            write("Введите конец отрезка: "),
            hasDomain(coord, Cell2),
            Cell2 = read(), clearInput(),
            next(Cell1, Cell2),
            assert(humanCell(Cell1)),
            assert(humanCell(Cell2)),
            move(2, [Cell1, Cell2])
        else
            move(1, [coord(3, 3), coord(4, 3)])
         end if,
         !,
        _ = readLine();
        write("Ошибка ввода"),
        _ = readLine().
Пример 14.1. Игра "Ползунок"

Предикат hasDomain/2 связывает переменную с именем домена. Предикат getTextAttribute возвращает текущие атрибуты текста окна консоли.

Метод ван Эмдена может быть использован только для полей небольших размеров, так как перебор во время поиска выигрышного хода делается довольно большой. Подробный разбор, демонстрирующий этапы проектирования и компьютерной реализации топологической игры "Ползунок", как в консольных, так и в GUI-приложениях на языке Visual Prolog, проделал В. А. Юхтенко (PDC SPb) [12].

< Лекция 13 || Лекция 14: 123 || Лекция 15 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.

Айдана Ахметова
Айдана Ахметова
Россия
Дмитрий Куянов
Дмитрий Куянов
Россия, Омск, ОмГТУ