Рекомендуемая литература
1.Информатика. Задачник-практикум в 2 т./Под ред. И.Г.Семакина, Е.К. Хеннера: Том.2.-М.:-БИНОМ. Лаборатория знаний, 2003.-278 с.:ил.
2.Практикум по логическому программированию: Методические рекомендации для студентов и преподавателей по лабораторному практикуму по курсу «Логическое программирование»/ Сост. Р.И. Баженов, И.И. Раскина. – Омск: Изд-во ОГПУ, 1995. – 85 с.
46
Лабораторная работа №6. Головоломки. Игровые программы. Пример 1. Нарисовать конверт, не отрывая карандаша от бумаги и
не проводя два раза по одной и той же линии. Введем обозначения, ребра – латинскими буквами, вершины - цифрами.
Знания о структуре графа можно представить следующим
образом: rebro(a,1,2), rebro(a,2,1), rebro(b,2,3), rebro(b,3,2), rebro(c,1,3),
rebro(c,1,2), rebro(c,3,1), rebro(d,2,4), rebro(d,4,2), rebro(e,2,5), rebro(e,5,2), rebro(f,3,4), rebro(f,4,3), rebro(g,3,5), rebro(g,5,3), rebro(h,4,5), rebro(h,5,4).
Решением задачи должен явиться список пройденных ребер графа, причем длина его должна быть равна 8, и в нем не должно быть повторяющихся ребер, что можно описать так:
prohod(T,P):-length(P,8),write_list(P),!. prohod(T,P):-rebro(R,T,H), not(member(R,P), prohod(H,[R|P).
T-текущая вершина графа, а P-список пройденных ребер. Первое правило означает, что если длина списка P пройденных вершин становится равной 8, то список P выводится на печать. Это правило ограничивает рекурсивный перебор вершин и ребер, проводимый вторым правилом. Второе правило является генератором перебора, оно перебирает предикаты “rebro()” и находит такое ребро R, из текущей вершины Т в новую H, чтобы оно не принадлежало списку P, зато это ребро добавляется в качестве головы к списку P, и поиск дальнейшего пути производится уже из новой вершины H.
Пример 2. Программа “Угадай число”.
Predicates play_the_game give_info play_it
generate_rand(integer) play_it_sam(integer) test_and_tell(integer,integer) say_you_got_it_right(integer) say_too_big
say_too_small Clauses
play_the_game:-give_info, play_it. /*информация для пользователя*/
give_info:-makewindow(1,7,7,"",0,0,25,80), makewindow(2,7,7,"Угадай число", 2,20,22,45), nl, write("Это игра Угадай число"),
nl, write("Я загадаю число из"),
47
nl, write("интервала [1,100]"),
nl, write("Я буду подсказывать больше"),
nl, write("или меньше задуманное число"),nl,
nl, write("Кода будешь готовнажми space bar"), nl,readchar(_),
clearwindow.
/*выполнение игры*/ play_it:-generate_rand(A),
play_it_sam(A).
/*генерация случайного числа*/ generate_rand(X):-
random(R),
X=1+R*100,
nl,write("Я загадал число"), nl,write("Теперь дело за Вами"),nl.
/*запрос к пользователю */ play_it_sam(X):-
nl, write ("Введите свой вариант"), nl, readint(G),
test_and_tell(X,G), play_it_sam(X).
/* проверка и выдача результата*/ test_and_tell(X,X):- say_you_got_it_right(X),!. test_and_tell(X,Y):- X>Y, say_too_big,!. test_and_tell(_,_):- say_too_small.
/*выдача сообщений*/ say_too_big:-nl, write("Загаданное число больше").
say_too_small:-nl, write("Загаданное число меньше"). say_you_got_it_right(X):-nl, write("Вы правы"),
nl,write("Я загадал ",X),
nl, write("До новых встреч!"), nl, write("Нажмите space bar"), nl,readchar(_),
Goal
play_the_game.
exit.
Пример 3. Игра Баше – 23 спички. На столе 23 спички, 2 игрока по очереди берут от 1 до 3 спичек, проигравшим считается тот, кто возьмет последнюю спичку.
Predicates play_the_game do_windows
play(integer,integer,integer) play_it_again(integer,integer,integer) real_int(real,integer)
Clauses
play_the_game:-do_windows,play(23,0,0).
/*правило для образования окон*/ do_windows:-makewindow(1,7,7,"",0,0,25,80),
makewindow(2,7,7,"Игра 23 спички", 1,5,22,40), nl, write("Добро пожаловать!"),
M=23, H=0, C=0,
nl, write("Всего ",M," спички" ),
nl, write("По очереди мы будем перемещать " ), nl, write("спички в свои кучки"),
48
nl, write("За раз можно взять 1, 2, 3 спички"),nl,
nl, write("Проиграет, тот кто заберет последнюю спичку"), nl, write("Итак, начнем, всего ", M, "сп."),nl,
nl, write("я взял ",C," сп. Вы взяли ",H, " сп."),nl. play(M,H,C):-play_it_again(M,H,C).
/*правило определения победителя*/ play_it_again(M,_,_):-
M<=0,
nl, write("Вы выиграли!"),
nl, write("Нажмите любую клавишу для выхода"), readchar(_), clearwindow,!,exit.
play_it_again(1,_,_):-
nl, write("Я выиграл!"),
nl, write("Нажмите любую клавишу для выхода"), readchar(_), clearwindow,!,exit.
play_it_again(M,_,_):-
nl, write("Ваш ход"),
nl, write("Сколько спичек вы хотите взять?"), readint(Hn),
M2=M-Hn, H2=Hn, write("Осталось ",M2,"сп."), nl,write("Мой ход"), random(F), Rea=1+3*F, real_int(Rea,Rint), M3=M2-Rint,
nl, write("Я беру ",Rint," сп."),
nl, write("Осталось ",M3, " сп."),nl, M7=M3,H7=H2,C7=Rint, play_it_again(M7,H7,C7). /*вспомогательное правило*/
real_int(Re,In):-In=trunc(Re). Goal
play_the_game
Задания для самостоятельной работы
1)Отгадать число, загаданное компьютером, максимум за 3 попытки.
2)23 спички. Разработать выигрышную стратегию для компьютера.
3)Имеется два сосуда – на 3 и 5 литров. Как отмерить с их помощью 4 литра воды?
4)Решите задачу о перевозке фермером через реку волка, козы, капусты.
5)Раскрасить плоскую карту так, чтобы никакие две смежные области на ней не были раскрашены в одинаковый цвет. В наборе 4 цвета.
49
Таблица 9.
Поле для раскраски
|
a |
|
b |
c |
d |
e |
|
f |
6) Лабиринт задан матрицей соединений, в которой для каждой пары комнат указано, соединены ли они коридором. Построить путь перехода из комнаты “a” в комнату “g”:
Таблица 10.
Поле для лабиринта
|
A |
B |
C |
D |
E |
F |
G |
A |
- |
1 |
0 |
0 |
0 |
0 |
0 |
B |
1 |
- |
1 |
0 |
1 |
0 |
0 |
C |
0 |
1 |
- |
1 |
0 |
0 |
0 |
D |
0 |
0 |
1 |
- |
1 |
0 |
0 |
E |
0 |
1 |
0 |
1 |
- |
0 |
0 |
F |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
G |
0 |
0 |
0 |
0 |
1 |
0 |
- |
7)Имеется n городов. Некоторые из них соединены дорогами известной длины. Вся система дорог задана квадратной матрицей n*n, элемент aij<0, если между городами дороги нет, в противном случае равен расстоянию между городами.
8)Задан лабиринт. Напишите программу для нахождения маршрутов для выхода из этого лабиринта. Начало маршрута точка О. Закрашенная клетка – стена.
Таблица 11.
О
50