Bin für jeden Tipp dankbar.
Hier der Code:
Code: Alles auswählen
import System
from System.Diagnostics import Stopwatch
MAX_STEPS = 10**7
class TPLA_world():
def __init__(self, rule = "LR", LMT = 0):
"""
Usage:
xyz = TPLA_world() # will create a world with the rule "LR"
xyz = TPA_world("LLRR") # will create a world with the rule "LLRR"
xyz = TPA_world(LMT = 13) # will create a world with the rule "RLR"
see http://en.wikipedia.org/wiki/Langton%27s_ant for more details.
"""
self.min_x = 0
self.max_x = 0
self.min_y = 0
self.max_y = 0
if LMT > 3:
rule = bin(LMT)[3:].replace('0', 'L').replace('1', 'R')
self.rule = []
for c in rule:
if c == 'L':
self.rule.append(3)
elif c == 'U':
self.rule.append(2)
elif c == 'R':
self.rule.append(1)
elif c == 'N':
self.rule.append(0)
self.rule_deep = len(self.rule)
self.map = {}
self.map[(0,0)] = 0
self.pos_x = 0
self.pos_y = 0
self.direction = 0 # 0 = up, 1 = right, 2 = down, 3 = left
def make_one_step(self):
"""
Move the ant one step forward. A world map is build, where each place the ant enters gets an integer
value how often the ant walks over the place.
"""
# find the new direction
self.direction = (self.direction + self.rule[self.map[(self.pos_x, self.pos_y)] % self.rule_deep]) % 4
#color the field
self.map[(self.pos_x, self.pos_y)] += 1
# move into the direction
if self.direction == 0:
self.pos_y += 1
elif self.direction == 1:
self.pos_x += 1
elif self.direction == 2:
self.pos_y -= 1
else:
self.pos_x -= 1
#entering new ground?
if not (self.pos_x, self.pos_y) in self.map:
self.map[(self.pos_x, self.pos_y)] = 0
if self.pos_x < self.min_x:
self.min_x = self.pos_x
if self.pos_x > self.max_x:
self.max_x = self.pos_x
if self.pos_y < self.min_y:
self.min_y = self.pos_y
if self.pos_y > self.max_y:
self.max_y = self.pos_y
def check_dimension(self, x = 77, y = 300):
"""For checking the printed result to fit into a standard console window."""
return (self.max_x - self.min_x > x) or (self.max_y - self.min_y > y)
def print_map(self):
"""Print the worls map to a Windows console."""
for y in range(self.max_y, self.min_y - 1, -1):
for x in range(self.max_x, self.min_x - 1, -1):
if (x, y) in self.map:
point_info = self.map[(x, y)] % self.rule_deep
if point_info == 0:
System.Console.Write(".")
elif point_info == 1:
System.Console.Write("#")
else:
System.Console.Write(point_info % 10)
else:
System.Console.Write(" ")
System.Console.WriteLine()
System.Console.WriteLine("\n{0} <= x <= {1}", self.min_x, self.max_x)
System.Console.WriteLine("{0} <= y <= {1}\n", self.min_y, self.max_y)
# ask for ant's rule to walk
System.Console.WriteLine("Please enter the rule how to walk. A string of 'L' and 'R',")
System.Console.WriteLine("where 'L' let the ant turn left and 'R' right.")
System.Console.WriteLine("Also allowed: 'U' as an 180 degree U-turn and 'N' for no turn (keep direction).")
System.Console.WriteLine("Some nice rules are 'LLRR' or 'LRRRLLR'. Melt your CPU with LLLRR.")
System.Console.WriteLine("Create a highway with RNNU or URLRUN.")
System.Console.WriteLine("You can enter the LMT value alternatively (19 is the same as LLRR),")
System.Console.WriteLine("see http://de.wikipedia.org/wiki/Ameise_(Turingmaschine) for details.")
System.Console.WriteLine("Try 12345 to get a nice rectangle.")
System.Console.WriteLine()
System.Console.Write("rule = ")
rule_string = System.Console.ReadLine().strip()
System.Console.WriteLine()
# check the string and init ant's little world
if rule_string.isnumeric() and int(rule_string) > 3:
world = TPLA_world(LMT=int(rule_string))
else:
if not rule_string:
rule_string = "error!"
for char in rule_string:
if not char in "LRUN":
System.Console.WriteLine("Your string contains unknown characters other than 'L', 'R', 'U' or 'N'.")
System.Console.WriteLine("We use the rule 'LLRR' instead.")
rule_string = "LLRR"
break
world = TPLA_world(rule_string)
# create a "we are alive" message
System.Console.Write("One moment please ")
# measure execution time
timer = Stopwatch()
timer.Start()
# the calculation
i = 0
while not world.check_dimension() and i < MAX_STEPS:
world.make_one_step()
i += 1
if not i % 250000:
System.Console.Write(".")
timer.Stop()
# print results
System.Console.Write("\n\n")
world.print_map()
if i < MAX_STEPS:
System.Console.WriteLine("We have to abort the calculation, else the map would not fit into the window!")
System.Console.WriteLine("The little ant walked {0} steps in {1} ms.\nThis is equal to one million steps in {2} s.", i, timer.ElapsedMilliseconds, timer.ElapsedMilliseconds * 1000.0 / i)
# Wait for a key press before closing the console window.
print "Press any key to continue..."
System.Console.ReadKey(True)
Man würde vermutlich eher ein zweidimensionales Array für die Map verwenden, aber ich wollte die Leistung bei der Bearbeitung von Dictionaries messen und mit nativem C# vergleichen. Das IronPython Programm ist also eigentlich ein Leistungstest.
Jetzt soll das Programm als winexe unter Verwendung von WPF geschrieben werden. Die einzelnen Felder der Karte speichern die Anzahl der Besuche der Ameise, nicht die Farbe. Es soll der Maximalwerte der Besuche ermittelt werden, und dann ein 3D-Objekt aus Säulen erstellt werden, dessen Länge den Besuchen entspricht und dessen Farbe der gemäß den Ameisenfeldfarben erzeugt wird.
Als Alternative eine Bitmap, bei der die Pixel weiß sind, oder den Farbwert map[(x,y)] / max_visits für RGB haben (Graustufenbild).
Wie würde man das umsetzen?