mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-12 13:15:18 -08:00
add 00_Alternate_Langage folder and move alternate ports there
This commit is contained in:
3
00_Alternate_Languages/90_Tower/python/README.md
Normal file
3
00_Alternate_Languages/90_Tower/python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Python](https://www.python.org/about/)
|
||||
171
00_Alternate_Languages/90_Tower/python/tower.py
Normal file
171
00_Alternate_Languages/90_Tower/python/tower.py
Normal file
@@ -0,0 +1,171 @@
|
||||
import sys
|
||||
|
||||
|
||||
class Disk:
|
||||
def __init__(self, size):
|
||||
self.__size = size
|
||||
|
||||
def size(self):
|
||||
return self.__size
|
||||
|
||||
def print(self):
|
||||
print("[ %s ]" % self.size())
|
||||
|
||||
|
||||
class Tower:
|
||||
def __init__(self):
|
||||
self.__disks = []
|
||||
|
||||
def empty(self):
|
||||
return len(self.__disks) == 0
|
||||
|
||||
def top(self):
|
||||
if self.empty():
|
||||
return None
|
||||
else:
|
||||
return self.__disks[-1]
|
||||
|
||||
def add(self, disk):
|
||||
if not self.empty():
|
||||
t = self.top()
|
||||
if disk.size() > t.size():
|
||||
raise Exception(
|
||||
"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!"
|
||||
)
|
||||
self.__disks.append(disk)
|
||||
|
||||
def pop(self):
|
||||
if self.empty():
|
||||
raise Exception("empty pop")
|
||||
return self.__disks.pop()
|
||||
|
||||
def print(self):
|
||||
r = "Needle: [%s]" % (", ".join([str(x.size()) for x in self.__disks]))
|
||||
print(r)
|
||||
|
||||
|
||||
print(
|
||||
"""
|
||||
IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.
|
||||
3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,
|
||||
7 THE NEXT, AND SO ON, UP TO 15. IF YOU DO THE PUZZLE WITH
|
||||
2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15. WITH 3 DISKS
|
||||
THE CODE NAMES WOULD BE 11, 13 AND 15, ETC. THE NEEDLES
|
||||
ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3. WE WILL
|
||||
START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM
|
||||
TO NEEDLE 3.
|
||||
|
||||
GOOD LUCK!
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self):
|
||||
# use fewer sizes to make debugging easier
|
||||
# self.__sizes = [3, 5, 7] # ,9,11,13,15]
|
||||
self.__sizes = [3, 5, 7, 9, 11, 13, 15]
|
||||
|
||||
self.__sizes.sort()
|
||||
|
||||
self.__towers = []
|
||||
self.__moves = 0
|
||||
self.__towers = [Tower(), Tower(), Tower()]
|
||||
self.__sizes.reverse()
|
||||
for size in self.__sizes:
|
||||
disk = Disk(size)
|
||||
self.__towers[0].add(disk)
|
||||
|
||||
def winner(self):
|
||||
return self.__towers[0].empty() and self.__towers[1].empty()
|
||||
|
||||
def print(self):
|
||||
for t in self.__towers:
|
||||
t.print()
|
||||
|
||||
def moves(self):
|
||||
return self.__moves
|
||||
|
||||
def which_disk(self):
|
||||
w = int(input("WHICH DISK WOULD YOU LIKE TO MOVE\n"))
|
||||
if w in self.__sizes:
|
||||
return w
|
||||
else:
|
||||
raise Exception()
|
||||
|
||||
def pick_disk(self):
|
||||
which = None
|
||||
while which is None:
|
||||
try:
|
||||
which = self.which_disk()
|
||||
except Exception:
|
||||
print("ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\n")
|
||||
|
||||
valids = [t for t in self.__towers if t.top() and t.top().size() == which]
|
||||
assert len(valids) in (0, 1)
|
||||
if not valids:
|
||||
print("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.\n")
|
||||
return None
|
||||
else:
|
||||
assert valids[0].top().size() == which
|
||||
return valids[0]
|
||||
|
||||
def which_tower(self):
|
||||
try:
|
||||
needle = int(input("PLACE DISK ON WHICH NEEDLE\n"))
|
||||
tower = self.__towers[needle - 1]
|
||||
except Exception:
|
||||
print(
|
||||
"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME. BUT WATCH IT,\nI ONLY ALLOW ONE MISTAKE.\n"
|
||||
)
|
||||
return None
|
||||
else:
|
||||
return tower
|
||||
|
||||
def take_turn(self):
|
||||
from_tower = None
|
||||
while from_tower is None:
|
||||
from_tower = self.pick_disk()
|
||||
|
||||
to_tower = self.which_tower()
|
||||
if not to_tower:
|
||||
to_tower = self.which_tower()
|
||||
|
||||
if not to_tower:
|
||||
print("I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\nBYE BYE, BIG SHOT.\n")
|
||||
sys.exit(0)
|
||||
|
||||
disk = from_tower.pop()
|
||||
try:
|
||||
to_tower.add(disk)
|
||||
self.__moves += 1
|
||||
except Exception as err:
|
||||
print(err)
|
||||
from_tower.add(disk)
|
||||
|
||||
|
||||
game = Game()
|
||||
while True:
|
||||
game.print()
|
||||
|
||||
game.take_turn()
|
||||
|
||||
if game.winner():
|
||||
print(
|
||||
"CONGRATULATIONS!!\nYOU HAVE PERFORMED THE TASK IN %s MOVES.\n"
|
||||
% game.moves()
|
||||
)
|
||||
while True:
|
||||
yesno = input("TRY AGAIN (YES OR NO)\n")
|
||||
if yesno.upper() == "YES":
|
||||
game = Game()
|
||||
break
|
||||
elif yesno.upper() == "NO":
|
||||
print("THANKS FOR THE GAME!\n")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("'YES' OR 'NO' PLEASE\n")
|
||||
elif game.moves() > 128:
|
||||
print("SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN 128 MOVES.")
|
||||
sys.exit(0)
|
||||
52
00_Alternate_Languages/90_Tower/python/tower_test.py
Normal file
52
00_Alternate_Languages/90_Tower/python/tower_test.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import unittest
|
||||
|
||||
import tower
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_something(self):
|
||||
t = tower.Tower()
|
||||
self.assertTrue(t.empty())
|
||||
|
||||
d = tower.Disk(3)
|
||||
t.add(d)
|
||||
self.assertFalse(t.empty())
|
||||
|
||||
d5 = tower.Disk(5)
|
||||
self.assertRaises(Exception, t.add, d5)
|
||||
self.assertFalse(t.empty())
|
||||
|
||||
def test_oksize(self):
|
||||
t = tower.Tower()
|
||||
self.assertTrue(t.empty())
|
||||
|
||||
d5 = tower.Disk(5)
|
||||
t.add(d5)
|
||||
self.assertFalse(t.empty())
|
||||
|
||||
d3 = tower.Disk(3)
|
||||
t.add(d3)
|
||||
self.assertFalse(t.empty())
|
||||
|
||||
self.assertEqual(t.top(), d3)
|
||||
self.assertEqual(t.pop(), d3)
|
||||
self.assertEqual(t.pop(), d5)
|
||||
|
||||
def test_game(self):
|
||||
g = tower.Game()
|
||||
self.assertEqual(g.moves(), 0)
|
||||
self.assertFalse(g.winner())
|
||||
|
||||
def test_format(self):
|
||||
t = tower.Tower()
|
||||
d3 = tower.Disk(3)
|
||||
d5 = tower.Disk(5)
|
||||
t.add(d5)
|
||||
t.add(d3)
|
||||
|
||||
f = t.vertical_format(6, 3)
|
||||
self.assertEqual(f, [" ", "[ 3 ] ", "[ 5 ] "])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user