Пушкарева Люба, ЛХФ 4-5

Решение числового ребуса в среде CLIPS


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

Задание:

КНИГА * 3 = НАУКА

Постановка задачи:

  1. Найти соответствие между буквами и цифрами.
  2. Разным буквам соответствуют разные цифры.
  3. В результате выполнения арифметических операций над числами, которые заменят буквы ребуса, должно получиться число после знака «=».
  4. Число не может начинаться с цифры 0.

Реализация задачи в среде CLIPS

Первый шаг:

Представим ребус в более удобном для восприятия виде:

    КНИГА
*
	3
-----------
=   НАУКА

Вместо слов КНИГА, 3 и НАУКА необходимо подобрать такие цифры, чтобы получилось математически верное выражение. Причём, разным буквам должны соответствовать разные цифры.

Рассмотрим разряды всех трёх чисел. Будем считать, что первый разряд – это единицы, второй – десятки, третий – сотни и т.д.

Таким образом, наш числовой ребус поразрядно можно представить следующим образом:

К5 Н4 И3 Г2 А1
* 31

= Н5 А4 У3 К2 А1

Второй шаг:

Для начала создадим правило, которое будет выполнять следующие задачи:

В CLIPS данное правило будет выглядеть следующим образом:
; Вывод на экран формулировки числового ребуса
; Занесение в список фактов, соответствующих буквам и цифрам
; Это правило выполняется всегда, поэтому его условная часть пуста
(defrule startup
	=>
	(printout t "The problem is" t)
	(printout t "    xxxxx" " | KNIGA" t)
	(printout t " *      x" " |     3" t)
	(printout t "   --------- | ------" t)
	(printout t " =  xxxxx" " | NAUKA" t)
	(assert (number 0) (number 1) (number 2) (number 3) (number 4) 
			(number 5) (number 6) (number 7) (number 8) (number 9)
			(letter A) (letter G) (letter I) (letter K) (letter N) 
			(letter U) (letter Z)
	)
)

Третий шаг:

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

; Правило, согласно которому в список фактов будут занесены все возможные 
; комбинации из одной буквы и одной цифры (например, комбинации А0...А9, G0...G9 и т.д.)
(defrule generate
	(number ?x)
	(letter ?y)
	=>
	(assert (combination ?y ?x))
)
Согласно данному правилу, если в списке фактов присутствуют факты, имеющие вид (number ?x) (letter ?y) , где вместо переменных стоят вполне конкретные значения, в список фактов добавляется еще один факт (combination ?y ?x), в котором вместо переменных стоят значения из фактов.

В результате выполнения данного правила будут сформированы комбинации от А0…А9 до Z0…Z9.

Четвёртый шаг:

Далее формируем третье правило. Оно реализует следующие задачи:

Внутри правила осуществляется формирование всех возможных комбинаций путём поразрядного сравнения всех букв числового ребуса.
; Правило, которое позволяет найти среди фактов те, которые удовлетворяют условию задачи 
; и выводит на экран полученное решение (или решения, если их несколько) 
(defrule find-solution
	(combination A ?a)
	(combination Z ?z&~?a)
	(test (= (mod (* ?a ?z) 10) ?a))
	
	(combination G ?g&~?a&~?z)
	(combination K ?k&~?a&~?z&~?g)
	(test (= (mod (+ (* ?a ?z)  
			(* (* ?g ?z) 10)) 
		  	100)
		(+ (* 10 ?k) ?a)))

	(combination I ?i&~?a&~?z&~?g&~?k)
	(combination U ?u&~?a&~?z&~?g&~?k&~?i)
	(test (= (mod (+ (* ?a ?z) 
		         (* (* ?g ?z) 10)
			 (* (* ?i ?z) 100)) 
			 1000)
		(+ (* 100 ?u) (* 10 ?k) ?a)))

	(combination N ?n&~?a&~?z&~?g&~?k&~?i&~?u)
	(test (= (mod (+ (* ?a ?z) 
		          (* (* ?g ?z) 10)
			      (* (* ?i ?z) 100)
			      (* (* ?n ?z) 1000)
			      (* (* ?k ?z) 10000)) 
			      100000)
		(+ (* 10000 ?n) (* 1000 ?a) (* 100 ?u) (* 10 ?k) ?a)))

	(test (> ?k 0))
	(test (> ?n 0))
  =>
  (printout t "Solution is:" t t)
  (printout t "  K = " ?k t)
  (printout t "  N = " ?n t)
  (printout t "  I = " ?i t)
  (printout t "  G = " ?g t)
  (printout t "  A = " ?a t)
  (printout t "  U = " ?u t)
  (printout t "  Z = " ?z t)
  (printout t t)
  (printout t "   " ?k ?n ?i ?g ?a " | KNIGA" t)
  (printout t " * "             ?z " |     3" t)
  (printout t "   " "-----------------------" t)
  (printout t " = " ?n ?a ?u ?k ?a " | NAUKA" t t)
) 	
В терминах CLIPS комбинации из одной буквы и одной цифры можно представить в виде фактов:
	(combination A ?a)
	(combination Z ?z&~?a)
	(test (= (mod (* ?a ?z) 10) ?a))
Здесь: Следующие указания в правиле дают ограничение на значения первых цифр:
	(test (> ?k 0))
	(test (> ?n 0))
	(test (> ?z 0))
То есть, эта конструкция обеспечивает выполнение начального условия: число не может начинаться с цифры 0.

Полный текст программы

; Вывод на экран формулировки числового ребуса
; Занесение в список фактов, соответствующих буквам и цифрам
; Это правило выполняется всегда, поэтому его условная часть пуста
(defrule startup
	=>
	(printout t "The problem is" t)
	(printout t "    xxxxx" " | KNIGA" t)
	(printout t " *      x" " |     3" t)
	(printout t "   --------- | ------" t)
	(printout t " =  xxxxx" " | NAUKA" t)
	(assert (number 0) (number 1) (number 2) (number 3) (number 4) 
			(number 5) (number 6) (number 7) (number 8) (number 9)
			(letter A) (letter G) (letter I) (letter K) (letter N) 
			(letter U) (letter Z)
	)
)

; Правило, согласно которому в список фактов будут занесены все возможные 
; комбинации из одной буквы и одной цифры (например, комбинации А0...А9, G0...G9 и т.д.)
(defrule generate
	(number ?x)
	(letter ?y)
	=>
	(assert (combination ?y ?x))
)

; Правило, которое позволяет найти среди фактов те, которые удовлетворяют условию задачи 
; и выводит на экран полученное решение (или решения, если их несколько) 
(defrule find-solution
	(combination A ?a)
	(combination Z ?z&~?a)
	(test (= (mod (* ?a ?z) 10) ?a))
	
	(combination G ?g&~?a&~?z)
	(combination K ?k&~?a&~?z&~?g)
	(test (= (mod (+ (* ?a ?z)  
			(* (* ?g ?z) 10)) 
		  	100)
		(+ (* 10 ?k) ?a)))

	(combination I ?i&~?a&~?z&~?g&~?k)
	(combination U ?u&~?a&~?z&~?g&~?k&~?i)
	(test (= (mod (+ (* ?a ?z) 
		         (* (* ?g ?z) 10)
			 (* (* ?i ?z) 100)) 
			 1000)
		(+ (* 100 ?u) (* 10 ?k) ?a)))

	(combination N ?n&~?a&~?z&~?g&~?k&~?i&~?u)
	(test (= (mod (+ (* ?a ?z) 
		          (* (* ?g ?z) 10)
			      (* (* ?i ?z) 100)
			      (* (* ?n ?z) 1000)
			      (* (* ?k ?z) 10000)) 
			      100000)
		(+ (* 10000 ?n) (* 1000 ?a) (* 100 ?u) (* 10 ?k) ?a)))

	(test (> ?k 0))
	(test (> ?n 0))
	(test (> ?z 0))
  =>
  (printout t "Solution is:" t t)
  (printout t "  K = " ?k t)
  (printout t "  N = " ?n t)
  (printout t "  I = " ?i t)
  (printout t "  G = " ?g t)
  (printout t "  A = " ?a t)
  (printout t "  U = " ?u t)
  (printout t "  Z = " ?z t)
  (printout t t)
  (printout t "   " ?k ?n ?i ?g ?a " | KNIGA" t)
  (printout t " * "             ?z " |     3" t)
  (printout t "   " "-----------------------------" t)
  (printout t " = " ?n ?a ?u ?k ?a " | NAUKA" t t)
) 	

Запуск программы в среде CLIPS

  1. Запускаем CLIPS



  2. Выполняем ряд команд для запуска программы



  3. Наблюдаем результат



  4. Программа нашла все возможные комбинации и вывела на экран только те, которые удовлетворяют условиям задачи.