One of the most enjoyable programming exercises is writing a computer
program that plays a game.
Paper Rock Scissors …
The weeks Ruby quiz involves writing a simple program to play the game
"Paper, Rock, Scissors". Soon after the comments started on the
quiz, someone submitted this 12 line "cheating" program:
class Cheater < Player
def initialize opponent
Object.const_get(opponent).send :define_method, :choose do
:paper
end
end
def choose
:scissors
end
end
It cheats in that it dynamically modifies its opponent object so that it
always returns :paper, making it trivial to beat. While it does cheat, it
does show some clever "thinking outside the box" approach to
playing Paper, Rock, Scissors.
This reminds me of a story …
Greed
A number of years ago, I used to teach C++ in GE’s after hours
education program. One of the projects assigned to the class was writing a
player for the game of Greed. Greed is a simple dice game where you score
points by rolling a set of 5 dice. You can continue to roll as long as you
continue to make points on each roll. However, a row that has no point
value causes you to lose all the points for a turn, so there is
some value in stopping while you are ahead (hence the name Greed).
The game framework handles the dice rolling. All the student’s prgram
had to do was decide whether or not to roll again given the the current
state of the dice.
As part of the course, I pointed out that the encapsulation and data hiding
features of C++ made it difficult to "cheat" by effecting the
framework or other player objects. One particular student took this as a
challenge and announced that he had a "cheating" player program
that stayed within the "rules" setup by the C++ langauge, but yet
would always win.
How did he do it? This cheating player would record the state of the seed
of the standard library’s random number generator. It would then do
trial rolls of the dice until it got a high scoring roll. Then it would
reset the random number seed to the value that produced the high scoring
roll, and indicate to the game framework that it wanted to roll again. The
framework would comply and give the player the high scoring roll that it
was setup to do. The cheating player would win the game in a single turn.
The cheat was easily defeated (once the cheat was understood) by using a
private random number generator that wasn’t accessible to the player
programs. But I learned two things from this exercise:
- Programmers love challenges, especially the kind that say "You
can’t do this …"
- Secure software is hard to create, particularly because of point 1.
comments
|