#!/usr/bin/env python
#coding=utf-8
# random_rectanglesV20_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']
DUPE_COLORS_NO_GREYS = [['tomato', 'tomato1'], ['blue4', 'darkblue'], ['cyan4', 'darkcyan'],
['aquamarine3', 'mediumaquamarine'], ['yellow', 'yellow1'],
['darkmagenta', 'magenta4'], ['red1', 'red'], ['honeydew1', 'honeydew'],
['lightyellow', 'lightyellow1'], ['darkred', 'red4'],
['chocolate4', 'saddlebrown'], ['springgreen1', 'springgreen'],
['lavenderblush1', 'lavenderblush'], ['blue', 'blue1'],
['ivory1', 'ivory'], ['deeppink', 'deeppink1'],
['lemonchiffon1', 'lemonchiffon'], ['lightsalmon1', 'lightsalmon'],
['dodgerblue', 'dodgerblue1'], ['seashell1', 'seashell'],
['peachpuff', 'peachpuff1'], ['palegreen2', 'lightgreen'],
['navy', 'navyblue'], ['deepskyblue1', 'deepskyblue'],
['orangered', 'orangered1'], ['olivedrab3', 'yellowgreen'],
['magenta', 'magenta1'], ['mistyrose', 'mistyrose1'],
['mediumblue', 'blue3'], ['seagreen4', 'seagreen'], ['azure1', 'azure'],
['cornsilk', 'cornsilk1'], ['navajowhite', 'navajowhite1'],
['cyan', 'cyan1'], ['peru', 'tan3'], ['snow', 'snow1'],
['lightcyan', 'lightcyan1'], ['green', 'green1'], ['orange1', 'orange'],
['aquamarine1', 'aquamarine'], ['gold1', 'gold'], ['bisque', 'bisque1'],
['chartreuse1', 'chartreuse']]
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 defaults():
global default_min
global default_max
global default_begin_range
global default_end_range
global default_pause
global default_speed
global default_delay
default_min, default_max = 5, 20
default_begin_range, default_end_range = default_min, default_max
default_pause = 1
default_speed = 4
default_delay = 15
def print_defaults_before_acceptance():
print "The defaults are:"
print "default min, default max: %d, %d" % (default_min, default_max)
print "default pause:", default_pause
print "default speed:", default_speed
print "default delay:", default_delay
print "default number of cycles:", default_max_num_cycles
def initialize_variables():
global used_colors
global multiple_of_num_avail_colors
global num_cycles
global total_rects
global black_or_colored_list
global unused_background_colors
mode("standard")
setup(width=.735, height= 1.0, startx=-1, starty=0)
unused_background_colors = BACKGROUND_COLORS[:]
num_cycles = 0
used_colors = []
total_rects = 0
multiple_of_num_avail_colors = 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)
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 (default_min, default_max)
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, just press Enter
""" % singular_to_plural(default_pause, 'second')
while True:
ans = raw_input("Enter pause in seconds: ")
if ans == '':
print "a pause of %s has been set" % singular_to_plural(default_pause, 'second')
return default_pause
try:
pause = float(ans)
except ValueError:
print "\nPlease start over and enter a number of seconds >= 0."
print "Just press Enter to set default pause of %s" % singular_to_plural(default_pause, 'second')
continue
if pause < 0:
print "\nPlease start over and enter a NONNEGATIVE number."
print "Press Enter to set default of 5, 20"
continue
print "a pause of %.3g second%s has been set" % (float(ans), s_or_none(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.
"""
print "Enter 2 integers >= 0 for speed and delay"
print "Put a comma between the numbers. E.g., '2, 20'"
print "Just press Enter to set defaults of %d, %d" % (default_speed, default_delay)
while True:
ans = raw_input("speed, delay: ")
if ans == '':
print "The defaults of speed %d, delay %d have been set" % (default_speed, default_delay)
return (default_speed, default_delay)
try:
spd, dly = ans.split(',')
except ValueError:
print "\nPlease start over and enter correct speed and delay."
print "Enter 2 integers >= 0 for speed and delay"
print "Just press Enter to set defaults of %d, %d" % (default_speed, default_delay)
continue
try:
spd = int(spd)
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 "Just press Enter to set defaults of %d, %d" % (default_speed, default_delay)
continue
try:
dly = int(dly)
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 "Just press Enter to set defaults of %d, %d" % (default_speed, default_delay)
continue
if spd < 0 or dly < 0:
print "\nPlease start over and enter correct min and max."
print "Both speed and delay must be NONNEGATIVE, i.e., >= 0"
print "Enter 2 integers >= 0 for speed and delay"
print "Just press Enter to set defaults of %d, %d" % (default_speed, default_delay)
continue
else:
break
print "speed has been set to %d; delay to %d" % (spd, dly)
return (spd, dly)
def calculate_num_avail_colors():
num_avail_colors = len(COLOR_NAMES_NO_GREYS) - len(DUPE_COLORS_NO_GREYS) ## dupe colors are all in pairs
return num_avail_colors
def calculate_num_cycles_to_show_all_colors(begin_range, end_range):
avg = (begin_range + end_range)*1.0/2
num_cycles_to_show_all_colors = int(ceil(num_avail_colors/avg))
print "num_cycles_to_show_all_colors:", num_cycles_to_show_all_colors
return num_cycles_to_show_all_colors
def get_max_num_cycles_from_user():
num_cycles_to_show_all_colors = calculate_num_cycles_to_show_all_colors(begin_range, end_range)
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
while True:
ans = raw_input("Number of cycles: ")
if ans == '':
ans = num_cycles_to_show_all_colors
print "The number of cycle%s has been set to %d." % (s_or_none(num_cycles_to_show_all_colors), num_cycles_to_show_all_colors)
try:
ans = int(ans)
except ValueError:
print "\nPlease start over and enter a number of cycles >= 1."
print "Just press Enter to set default number of cycles of %s" % num_cycles_to_show_all_colors
continue
if ans < 1:
print "\nPlease start over and enter a positive integer."
print "Press Enter to set default of %d" % num_cycles_to_show_all_colors
continue
else:
ans = int(ans)
return ans
def adjust_for_monitor_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_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)
## when have exhausted colors
if len(used_colors) >= num_avail_colors:
used_colors = []
multiple_of_num_avail_colors += num_avail_colors
color_names = dupe_color_names(color_name)
if isinstance(color_names, tuple):
name0 = color_names[0]
name1 = color_names[1]
if name0 not in used_colors and name1 not in used_colors:
used_colors.append(name0)
used_colors.append(name1)
return name0
for col_name in color_names:
if col_name not in used_colors:
used_colors.append(col_name)
return col_name
else:
col_name = color_names ## only one name in this case
if col_name not in used_colors:
used_colors.append(col_name)
return col_name
def dupe_color_names(color_name):
"""
Check if color_name is a dupe.
Return a tuple of it and its fellow dupes.
If not a dupe, return color_name.
(a dupe color_name is a color name that has the same color value as at
least one other color name in COLOR_NAMES_NO_GREYS)
"""
for x in DUPE_COLORS_NO_GREYS:
if color_name in x:
return x[0], x[1]
return color_name
def print_color_names(color_names):
if isinstance(color_names, tuple):
for col_name in color_names:
print col_name,
print
else:
print color_names # a single color
def draw_rect():
speed(spd)
pensize(pen_size)
color(color_name)
color_names = dupe_color_names(color_name)
print_color_names(color_names)
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():
"""
Print at end of each cycle except for the last, when
print_program_end_report() will by called.
"""
if 0 < num_used_colors_to_report < num_avail_colors:
astr = "%d rects drawn, %d colors used so far, of %d colors"
print astr % (total_rects, total_rects, num_avail_colors)
elif total_rects >= num_avail_colors:
longstr = "%d rects drawn so far; all %d colors have been used"
print longstr % (total_rects, num_avail_colors)
def s_or_none(n):
"""
Returns 's' to pluralize regular nouns.
n can be an int, long, float, or str
"""
e = .0000000000001
if isinstance(n, (int, long)):
if n == 1:
return ''
elif isinstance(n, float):
if n - e < 1 < n + e:
print n
return ''
elif isinstance(n, str):
if '.' not in n:
if n == '1':
return ''
else:
n = float(n)
if n - e < 1 < n + e:
return ''
return 's'
def singular_to_plural(n, noun):
"""
Depending on n, return plural of regular noun in phrase such as
"3 goats", "1 goat", "1.0 goat", "1.3 goats", "0 goats"
n may be an int, long, float, or str
"""
e = .0000000000001
if isinstance(n, (int, long)):
if n == 1:
return str(n) + ' ' + noun
elif isinstance(n, float):
if n - e < 1 < n + e:
return str(n) + ' ' + noun
elif isinstance(n, str):
if '.' not in n:
if n == '1':
return n + ' ' + noun
else:
n = float(n)
if n - e < 1 < n + e:
return str(n) + ' ' + noun
return str(n) + ' ' + noun + '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. Useful at end of program to remind user of the .exe
to check final report in the 10 seconds before the console window closes
"""
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))
## defaults() has all the defaults except max_num_cycles, which depends on
## num_cycles_to_show_all_colors, which in turn depends on num_avail_colors,
## which depends on end_range, begin_range, which depend on the defaults
## default_min, default_max .
defaults()
num_avail_colors = calculate_num_avail_colors()
default_max_num_cycles = calculate_num_cycles_to_show_all_colors(default_begin_range, default_end_range)
print_defaults_before_acceptance()
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 == '':
print "All defaults have been set."
accept_all_defaults = True
begin_range, end_range = default_min, default_max
pause = default_pause
max_num_cycles = default_max_num_cycles
spd, dly = default_speed, default_delay
speed(spd)
else:
accept_all_defaults = False
if not accept_all_defaults:
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)
print
pause = get_pause_from_user(default_pause)
if not accept_all_defaults:
max_num_cycles = get_max_num_cycles_from_user()
print """
The program will stop after %s.
To stop it sooner, click in the console window to
make it the active window; then press Ctrl+Q.
""" % singular_to_plural(max_num_cycles, 'cycle')
if not accept_all_defaults:
spd, dly = get_speed_and_delay_from_user(default_speed, default_delay)
## spd is used in line below; dly is used in tracer() in function draw_rect()
speed(spd)
initialize_variables()
print "\nThe program has started\n"
timeStart = time.time()
for x in range(1, max_num_cycles+1):
if x == 1:
bgcolor("white")
print "white is the background color"
## do setup() again (only once again), in order to set the window
## height so that the bottom will be just at the top of task bar.
setup(width=.735, height=(window_height()- 40), startx=-1, starty=0)
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 rects in new %s cycle are coming up" % (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 ends 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)