#!/usr/bin/env python
#coding=utf-8
# random_rectanglesV19_web.py
"""
ATTENTION: The turtle module imported here is the turtle.py that is part of Python2.6 beta2.
See http://article.gmane.org/gmane.comp.python.tutor/49765 for more information.
"""
from turtle26 import *
from random import randint, choice, randrange
from math import ceil
import time
COLOR_NAMES_NO_GREYS = ['yellow', 'darkseagreen', 'aquamarine4', 'aquamarine1', 'aquamarine3', 'aquamarine2', 'brown', 'indianred4', 'skyblue', 'rosybrown4', 'cornsilk', 'lightpink', 'indianred2', 'chocolate1', 'lemonchiffon3', 'lemonchiffon2', 'lemonchiffon1', 'bisque', 'violetred1', 'chocolate2', 'lemonchiffon4', 'chocolate3', 'chocolate4', 'lightgoldenrodyellow', 'lavender', 'chartreuse3', 'chartreuse2', 'chartreuse1', 'darkslateblue', 'chartreuse4', 'lightskyblue', 'blue', 'rosybrown2', 'maroon4', 'maroon3', 'maroon2', 'maroon1', 'gold3', 'gold2', 'gold1', 'gold4', 'wheat4', 'rosybrown1', 'skyblue4', 'skyblue1', 'skyblue3', 'skyblue2', 'indianred1', 'floralwhite', 'turquoise1', 'firebrick3', 'firebrick2', 'firebrick1', 'steelblue2', 'steelblue4', 'firebrick4', 'lightskyblue1', 'greenyellow', 'lightseagreen', 'sienna', 'tomato', 'indianred3', 'royalblue', 'gainsboro', 'peru', 'red3', 'red2', 'red1', 'springgreen3', 'violetred4', 'lightyellow', 'lemonchiffon', 'chocolate', 'antiquewhite', 'moccasin', 'deeppink', 'springgreen1', 'springgreen2', 'dodgerblue', 'springgreen4', 'seashell2', 'seashell3', 'magenta', 'seashell1', 'tan', 'seashell4', 'pink', 'palevioletred', 'powderblue', 'mediumblue', 'honeydew1', 'mediumpurple1', 'mediumpurple2', 'mediumpurple3', 'mediumpurple4', 'honeydew2', 'khaki4', 'honeydew3', 'paleturquoise3', 'khaki1', 'cadetblue', 'khaki3', 'salmon1', 'honeydew4', 'salmon3', 'salmon2', 'salmon4', 'linen', 'green', 'blueviolet', 'brown2', 'brown3', 'brown1', 'brown4', 'orange4', 'orange1', 'orange3', 'orange2', 'cyan', 'yellow4', 'yellow3', 'yellow2', 'yellow1', 'orange', 'lightsteelblue', 'goldenrod', 'cyan4', 'darkviolet', 'darkmagenta', 'navy', 'ghostwhite', 'plum', 'khaki2', 'darkkhaki', 'violetred', 'red', 'peachpuff', 'lightslateblue', 'lightskyblue4', 'aliceblue', 'lightskyblue2', 'lightskyblue3', 'blue1', 'blue3', 'blue2', 'blue4', 'purple3', 'lightcyan', 'darksalmon', 'mediumspringgreen', 'tomato4', 'tomato1', 'tomato3', 'tomato2', 'mistyrose', 'blanchedalmond', 'orangered', 'navajowhite', 'pink3', 'pink2', 'burlywood', 'pink4', 'mistyrose1', 'white', 'darkolivegreen4', 'lightyellow3', 'paleturquoise4', 'darkolivegreen1', 'seagreen4', 'seagreen3', 'seagreen2', 'seagreen1', 'paleturquoise2', 'limegreen', 'mistyrose3', 'palegreen1', 'palegreen3', 'palegreen2', 'palegreen4', 'mistyrose2', 'burlywood1', 'turquoise2', 'burlywood3', 'burlywood2', 'burlywood4', 'rosybrown', 'turquoise4', 'whitesmoke', 'lightblue', 'snow', 'orangered3', 'orangered2', 'orangered1', 'orangered4', 'mistyrose4', 'thistle2', 'thistle1', 'salmon', 'thistle4', 'oldlace', 'darkseagreen4', 'darkseagreen3', 'darkseagreen2', 'darkseagreen1', 'darkblue', 'lightpink1', 'gold', 'lightsalmon4', 'lightsalmon2', 'lightsalmon3', 'lightsalmon1', 'green4', 'green1', 'green3', 'green2', 'steelblue1', 'papayawhip', 'black', 'orchid4', 'orchid1', 'orchid2', 'orchid3', 'purple2', 'antiquewhite3', 'antiquewhite2', 'antiquewhite1', 'antiquewhite4', 'bisque4', 'bisque1', 'bisque2', 'bisque3', 'darkturquoise', 'turquoise3', 'plum4', 'plum3', 'plum2', 'plum1', 'lightblue3', 'thistle', 'violet', 'darkorchid4', 'darkorchid1', 'darkorchid2', 'darkorchid3', 'rosybrown3', 'honeydew', 'cornflowerblue', 'palevioletred4', 'palevioletred1', 'palevioletred2', 'palevioletred3', 'mediumpurple', 'lightblue2', 'darkcyan', 'lightblue1', 'lightblue4', 'darkred', 'lavenderblush1', 'lavenderblush3', 'lavenderblush2', 'lavenderblush4', 'mediumturquoise', 'lightyellow1', 'lightyellow4', 'lightgoldenrod', 'navajowhite4', 'hotpink', 'olivedrab', 'navajowhite1', 'navajowhite2', 'magenta2', 'magenta1', 'palegreen', 'seashell', 'aquamarine', 'tan4', 'tan3', 'tan2', 'tan1', 'paleturquoise1', 'lawngreen', 'slateblue', 'darkorange4', 'mintcream', 'darkorange1', 'darkorange3', 'darkorange2', 'saddlebrown', 'goldenrod4', 'goldenrod1', 'goldenrod2', 'goldenrod3', 'darkgoldenrod', 'lightcyan1', 'sandybrown', 'lightcyan3', 'ivory3', 'ivory2', 'ivory1', 'lightcyan2', 'mediumseagreen', 'ivory4', 'darkorange', 'violetred2', 'steelblue3', 'lightcyan4', 'sienna1', 'palegoldenrod', 'sienna3', 'violetred3', 'sienna2', 'pink1', 'lightyellow2', 'darkolivegreen3', 'darkolivegreen2', 'lavenderblush', 'azure1', 'azure3', 'azure2', 'azure4', 'firebrick', 'indianred', 'sienna4', 'darkolivegreen', 'mediumorchid4', 'lightsteelblue1', 'lightsteelblue2', 'lightsteelblue3', 'lightsteelblue4', 'darkgoldenrod4', 'mediumorchid1', 'magenta4', 'magenta3', 'darkgoldenrod1', 'darkgoldenrod2', 'darkgoldenrod3', 'chartreuse', 'mediumslateblue', 'mediumorchid3', 'springgreen', 'mediumorchid2', 'lightsalmon', 'cyan2', 'turquoise', 'cyan3', 'olivedrab4', 'royalblue4', 'cyan1', 'purple4', 'navajowhite3', 'darkgreen', 'peachpuff4', 'purple1', 'slateblue3', 'peachpuff1', 'peachpuff2', 'olivedrab1', 'olivedrab2', 'olivedrab3', 'slateblue4', 'slateblue2', 'lightgoldenrod4', 'yellowgreen', 'lightgoldenrod1', 'slateblue1', 'lightgoldenrod3', 'lightgoldenrod2', 'peachpuff3', 'orchid', 'purple', 'darkorchid', 'royalblue1', 'thistle3', 'wheat1', 'wheat3', 'wheat2', 'coral3', 'coral2', 'coral1', 'deepskyblue4', 'deepskyblue3', 'deepskyblue2', 'deepskyblue1', 'coral4', 'khaki', 'wheat', 'deepskyblue', 'coral', 'beige', 'azure', 'dodgerblue1', 'dodgerblue2', 'dodgerblue3', 'dodgerblue4', 'mediumvioletred', 'snow4', 'snow2', 'snow3', 'snow1', 'lightcoral', 'ivory', 'lightpink2', 'lightpink3', 'forestgreen', 'lightpink4', 'midnightblue', 'mediumorchid', 'cornsilk4', 'cornsilk2', 'cornsilk3', 'cornsilk1', 'royalblue3', 'royalblue2', 'maroon', 'seagreen', 'red4', 'cadetblue4', 'cadetblue3', 'cadetblue2', 'cadetblue1', 'paleturquoise', 'deeppink3', 'deeppink2', 'deeppink1', 'deeppink4', 'hotpink3', 'hotpink2', 'hotpink1', 'lightgreen', 'hotpink4', 'navyblue', 'mediumaquamarine', 'steelblue']
BACKGROUND_COLORS = ['aquamarine4', 'blue', 'blueviolet', 'cadetblue1',
'cadetblue3', 'chartreuse2', 'chartreuse4',
'coral', 'cyan', 'cyan3', 'darkgoldenrod1', 'darkgreen',
'darkolivegreen1', 'darkorange2', 'darksalmon', 'darkseagreen',
'darkseagreen2', 'darkviolet', 'deeppink', 'firebrick',
'forestgreen', 'gold', 'green', 'hotpink', 'lightcoral',
'lightcyan', 'lightgoldenrod1', 'lightgoldenrodyellow',
'lightsalmon2', 'lightskyblue',
'lightslateblue', 'lightsteelblue1', 'lightsteelblue3',
'magenta', 'magenta1', 'magenta2', 'magenta3', 'mediumorchid1',
'mediumvioletred', 'navy', 'orangered', 'orangered4', 'orchid1',
'palegreen', 'paleturquoise1', 'palevioletred1', 'papayawhip',
'pink', 'plum1', 'purple','purple4', 'red4', 'skyblue', 'skyblue2',
'skyblue3', 'springgreen',
'springgreen4', 'turquoise1', 'turquoise3', 'violetred', 'yellow']
def floatToNearestInt(x):
"""
convert float x to the nearest integer n
e.g., 3.4 --> 3; 45.5 --> 46; -2.1 --> -2; -0.8 --> -1
"""
return int(round(x))
def intCommas(n):
"""
inserts commas into integers. E.g. -12345678 -> -12,345,789
"""
s = str(n)
sign = ''
if s[0] == '-':
sign = '-'
s = s[1:]
slen = len(s)
a = ''
for index in range(slen):
if index > 0 and index % 3 == slen % 3:
a = a + ','
a = a + s[index]
return sign + a
def int_to_ordinal(n):
"""
Takes an int and returns the string ordinal integer, with commas as appropriate
plus the appropriate suffix; e.g. 1237 -> 1,237th
"""
n = str(n)
if n[-1] in "0456789":
suff = "th"
elif n[-2:] in ['11', '12', '13']:
suff = "th"
elif n[-1] == "1":
suff = "st"
elif n [-1] == "2":
suff = "nd"
else:
suff = "rd"
return intCommas(n) + suff
def hmsToText(seconds):
"""
Convert seconds to hours, minutes, seconds and return result
"""
seconds = floatToNearestInt(seconds)
hours, minutes = 0, 0
if seconds >= 60 and seconds < 3600:
minutes, seconds = divmod(seconds, 60)
elif seconds >= 3600:
hours, seconds = divmod(seconds, 3600)
minutes, seconds = divmod(seconds, 60)
hp, mp, sp = "s", "s", "s" # add "s" to make "hour", "minute", "second" plural
if hours == 1:
hp = "" # no "s" on "hour"
if minutes == 1:
mp = ""
if seconds >= 1 and seconds < 2:
sp = ""
if hours == 0 and minutes == 0:
result = "%d second%s" % (seconds, sp)
elif hours == 0:
if seconds == 0:
result = "%d minute%s exactly" % (minutes, mp)
else:
result = "%d minute%s, %d second%s" % (minutes, mp, seconds, sp)
elif minutes == 0:
if seconds == 0:
result = "%d hour%s exactly" % (hours, hp)
else:
result = "%d hour%s, %d second%s" % (hours, hp, seconds, sp)
else:
result = "%d hour%s, %d minute%s, %d second%s" % (hours, hp, minutes, mp, seconds, sp)
return result
def getMinAndMaxIntegersFromUser(default_min, default_max):
print "Enter 2 integers > 1 for min and max, with max >= min"
print "Put a comma between the numbers. E.g., '8, 20'"
print "Press Enter to set default of %d, %d" % (default_min, default_max)
while True:
ans = raw_input("min, max: ")
if ans == '':
print "The default min, max have been set to %d, %d" % (default_min, default_max)
return (5, 20)
try:
min, max = ans.split(',')
except ValueError:
print "\nPlease start over and enter correct min and max."
print "Enter 2 integers > 1 for min and max, with max >= min"
print "Press Enter to set default of 5, 20\n"
continue
try:
min = int(min)
except ValueError:
print "\nPlease start over and enter correct min and max."
print "Enter 2 INTEGERS > 1 for min and max, with max >= min"
print "Press Enter to set default of 5, 20\n"
continue
try:
max = int(max)
except ValueError:
print "\nPlease start over and enter correct min and max."
print "Enter 2 INTEGERS > 1 for min and max, with max >= min"
print "Press Enter to set default of 5, 20"
continue
if min > max or min < 2:
print "\nPlease start over and enter correct min and max."
print "min must be <= max and min must be > 1"
print "Enter 2 integers > 1 for min and max, with max >= min"
print "Press Enter to set default of 5, 20"
continue
else:
break
return (min, max)
def get_pause_from_user(default_pause):
print """
You can set the pause between the filling of a rectangle and the start of the
next. Enter any non-negative number for the number of seconds to pause.
E.g., 0, 2, or 2.4
To set the default pause of %s second, just press Enter
""" % str(default_pause)
ans = raw_input("Enter pause in seconds: ")
if ans == '':
print "a pause of %s seconds has been set" % str(default_pause)
return default_pause
else:
print "a pause of %.3g seconds has been set" % float(ans)
return float(ans)
def get_speed_and_delay_from_user(default_speed, default_delay):
print """
Enter the speed and delay you want in the drawing of rectangles as
two integers separated by a comma; e.g., 2, 20. If you want the
default of speed %d and the delay %d, just press Enter.
""" % (default_speed, default_delay)
ans = raw_input("Enter speed and delay: ")
if ans == '':
print "speed %d and delay %d have been set" % (default_speed, default_delay)
return default_speed, default_delay
else:
spd, dly = ans.split(',')
spd, dly = int(spd), int(dly)
print "a speed of %d and a delay of %d have been set" % (spd, dly)
return spd, dly
def get_max_num_cycles_from_user():
longstr = """\nEnter the number of cycles; %d cycles will show approximately %d rectangles using all %d colors"""
print longstr % (num_cycles_to_show_all_colors, num_avail_colors, num_avail_colors)
print "Press Enter to set the default of %d" % num_cycles_to_show_all_colors
ans = raw_input("Number of cycles: ")
if ans == '':
ans = num_cycles_to_show_all_colors
print "The number of cycles has been set to %d." % num_cycles_to_show_all_colors
else:
ans = int(ans)
return ans
def adjust_for_monitor_size_and_resolution():
wd = window_width()
width_adjustment = wd*1.0/999
ht = window_height()
height_adjustment = ht*1.0/702
return width_adjustment, height_adjustment
def get_next_rect_params():
color_name = get_next_rect_color()
x = randrange(15, 451, 2)
y = randrange(15, 251, 2)
width_adjustment, height_adjustment = adjust_for_monitor_size_and_resolution()
x = x * width_adjustment
y = y * height_adjustment
pen_size = get_pen_size(x, y)
flag = randint(1, 8)
return pen_size, color_name, x, y, flag
def get_pen_size(x, y):
"""
Return a pen size proportional to the area of the rectangle
"""
pen_size = (x * y)//11320 + 1
return pen_size
def get_next_rect_color():
global used_colors
global multiple_of_num_avail_colors
while True:
color_name = choice(COLOR_NAMES_NO_GREYS)
if len(used_colors) >= num_avail_colors:
used_colors = []
multiple_of_num_avail_colors += num_avail_colors
if color_name not in used_colors:
used_colors.append(color_name)
return color_name
def draw_rect():
speed(spd)
pensize(pen_size)
color(color_name)
print color_name
begin_fill()
## NE, CW (northeast, clockwise)
if flag == 1:
up()
goto(x, y)
down()
# up to here tracer(False) is in effect from the last time draw_rect()
# was called (see bottom line)
tracer(True, dly)
goto(x, -y)
goto(-x, -y)
goto(-x, y)
goto(x, y)
## NE, CCW (northeast, counterclockwise)
elif flag == 2:
up()
goto(x, y)
down()
tracer(True, dly)
goto(-x, y)
goto(-x, -y)
goto(x, -y)
goto(x, y)
## SE, CW
elif flag == 3:
up()
goto(x, -y)
down()
tracer(True, dly)
goto(-x, -y)
goto(-x, y)
goto(x, y)
goto(x, -y)
## SE, CCW
elif flag == 4:
up()
goto(x, -y)
down()
tracer(True, dly)
goto(x, y)
goto(-x, y)
goto(-x, -y)
goto(x, -y)
## SW, CW
elif flag == 5:
up()
goto(-x, -y)
down()
tracer(True, dly)
goto(-x, y)
goto(x, y)
goto(x, -y)
goto(-x, -y)
## SW, CCW
elif flag == 6:
up()
goto(-x, -y)
down()
tracer(True, dly)
goto(x, -y)
goto(x, y)
goto(-x, y)
goto(-x, -y)
## NW, CW
elif flag == 7:
up()
goto(-x, y)
down()
tracer(True, dly)
goto(x, y)
goto(x, -y)
goto(-x, -y)
goto(-x, y)
## NW, CCW
elif flag == 8:
up()
goto(-x, y)
down()
tracer(True, dly)
goto(-x, -y)
goto(x, -y)
goto(x, y)
goto(-x, y)
end_fill()
tracer(False)
def get_black_or_colored():
"""
For the next background color, return 0 if it will
be "black"; 1 if it will be colored, i.e., a color
to be chosen from the list of unused background colors.
This function serves the purpose of preventing "black"
from being used more than once in a row, and a non-black
color from being used more than four times in a row.
"""
global black_or_colored_list
if sum(black_or_colored_list[-1:]) == 0:
black_or_colored = 1
elif sum(black_or_colored_list[-4:]) == 4:
black_or_colored = 0
else:
black_or_colored = choice((0, 1))
black_or_colored_list.append(black_or_colored)
return black_or_colored
def get_next_background_color():
"""
Return random hue from an updating list of unused background colors.
"""
global BACKGROUND_COLORS
global unused_background_colors
while True:
if len(unused_background_colors) > 0:
hue = choice(unused_background_colors)
unused_background_colors.remove(hue)
return hue
else:
unused_background_colors = BACKGROUND_COLORS[:]
def get_background():
black_or_colored = get_black_or_colored() # 0 for black; 1 for colored
clearscreen()
if black_or_colored == 0:
hue = 'black'
else:
hue = get_next_background_color()
if num_cycles < max_num_cycles:
print
print '%s is the new background color' % hue
return hue
def print_so_far_report():
if 0 < num_used_colors_to_report < num_avail_colors:
astr = "%d different colors of %d have been used for %d rectangles so far"
print astr % (num_used_colors_to_report, num_avail_colors, num_used_colors_to_report)
elif num_avail_colors <= num_used_colors_to_report:
longstr = "all %d different colors have been used for %d rectangles so far"
print longstr % (num_avail_colors, num_used_colors_to_report)
def s_or_none(n):
"""
Returns 's' to pluralize regular nouns.
"""
if n == 1:
return ''
else:
return 's'
def print_program_end_report():
if 0 < total_rects < num_avail_colors:
astr = "%d colors of %d were used for %d rectangles"
print astr % (total_rects, num_avail_colors,
total_rects)
elif num_avail_colors <= total_rects:
print "all %d colors were used for %d rectangles" % (num_avail_colors,
total_rects)
def beepN(times,interval):
"""Calls beep() n times at interval of x seconds."""
import time
for k in range(times-1):
beep()
time.sleep(interval)
beep()
def beep():
"""A very short Beep"""
import winsound
pitch = 500
length = 30
winsound.Beep(pitch,length)
print \
"""
This program creates sets (cycles) of concentric randomly sized and
randomly colored rectangles against background colors randomly chosen from a
special list of %d colors. After the initial background of white, a black
background will be chosen at least once in five times, but never twice in a row.
No rectangle color will repeat until all %d colors have been chosen.
""" % (len(BACKGROUND_COLORS), len(COLOR_NAMES_NO_GREYS))
## all the defaults are here
default_min, default_max = 5, 20
default_pause = 1
default_speed = 4
default_delay = 15
print """
You can accept all defaults by pressing Enter at the prompt
Enter 'n' to decline to accept all defaults
"""
ans = raw_input("Your choice: ")
if ans == '':
flag = True
else:
flag = False
if not flag:
print \
"""You can configure the number of rectangles per cycle by setting the minimum
and maximum numbers. This will be the range from which the actual number will
be chosen by a random process for each cycle. E.g., enter 10, 15 for a range of
10 to 15."""
print "For the default of %d, %d just press Enter." % (default_min, default_max)
begin_range, end_range = getMinAndMaxIntegersFromUser(default_min, default_max)
pause = get_pause_from_user(default_pause)
else:
begin_range, end_range = default_min, default_max
pause = default_pause
avg = (end_range + begin_range)*1.0/2
num_avail_colors = len(COLOR_NAMES_NO_GREYS)
num_cycles_to_show_all_colors = int(ceil(num_avail_colors/avg))
if not flag:
max_num_cycles = get_max_num_cycles_from_user()
else:
max_num_cycles = num_cycles_to_show_all_colors
print """
The program will stop after %d cycles.
To stop it sooner, click in the console window to
make it the active window; then press Ctrl+Q.
""" % max_num_cycles
if not flag:
spd, dly = get_speed_and_delay_from_user(default_speed, default_delay)
else:
spd, dly = default_speed, default_delay
## spd is used in line below; dly is used in tracer() in function draw_rect()
speed(spd)
print "\nThe program has started\n"
timeStart = time.time()
mode("standard")
setup(width=.735, height=.915, startx=-1, starty=0)
unused_background_colors = BACKGROUND_COLORS[:]
num_cycles = 0
used_colors = []
total_rects = 0
multiple_of_num_avail_colors = 0
#flag = 0
black_or_colored_list = [10, 10, 10, 0] ## so that first sum of list cannot be 0 or 4
title_string = "Random Rectangles with %d Colors" % num_avail_colors
title(title_string)
for x in range(1, max_num_cycles+1):
if x == 1:
bgcolor("white")
print "white is the background color"
final_rect_num = randint(begin_range, end_range)
count = 0
num_used_colors = len(used_colors)
num_used_colors_to_report = num_used_colors + multiple_of_num_avail_colors
print_so_far_report()
print "%d rectangles are coming up in this %s cycle" % (final_rect_num,
int_to_ordinal(num_cycles+1))
for x in range(0, final_rect_num):
pen_size, color_name, x, y, flag = get_next_rect_params()
hideturtle()
draw_rect()
total_rects += 1
count += 1
if count == final_rect_num:
num_cycles += 1
print "That's the end of the %s cycle of %d cycles" % (int_to_ordinal(num_cycles), max_num_cycles)
time.sleep(1.5)
if num_cycles < max_num_cycles:
hue = get_background()
bgcolor(hue)
else:
beepN(3, 0.2)
print "The program will close in 10 seconds"
else:
time.sleep(pause)
## report at end of program
print
print_program_end_report()
timeEnd = time.time()
print "Time was %s" % (hmsToText(timeEnd - timeStart))
time.sleep(8.5)