Читаем Программирование игр и головоломок полностью

Т0: соединить два промежуточных результата между собой случайным образом выбранным знаком.

Рисунок 35 дает граф этого автомата, где стрелки показывают операции, которые нужно выполнить, чтобы перейти от одного состояния к другому. Ваша программа должна реализовать этот автомат, причем переходы должны выбираться случайным образом, если это возможно.

Вы теперь знаете все. Конечные автоматы часто встречаются в программировании. Запомните этот пример, он имеет очень широкую область применения…

Игра 13.

Проблема наиболее длинного пути взятия является типичной возвратной задачей. Когда лиса находится в некотором положении, нужно испытать 4 возможных направления и для каждого из них увидеть, есть ли курица и свободно ли следующее за ней поле. Это легко!

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

Если вы обнаружили возможное взятие, то результат есть наиболее длинное взятие, возможное при этом новом исходном положении, увеличенное на 1.

Но вы можете также действовать итеративным способом. Вы делаете первое взятие и продолжаете дальнейшие исследования, исходя из этого поля прибытия. Нужно испытать все возможности. Вы снова получаете, таким образом, тип задач, известный по головоломке 8. Упорядочьте четыре направления перемещения. Вы исходите из некоторого положения с направлением перемещения i = 1.

Если все четыре направления испытаны, то все закончено.

В противном случае вы смотрите, возможно ли взятие в направлении i:

— если невозможно, то вы увеличиваете i на 1 и возвращаетесь для нового цикла;

— если возможно, то вы выполняете это взятие, оказываетесь в новом положении и начинаете заново, исходя из него.

Внимание: нужно иметь возможность отменять сделанные вами взятия, потому что они происходят в рамках исследования… Это требует некоторой ловкости. По этой причине рассматриваемая игра — не из самых легких.

Остальное вы исследуете совершенно самостоятельно.

Игра 14.

Ничего нового с точки зрения программирования, за исключением того, что нужно исследовать восемь направлений перемещения вместо четырех.

4. Игры со стратегией

Игра 16. Числа Спрага-Грюнди

В большинстве нижеследующих игр два игрока делают ходы по очереди, и выигрывает тот, кто достигает некоторой намеченной в начале игры позиции. В той игре, которую мы обсуждаем сейчас, позиция может быть полностью охарактеризована числом оставшихся спичек, и выигрывающая позиция соответствует числу спичек, равному нулю. Спраг и Грюнди предложили (соответственно в 1936 и 1939 годах) связывать с каждой игровой позицией неотрицательное целое число следующим образом:

— выигрывающей позиции вы сопоставляете 0;

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

Образуем числа Спрага-Грюнди для этой игры.

Позиции 0 сопоставляется число 0, SG (0) = 0.

Исходя из 1, можно получить 0 (поскольку мы имеем право удалить одну спичку[19]. Следовательно, SG(1) — наименьшее неотрицательное целое, отличное от 0, или SG(1) = 1. Исходя из 2, можно получить 1 и 0. Следовательно, SG(2) — наименьшее неотрицательное целое, отличное от 0 и 1, поэтому SG(2) = 2.

Так как можно удалять спички вплоть до 6, то точно так же имеем

SG(3) = 3, SG(4) = 4, SG(5) = 5, SG(6) = 6.

Предположим теперь, что имеется 7 спичек. Можно удалить от 1 до 6. Поэтому в результате можно получить от 6 до 1 спичек, но не 0. Число SG(7) — наименьшее неотрицательное целое, отличное от 1, 2, 3, 4, 5, 6, Следовательно, это 0.

SG(7) = 0,

А теперь из 8 можно получить от 2 до 7, поэтому SG(8) — это не 2, не 3, …, не 6 и не 0, поэтому оно равно 1.

SG(8) = 1.

Теперь вы можете установить общий закон:

SG(p) = остаток от деления p на 7.

Как же выигрывать?

Если вы после своего хода можете оставить кучу, для которой число Спрага-Грюнди равно 0, то ваш противник не сможет достичь ситуации с числом нуль, поскольку по определению число, которое он оставит, отлично от исходного числа. Поскольку он не сможет достичь ситуации p с SG (p) = 0, то он и не может выиграть. Ему придется оставить вам ситуацию с SG(p) ≠ 0, исходя из которой, вы всегда сможете получить ситуацию с числом Спрага-Грюнди, равным нулю. Следовательно, вам нужно оставлять вашему противнику число спичек с числом SG, равным нулю, иначе говоря, число спичек, кратное 7.

Одно из двух: либо ваш противник не знает этого правила и играет «по нюху»; при первой возможности вы оставляете ему кратное 7 и из ежовых рукавиц не выпускаете; либо он знает правило и ходит первым: он достигает кратного 7. Вы не сможете выиграть, если он не рассеян или не сделает ошибки в счете. Но компьютер не рассеян и не делает ошибок в счете (если ваша программа верна)…

Игра 17.

Перейти на страницу:

Похожие книги

Programming with POSIX® Threads
Programming with POSIX® Threads

With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications. The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O. This book offers an in-depth description of the IEEE operating system interface standard, POSIX (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset. Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.

David Butenhof

Программирование, программы, базы данных
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Эта книга представляет собой перевод третьего издания американского бестселлера Effective C++ и является руководством по грамотному использованию языка C++. Она поможет сделать ваши программы более понятными, простыми в сопровождении и эффективными. Помимо материала, описывающего общую стратегию проектирования, книга включает в себя главы по программированию с применением шаблонов и по управлению ресурсами, а также множество советов, которые позволят усовершенствовать ваши программы и сделать работу более интересной и творческой. Книга также включает новый материал по принципам обработки исключений, паттернам проектирования и библиотечным средствам.Издание ориентировано на программистов, знакомых с основами C++ и имеющих навыки его практического применения.

Скотт Майерс , Скотт Мейерс

Программирование, программы, базы данных / Программирование / Книги по IT