Здравствуйте.
Еще осенью на 2 курсе в качестве лабораторной работы по «Теории автоматов» преподаватель на ходу придумывал нам задания, ориентируяюсь на наши пожелания в оценке. В основном это были игры. Кому-то достался хоккей, кому-то теннис, мне же досталась не столь известная логическая игра «Быки и коровы».

Нужно было реализовать хоть какое-то обоснованное поведение компьютера в игре с человеком. Но я пошел дальше и уже через месяц компьютер в большинстве случаев легко обыгрывал моих однокурсников. А по предмету был получен автомат. Программу получите после описания алгоритмов.
Игрок и компьютер загадывают четырехзначные числа, используя цифры от 0 до 9. Игроки пытаются разгадать числа соперника, посылая ему возможные варианты чисел, в ответ получая два числа — число «быков» и число «коров». Что же это за числа такие?
Для понимания приведу пример:
Оперируя данными о «скоте» противника, нужно угадать число быстрей него.
Первый же тривиальный алгоритм, который так и напрашивается, — это перебирать наборы «1111», «2222», «3333»... до тех пор, пока не будет получен полный набор, а затем генерировать перемещения этого набора.
Очевидно, что алгоритм не очень хорош, зато понятный и не запутаться. Максимальное число ходов для угадывания — 10(«7890»)+24 перестановки. 34 — это в самом худшем случае. Конечно возможно перебор и перестановки всячески оптимизировать, например перебирать поочередно с двух концов — «1111», «0000», «2222», «9999»... так же оптимизировать генерацию перестановок при наличии одинаковых цифр(как в нашем примере — несколько раз спрашиваем одно и то же).
Но не будем этим заниматься. Пусть данная стратегия будет у нас легким уровнем сложности компьютера.
Много я сидел на парах и играл сам с собой, пытаясь придумать какой то свой крутой алгоритм. Но приходили только единичные идеи, из которой я не мог составить единой стратегии. Начал изучать литературу. Наткнулся на статьи, рода «угадывание за 7 ходов». Они меня не привлекли, поскольку там очень много ветвления. Но прочитав книгу нашего Кировского профессора(но не из нашего университета) С.М. Окулова «Программирование в алгоритмах», я нашел описание довольно простого и достаточно эффективного алгоритма. В нем используется так называемый «метод решета» (примером может служить известное «решето Эрастофена» — классическая задача поиска простых чисел). Мы рассматриваем конечное множество всех возможных чисел и каждый ход исключаем все элементы множества, не представляющие интереса.
Начнем со структур данных. Код на паскале:
Инициализация:
Функция, реализующая анализ элемента множества по значениям переменных (bk,kr — быки и коровы)
таким образом после каждого нашего хода запускаем решето
В заключение можно сказать, что алгоритм затратен к памяти и по сравнению со стандартными алгоритмами будет думать «дольше», но насколько же он проще и вполне оптимизируется.
Ну вот и все, совсем не сложно. Первая моя статья, судить строго.
Как и обещал, ссылка на мою игрульку со второго курса, чтоб на себе почувствовать метод «решета»:
Быки и коровы
Еще осенью на 2 курсе в качестве лабораторной работы по «Теории автоматов» преподаватель на ходу придумывал нам задания, ориентируяюсь на наши пожелания в оценке. В основном это были игры. Кому-то достался хоккей, кому-то теннис, мне же досталась не столь известная логическая игра «Быки и коровы».

Нужно было реализовать хоть какое-то обоснованное поведение компьютера в игре с человеком. Но я пошел дальше и уже через месяц компьютер в большинстве случаев легко обыгрывал моих однокурсников. А по предмету был получен автомат. Программу получите после описания алгоритмов.
Суть игры
Игрок и компьютер загадывают четырехзначные числа, используя цифры от 0 до 9. Игроки пытаются разгадать числа соперника, посылая ему возможные варианты чисел, в ответ получая два числа — число «быков» и число «коров». Что же это за числа такие?
- «Быки» — правильные цифры на правильных местах. Четыре «быка» — залог победы, мечта каждого фермера.
- «Коровы» — правильные цифры на неправильных местах.
Для понимания приведу пример:
Загадано число 1622. Если мы предположим 6112, то в ответ придет: 1 бык(четвертая цифра «2» на своем месте), 2 коровы(шестерка и единица не на своих местах).
Оперируя данными о «скоте» противника, нужно угадать число быстрей него.
Первый же тривиальный алгоритм, который так и напрашивается, — это перебирать наборы «1111», «2222», «3333»... до тех пор, пока не будет получен полный набор, а затем генерировать перемещения этого набора.
Например, загадано то же число 1622, мы предполагаем «1111», получаем в ответ «быка», затем «2222» — получаем в ответ уже 2 «быков», «3333» — пусто, «4444» — пусто, «5555» — пусто, «6666» — 1 бык.
Дальше продолжать не будем, так как набралось уже 4 быка в сумме. Осталось найти нужную комбинацию. Будем генерировать перестановки, пока не получим Та-дааам: «1226», «1262», «1226», «1262», «1622». Все.
Очевидно, что алгоритм не очень хорош, зато понятный и не запутаться. Максимальное число ходов для угадывания — 10(«7890»)+24 перестановки. 34 — это в самом худшем случае. Конечно возможно перебор и перестановки всячески оптимизировать, например перебирать поочередно с двух концов — «1111», «0000», «2222», «9999»... так же оптимизировать генерацию перестановок при наличии одинаковых цифр(как в нашем примере — несколько раз спрашиваем одно и то же).
Но не будем этим заниматься. Пусть данная стратегия будет у нас легким уровнем сложности компьютера.
Много я сидел на парах и играл сам с собой, пытаясь придумать какой то свой крутой алгоритм. Но приходили только единичные идеи, из которой я не мог составить единой стратегии. Начал изучать литературу. Наткнулся на статьи, рода «угадывание за 7 ходов». Они меня не привлекли, поскольку там очень много ветвления. Но прочитав книгу нашего Кировского профессора(но не из нашего университета) С.М. Окулова «Программирование в алгоритмах», я нашел описание довольно простого и достаточно эффективного алгоритма. В нем используется так называемый «метод решета» (примером может служить известное «решето Эрастофена» — классическая задача поиска простых чисел). Мы рассматриваем конечное множество всех возможных чисел и каждый ход исключаем все элементы множества, не представляющие интереса.
Например, для загаданного числа 1234 мы предположили 5678, и получили 0 быков и 0 коров, чего думать — мы исключаем все числа, содержащие 5, 6, 7, 8. Сразу можете прикинуть, сколько отнимется из 10000. Не стоит пугаться множества из 10000 элементов. За 5-6 ходов останется всего несколько чисел.
Начнем со структур данных. Код на паскале:
Const Pmax=10000; Type Post=string[4]; Var A:array[1..Pmax] of Post; //множество B:array[1..Pmax] of boolean; // массив флажков, 1 - значит подходит, 0 - исключено
Инициализация:
t:=1; for i:=0 to 9 do for j:=0 to 9 do for k:=0 to 9 do for l:=0 to 9 do begin a[t]:=inttostr(i)+inttostr(j)+inttostr(k)+inttostr(l); // формируем множество inc(t); end; for i:=1 to pmax do b[i]:=true; // по умолчанию все числа подходят
Функция, реализующая анализ элемента множества по значениям переменных (bk,kr — быки и коровы)
function pr(a,b:post;bk,kr:integer):boolean; //b - наш ход, a- элемент "тестируемого" множества var i,x:integer; begin x:=0; for i:=1 to 4 do // проверка по быкам if a[i]=b[i] then inc(x); if x<>bk then begin pr:=false; exit; end; x:=0; for i:=1 to 4 do // проверка по коровам if (a[i]<>b[i]) and (pos(b[i],a)<>0) then inc(x); if x<kr then begin pr:=false; exit; end; pr:=true; end;
таким образом после каждого нашего хода запускаем решето
for i:=1 to Pmax do if b[i] and not pr(a[i],hod,bk,kr) then b[i]:=false;
В заключение можно сказать, что алгоритм затратен к памяти и по сравнению со стандартными алгоритмами будет думать «дольше», но насколько же он проще и вполне оптимизируется.
Ну вот и все, совсем не сложно. Первая моя статья, судить строго.
Как и обещал, ссылка на мою игрульку со второго курса, чтоб на себе почувствовать метод «решета»:
Быки и коровы
