Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@danbst
Last active November 4, 2021 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbst/ae4fd7cbb1ea97d5efbc80bd06b50075 to your computer and use it in GitHub Desktop.
Save danbst/ae4fd7cbb1ea97d5efbc80bd06b50075 to your computer and use it in GitHub Desktop.
Пачка програм
"""
Алфавіт-квіз, автор Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import random, time
QUESTION_SIZE = 5
QUIZ_DURATION = 30
abc = {}
abc['uk'] = 'АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩьЮЯ'
abc['small'] = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩьЮЯ'
abc['eng'] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ALPHABET = abc['small']
REVERSE_ALPHABET = abc['small'][::-1]
preamble = '''
\u001b[32m
Швидко надрукуй літери в алфавітному порядку.
У тебе є {} секунд!
Наприклад:
П М О Т К <- букви
> кмопт <- їх правильний порядок
\u001b[0m
'''
def main():
slowPrint(ALPHABET, 0.02)
slowPrint(' Алфавіт Квіз', 0.02)
slowPrint(REVERSE_ALPHABET, 0.02)
time.sleep(0.5)
print(preamble.format(QUIZ_DURATION))
input('Тисни Enter щоб почати...')
startTime = time.time()
numCorrect = 0
while True:
quizLetters = random.sample(ALPHABET, QUESTION_SIZE)
print(' '.join(quizLetters))
response = input('> ').strip().upper()
response = response.replace(' ', '') # Remove spaces.
# Check if the quiz's time is up:
if time.time() - QUIZ_DURATION > startTime:
print("ЧАС ВИЙШОВ!")
break
# Check if the response is correct:
if list(response) == sorted(quizLetters):
print(' Вірно!\n')
numCorrect += 1 # Increase the score by 1.
else:
print(' Упс, помилка. :(\n')
# After the loop exits, the quiz is over. Show the final score:
print('За {} секунд ти'.format(QUIZ_DURATION))
print('маєш {} правильних результатів!'.format(numCorrect))
print('Дякую за гру!')
def slowPrint(text, pauseAmount=0.1):
"""Slowly print out the characters in text one at a time."""
for character in text:
# Set flush=True here so the text is immediately printed:
print(character, flush=True, end='') # end='' means no newline.
time.sleep(pauseAmount) # Pause in between each character.
print() # Print a newline.
# If this program was run (instead of imported), run the game:
if __name__ == '__main__':
main()
"""
Баглі, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import random
NUM_DIGITS = 3
MAX_GUESSES = 10
preamble = '''
Баглі, лоігчна гра
Я загадую {}-значне число, в якому цифри не повторюються.
Спробуй його відгадати. Ось підказки:
Якщо я кажу: то це означає:
----------- -------------
Піко одна цифра правильна, але у неправильному місці
Фермі одна цифра правильна, і у правильному місці
Баглі не вгадано жодну цифру
Наприклад, якщо секретне число 248, а ти кажеш 843, то підказки будуть
Фермі Піко
'''
def main():
print(preamble.format(NUM_DIGITS))
while True:
secretNum = getSecretNum()
print('Я задумав число.')
print(' У тебе є {} спроб, щоб його вгадати.'.format(MAX_GUESSES))
numGuesses = 1
while numGuesses <= MAX_GUESSES:
guess = ''
# Keep looping until they enter a valid guess:
while len(guess) != NUM_DIGITS or not guess.isdecimal():
print('Спроба №{}: '.format(numGuesses))
guess = input('> ')
clues = getClues(guess, secretNum)
print(clues)
numGuesses += 1
if guess == secretNum:
break # They're correct, so break out of this loop.
if numGuesses > MAX_GUESSES:
print('Більше немає спроб.')
print('Відповідь -- {}.'.format(secretNum))
# Ask player if they want to play again.
print('Хочеш зіграти ще раз? (yes/no так/ні)')
answer = input('> ').lower().startswith
if not (answer('y') or answer('т')):
break
print('Дякую за гру!')
def getSecretNum():
"""Returns a string made up of NUM_DIGITS unique random digits."""
numbers = list('0123456789') # Create a list of digits 0 to 9.
random.shuffle(numbers) # Shuffle them into random order.
# Get the first NUM_DIGITS digits in the list for the secret number:
secretNum = ''
for i in range(NUM_DIGITS):
secretNum += str(numbers[i])
return secretNum
def getClues(guess, secretNum):
"""Returns a string with the pico, fermi, bagels clues for a guess
and secret number pair."""
if guess == secretNum:
return 'You got it!'
clues = []
for i in range(len(guess)):
if guess[i] == secretNum[i]:
# A correct digit is in the correct place.
clues.append('Фермі')
elif guess[i] in secretNum:
# A correct digit is in the incorrect place.
clues.append('Піко')
if len(clues) == 0:
return 'Баглі' # There are no correct digits at all.
else:
# Sort the clues into alphabetical order so their original order
# doesn't give information away.
clues.sort()
# Make a single string from the list of string clues.
return ' '.join(clues)
# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
main()
import turtle
import random
verts = [(-200, 0), (200, -200), (0, 200)]
turtle.bgcolor('black')
turtle.tracer(0, 0)
turtle.penup()
turtle.goto(-20, -71)
turtle.shape('circle')
turtle.shapesize(2/20)
rr = random.randrange
rrd = random.random
kx = ky = 0.5
cnt = 0
while True:
cnt += 1
vx, vy = random.choice(verts)
x, y = turtle.pos()
turtle.goto((x+vx)*kx, (y+vy)*ky)
turtle.color(rrd(), rrd(), rrd())
turtle.stamp()
if cnt % 50 == 0:
turtle.update()
if cnt > 1000:
verts = [(rr(-400, 400), rr(-350, 350)) for _ in range(3)]
kx = ky = rrd()
turtle.clear()
cnt = 0
"""
Парадокс днів народження, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import datetime
import random
def getBirthdays(numberOfBirthdays):
"""Returns a list of number random date objects for birthdays."""
birthdays = []
for i in range(numberOfBirthdays):
# The year is unimportant for our simulation, as long as all
# birthdays have the same year.
startOfYear = datetime.date(2001, 1, 1)
# Get a random day into the year:
randomNumberOfDays = datetime.timedelta(random.randint(0, 364))
birthday = startOfYear + randomNumberOfDays
birthdays.append(birthday)
return birthdays
def getMatch(birthdays):
"""Returns the date object of a birthday that occurs more than once
in the birthdays list."""
if len(birthdays) == len(set(birthdays)):
return None # All birthdays are unique, so return None.
# Compare each birthday to every other birthday:
for a, birthdayA in enumerate(birthdays):
for b, birthdayB in enumerate(birthdays[a + 1 :]):
if birthdayA == birthdayB:
return birthdayA # Return the matching birthday.
# Display the intro:
print('''
Як часто в групі з 30 учнів у двох учнів день народження в один день?
Відповідь дивує --- у більшості класів!
Ця програма робить симуляцію (створює багато випадкових груп), щоб
порахувати цей парадокс більш точно.
''')
# Set up a tuple of month names in order:
MONTHS = ('Січ', 'Лют', 'Бер', 'Кві', 'Тра', 'Чер',
'Лип', 'Сер', 'Вер', 'Жов', 'Лис', 'Гру')
while True: # Keep asking until the user enters a valid amount.
print('Скільки учнів в групі? (не більше 100)')
response = input('> ')
if response.isdecimal() and (0 < int(response) <= 100):
numBDays = int(response)
break # User has entered a valid amount.
print()
# Generate and display the birthdays:
print('Ось', numBDays, 'випадкових днів народжень:')
birthdays = getBirthdays(numBDays)
for i, birthday in enumerate(birthdays):
if i != 0:
# Display a comma for each birthday after the first birthday.
print(', ', end='')
monthName = MONTHS[birthday.month - 1]
dateText = '{} {}'.format(monthName, birthday.day)
print(dateText, end='')
print()
print()
# Determine if there are two birthdays that match.
match = getMatch(birthdays)
# Display the results:
print('Якщо порахувати, то ', end='')
if match != None:
monthName = MONTHS[match.month - 1]
dateText = '{} {}'.format(monthName, match.day)
print('кілька учнів мають день народження', dateText)
else:
print('дні народження у всіх різні.')
print()
# Run through 100,000 simulations:
print('Генерую', numBDays, 'випадкових днів народжень 100 000 разів...')
input('Тисни Enter щоб продовжити...')
#print('Let\'s run another 100,000 simulations.')
simMatch = 0 # How many simulations had matching birthdays in them.
for i in range(100_000):
# Report on the progress every 10,000 simulations:
if i % 10_000 == 0:
print(i, 'симуляцій зроблено...')
birthdays = getBirthdays(numBDays)
if getMatch(birthdays) != None:
simMatch = simMatch + 1
print('100 000 симуляцій закінчено.')
# Display simulation results:
probability = round(simMatch / 100_000 * 100, 2)
print(f'''
З {100_000} симуляцій груп по {numBDays} учнів, день народження
в один день був в {simMatch} групах. Це означає, що {numBDays} учнів
мають {probability}% шанс разом святкувати ДР.
Це може бути неочікувно!
''')
"""
Текст картинкою, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import sys
bitmap = """
....................................................................
************** * *** ** * ******************************
********************* ** ** * * ****************************** *
** ***************** ******************************
************* ** * **** ** ************** *
********* ******* **************** * *
******** *************************** *
* * **** *** *************** ****** ** *
**** * *************** *** *** *
****** ************* ** ** *
******** ************* * ** ***
******** ******** * *** ****
********* ****** * **** ** * **
********* ****** * * *** * *
****** ***** ** ***** *
***** **** * ********
***** **** *********
**** ** ******* *
*** * *
** * *
...................................................................."""
print('Напиши текст, який ти хочеш закодувати картинкою:')
message = input('> ')
if message == '':
sys.exit()
# Loop over each line in the bitmap:
for line in bitmap.splitlines():
# Loop over each character in the line:
for i, bit in enumerate(line):
if bit == ' ':
# Print an empty space since there's a space in the bitmap:
print(' ', end='')
else:
# Print a character from the messge:
print(message[i % len(message)], end='')
print() # Print a newline.
"""
Календар, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import datetime
# Set up the constants:
DAYS = ('Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П\'ятниця',
'Субота', 'Неділя')
MONTHS = ('Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень',
'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень')
R = '\u001b[0m'
background = '\u001b[7m\u001b[1m'
width = 7
print('Календарик')
year, month = None, None
while not year: # Loop to get a year from the user.
print('Введи рік для календаря:')
response = input('> ')
if response.isdecimal() and int(response) > 0:
year = int(response)
break
print('Введи рік числом, наприклад, 2023.')
continue
while not month: # Loop to get a month from the user.
print('Введи місяць, 1-12:')
response = input('> ')
if not response.isdecimal():
print('Введи місяць числом, наприклад 3 для березня.')
continue
month = int(response)
if 1 <= month <= 12:
break
print('Має бути число від 1 до 12.')
month = None
def getCalendarFor(year, month):
calText = '' # calText will contain the string of our calendar.
# Put the month and year at the top of the calendar:
calText += (' ' * 34) + MONTHS[month - 1] + ' ' + str(year) + '\n'
# Add the days of the week labels to the calendar:
# (!) Try changing this to abbreviations: SUN, MON, TUE, etc.
calText += ''.join([day[:width-1].ljust(width+1, '.') for day in DAYS]) + '\n'
# The horizontal line string that separate weeks:
weekSeparator = (('+' + '-'*width) * 7) + '+\n'
# The blank rows have ten spaces in between the | day separators:
blankRow = (('|' + ' '*width) * 7) + '|\n'
# Get the first date in the month. (The datetime module handles all
# the complicated calendar stuff for us here.)
currentDate = datetime.date(year, month, 1)
# Roll back currentDate until it is Sunday. (weekday() returns 6
# for Sunday, not 0.)
while currentDate.weekday() != 0:
currentDate -= datetime.timedelta(days=1)
while True: # Loop over each week in the month.
calText += weekSeparator
# dayNumberRow is the row with the day number labels:
dayNumberRow = ''
for i in range(7):
dayNumberLabel = str(currentDate.day).rjust(2)
dayNumberRow += '|'
filler = dayNumberLabel + (' ' * (width-2))
if currentDate.month == month:
dayNumberRow += background + filler + R
else:
dayNumberRow += filler
currentDate += datetime.timedelta(days=1) # Go to next day.
dayNumberRow += '|\n' # Add the vertical line after Saturday.
# Add the day number row and 3 blank rows to the calendar text.
calText += dayNumberRow
for i in range(3): # (!) Try changing the 4 to a 5 or 10.
calText += blankRow
# Check if we're done with the month:
if currentDate.month != month:
break
# Add the horizontal line at the very bottom of the calendar.
calText += weekSeparator
return calText
calText = getCalendarFor(year, month)
print(calText) # Display the calendar.
# Save the calendar to a text file:
calendarFilename = 'calendar_{}_{}.txt'.format(year, month)
with open(calendarFilename, 'w') as fileObj:
fileObj.write(calText)
print('Saved to ' + calendarFilename)
"""Clickbait Headline Generator, by Al Sweigart al@inventwithpython.com
A clickbait headline generator for your soulless content farm website.
This and other games are available at https://nostarch.com/XX
Tags: large, beginner, humor, word"""
__version__ = 0
import random
# Set up the constants:
OBJECT_PRONOUNS = ['Her', 'Him', 'Them']
POSSESIVE_PRONOUNS = ['Her', 'His', 'Their']
PERSONAL_PRONOUNS = ['She', 'He', 'They']
STATES = ['California', 'Texas', 'Florida', 'New York', 'Pennsylvania',
'Illinois', 'Ohio', 'Georgia', 'North Carolina', 'Michigan']
NOUNS = ['Athlete', 'Clown', 'Shovel', 'Paleo Diet', 'Doctor', 'Parent',
'Cat', 'Dog', 'Chicken', 'Robot', 'Video Game', 'Avocado',
'Plastic Straw','Serial Killer', 'Telephone Psychic']
PLACES = ['House', 'Attic', 'Bank Deposit Box', 'School', 'Basement',
'Workplace', 'Donut Shop', 'Apocalypse Bunker']
WHEN = ['Soon', 'This Year', 'Later Today', 'RIGHT NOW', 'Next Week']
def main():
print('Clickbait Headline Generator')
print('By Al Sweigart al@inventwithpython.com')
print()
print('Our website needs to trick people into looking at ads!')
while True:
print('Enter the number of clickbait headlines to generate:')
response = input('> ')
if not response.isdecimal():
print('Please enter a number.')
else:
numberOfHeadlines = int(response)
break # Exit the loop once a valid number is entered.
for i in range(numberOfHeadlines):
clickbaitType = random.randint(1, 8)
if clickbaitType == 1:
headline = generateAreMillenialsKillingHeadline()
elif clickbaitType == 2:
headline = generateWhatYouDontKnowHeadline()
elif clickbaitType == 3:
headline = generateBigCompaniesHateHerHeadline()
elif clickbaitType == 4:
headline = generateYouWontBelieveHeadline()
elif clickbaitType == 5:
headline = generateDontWantYouToKnowHeadline()
elif clickbaitType == 6:
headline = generateGiftIdeaHeadline()
elif clickbaitType == 7:
headline = generateReasonsWhyHeadline()
elif clickbaitType == 8:
headline = generateJobAutomatedHeadline()
print(headline)
print()
website = random.choice(['wobsite', 'blag', 'Facebuuk', 'Googles',
'Facesbook', 'Tweedie', 'Pastagram'])
when = random.choice(WHEN).lower()
print('Post these to our', website, when, 'or you\'re fired!')
# Each of these functions returns a different type of headline:
def generateAreMillenialsKillingHeadline():
noun = random.choice(NOUNS)
return 'Are Millenials Killing the {} Industry?'.format(noun)
def generateWhatYouDontKnowHeadline():
noun = random.choice(NOUNS)
pluralNoun = random.choice(NOUNS) + 's'
when = random.choice(WHEN)
return 'Without This {}, {} Could Kill You {}'.format(noun, pluralNoun, when)
def generateBigCompaniesHateHerHeadline():
pronoun = random.choice(OBJECT_PRONOUNS)
state = random.choice(STATES)
noun1 = random.choice(NOUNS)
noun2 = random.choice(NOUNS)
return 'Big Companies Hate {}! See How This {} {} Invented a Cheaper {}'.format(pronoun, state, noun1, noun2)
def generateYouWontBelieveHeadline():
state = random.choice(STATES)
noun = random.choice(NOUNS)
pronoun = random.choice(POSSESIVE_PRONOUNS)
place = random.choice(PLACES)
return 'You Won\'t Believe What This {} {} Found in {} {}'.format(state, noun, pronoun, place)
def generateDontWantYouToKnowHeadline():
pluralNoun1 = random.choice(NOUNS) + 's'
pluralNoun2 = random.choice(NOUNS) + 's'
return 'What {} Don\'t Want You To Know About {}'.format(pluralNoun1, pluralNoun2)
def generateGiftIdeaHeadline():
number = random.randint(7, 15)
noun = random.choice(NOUNS)
state = random.choice(STATES)
return '{} Gift Ideas to Give Your {} From {}'.format(number, noun, state)
def generateReasonsWhyHeadline():
number1 = random.randint(3, 19)
pluralNoun = random.choice(NOUNS) + 's'
# number2 should be no larger than number1:
number2 = random.randint(1, number1)
return '{} Reasons Why {} Are More Interesting Than You Think (Number {} Will Surprise You!)'.format(number1, pluralNoun, number2)
def generateJobAutomatedHeadline():
state = random.choice(STATES)
noun = random.choice(NOUNS)
i = random.randint(0, 2)
pronoun1 = POSSESIVE_PRONOUNS[i]
pronoun2 = PERSONAL_PRONOUNS[i]
if pronoun1 == 'Their':
return 'This {} {} Didn\'t Think Robots Would Take {} Job. {} Were Wrong.'.format(state, noun, pronoun1, pronoun2)
else:
return 'This {} {} Didn\'t Think Robots Would Take {} Job. {} Was Wrong.'.format(state, noun, pronoun1, pronoun2)
# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
main()
"""
Підкадання монетки, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import random
print('Підкидання монетки')
# Ask the user how many flips to make:
print('Скільки разів кидати монетку?')
while True:
response = input('> ')
if response.isdecimal():
numberOfFlips = int(response)
break # Exit the loop once they enter a valid number.
# The streakStats dictionary keeps count of how many times a certain
# streak of heads or tails has occurred. The keys are tuples of
# (streakLength, side) and the values are integer counts.
streakStats = {}
for i in range(numberOfFlips):
# Simulate one coin flip:
if random.randint(0, 1) == 0:
flip = 'герби'
else:
flip = 'числа'
print(flip[0], end='') # Print out "h" or "t".
isFirstFlip = i == 0
if isFirstFlip:
currentStreakLength = 0
currentStreakSide = flip
# Check if we need to reset the streak:
if flip != currentStreakSide:
# Record the streak stats:
streakKey = (currentStreakLength, currentStreakSide)
if streakKey not in streakStats:
# Set this new key to 0:
streakStats[streakKey] = 0
streakStats[streakKey] = streakStats[streakKey] + 1
# Reset the streak length for this new streak:
currentStreakLength = 1
currentStreakSide = flip
else:
currentStreakLength = currentStreakLength + 1
# Record the streak stats for the final flip:
streakKey = (currentStreakLength, currentStreakSide)
if streakKey not in streakStats:
streakStats[streakKey] = 0 # New streaks start at 0.
streakStats[streakKey] = streakStats[streakKey] + 1
print()
print('Кінець.')
streakLengthsAndSides = list(streakStats.keys())
streakLengthsAndSides.sort()
# Display the results:
for length, side in streakLengthsAndSides:
label = str(length) + ' ' + side + ' підряд'
print(label.rjust(21) + ' - ' + str(streakStats[(length, side)]))
"""Conway's Game of Life, by Al Sweigart al@inventwithpython.com
The classic cellular automata simulation. Press Ctrl-C to stop.
More info at: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
This and other games are available at https://nostarch.com/XX
Tags: short, artistic, simulation"""
__version__ = 0
import copy, random, sys, time
# Set up the constants:
WIDTH = 50 # The width of the cell grid.
HEIGHT = 20 # The height of the cell grid.
# (!) Try changing ALIVE to '#' or another character:
ALIVE = '.' # The character representing a living cell.
# (!) Try changing DEAD to '.' or another character:
DEAD = ' ' # The character representing a dead cell.
# (!) Try changing ALIVE to '|' and DEAD to '-'.
# The cells and nextCells are dictionaries for the state of the game.
# Their keys are (x, y) tuples and their values are one of the ALIVE
# or DEAD values.
nextCells = {}
# Put random dead and alive cells into nextCells:
for x in range(WIDTH): # Loop over every possible column.
for y in range(HEIGHT): # Loop over every possible row.
# 50/50 chance for starting cells being alive or dead.
if random.randint(0, 1) == 0:
nextCells[(x, y)] = ALIVE # Add a living cell.
else:
nextCells[(x, y)] = DEAD # Add a dead cell.
while True: # Main program loop.
# Each iteration of this loop is a step of the simulation.
print('\n' * 50) # Separate each step with newlines.
cells = copy.deepcopy(nextCells)
# Print cells on the screen:
for y in range(HEIGHT):
for x in range(WIDTH):
print(cells[(x, y)], end='') # Print the # or space.
print() # Print a newline at the end of the row.
print('Press Ctrl-C to quit.')
# Calculate the next step's cells based on current step's cells:
for x in range(WIDTH):
for y in range(HEIGHT):
# Get the neighboring coordinates of (x, y), even if they
# wrap around the edge:
left = (x - 1) % WIDTH
right = (x + 1) % WIDTH
above = (y - 1) % HEIGHT
below = (y + 1) % HEIGHT
# Count the number of living neighbors:
numNeighbors = 0
if cells[(left, above)] == ALIVE:
numNeighbors += 1 # Top-left neighbor is alive.
if cells[(x, above)] == ALIVE:
numNeighbors += 1 # Top neighbor is alive.
if cells[(right, above)] == ALIVE:
numNeighbors += 1 # Top-right neighbor is alive.
if cells[(left, y)] == ALIVE:
numNeighbors += 1 # Left neighbor is alive.
if cells[(right, y)] == ALIVE:
numNeighbors += 1 # Right neighbor is alive.
if cells[(left, below)] == ALIVE:
numNeighbors += 1 # Bottom-left neighbor is alive.
if cells[(x, below)] == ALIVE:
numNeighbors += 1 # Bottom neighbor is alive.
if cells[(right, below)] == ALIVE:
numNeighbors += 1 # Bottom-right neighbor is alive.
# Set cell based on Conway's Game of Life rules:
if cells[(x, y)] == ALIVE and (numNeighbors == 2
or numNeighbors == 3):
# Living cells with 2 or 3 neighbors stay alive:
nextCells[(x, y)] = ALIVE
elif cells[(x, y)] == DEAD and numNeighbors == 3:
# Dead cells with 3 neighbors become alive:
nextCells[(x, y)] = ALIVE
else:
# Everything else dies or stays dead:
nextCells[(x, y)] = DEAD
try:
time.sleep(0.1) # Add a 1 second pause to reduce flickering.
except KeyboardInterrupt:
print('Conway\'s Game of Life')
print('By Al Sweigart al@inventwithpython.com')
sys.exit() # When Ctrl-C is pressed, end the program.
"""Countdown, by Al Sweigart al@inventwithpython.com
Show a countdown timer animation using a seven-segment display.
Press Ctrl-C to stop.
More info at https://en.wikipedia.org/wiki/Seven-segment_display
Requires sevseg.py to be in the same folder.
This and other games are available at https://nostarch.com/XX
Tags: tiny, artistic"""
__version__ = 0
import sys, time
# (!) Change this to any number of seconds:
secondsLeft = 30
def getSevSegStr(number, minWidth=0):
"""Return a seven-segment display string of number. The returned
string will be padded with zeros if it is smaller than minWidth."""
# Convert number to string in case it's an int or float:
number = str(number).zfill(minWidth)
rows = ['', '', '']
for i, numeral in enumerate(number):
if numeral == '.': # Render the decimal point.
rows[0] += ' '
rows[1] += ' '
rows[2] += '.'
continue # Skip the space in between digits.
elif numeral == '-': # Render the negative sign:
rows[0] += ' '
rows[1] += ' __ '
rows[2] += ' '
elif numeral == '0': # Render the 0.
rows[0] += ' __ '
rows[1] += '| |'
rows[2] += '|__|'
elif numeral == '1': # Render the 1.
rows[0] += ' '
rows[1] += ' |'
rows[2] += ' |'
elif numeral == '2': # Render the 2.
rows[0] += ' __ '
rows[1] += ' __|'
rows[2] += '|__ '
elif numeral == '3': # Render the 3.
rows[0] += ' __ '
rows[1] += ' __|'
rows[2] += ' __|'
elif numeral == '4': # Render the 4.
rows[0] += ' '
rows[1] += '|__|'
rows[2] += ' |'
elif numeral == '5': # Render the 5.
rows[0] += ' __ '
rows[1] += '|__ '
rows[2] += ' __|'
elif numeral == '6': # Render the 6.
rows[0] += ' __ '
rows[1] += '|__ '
rows[2] += '|__|'
elif numeral == '7': # Render the 7.
rows[0] += ' __ '
rows[1] += ' |'
rows[2] += ' |'
elif numeral == '8': # Render the 8.
rows[0] += ' __ '
rows[1] += '|__|'
rows[2] += '|__|'
elif numeral == '9': # Render the 9.
rows[0] += ' __ '
rows[1] += '|__|'
rows[2] += ' __|'
# Add a space (for the space in between numerals) if this
# isn't the last numeral and the decimal point isn't next:
if i != len(number) - 1 and number[i + 1] != '.':
rows[0] += ' '
rows[1] += ' '
rows[2] += ' '
return '\n'.join(rows)
try:
while True: # Main program loop.
# Clear the screen by printing several newlines:
print('\n' * 60)
# Get the hours/minutes/seconds from secondsLeft:
# For example: 7265 is 2 hours, 1 minute, 5 seconds.
# So 7265 // 3600 is 2 hours:
hours = str(secondsLeft // 3600)
# And 7265 % 3600 is 65, and 65 // 60 is 1 minute:
minutes = str((secondsLeft % 3600) // 60)
# And 7265 % 60 is 5 seconds:
seconds = str(secondsLeft % 60)
# Get the digit strings from the sevseg module:
hDigits = getSevSegStr(hours, 2)
hTopRow, hMiddleRow, hBottomRow = hDigits.splitlines()
mDigits = getSevSegStr(minutes, 2)
mTopRow, mMiddleRow, mBottomRow = mDigits.splitlines()
sDigits = getSevSegStr(seconds, 2)
sTopRow, sMiddleRow, sBottomRow = sDigits.splitlines()
# Display the digits:
print(hTopRow + ' ' + mTopRow + ' ' + sTopRow)
print(hMiddleRow + ' * ' + mMiddleRow + ' * ' + sMiddleRow)
print(hBottomRow + ' * ' + mBottomRow + ' * ' + sBottomRow)
if secondsLeft == 0:
print()
print(' * * * * BOOM * * * *')
break
print()
print('Press Ctrl-C to quit.')
time.sleep(1) # Insert a one-second pause.
secondsLeft -= 1
except KeyboardInterrupt:
print('Countdown, by Al Sweigart al@inventwithpython.com')
sys.exit() # When Ctrl-C is pressed, end the program.)
"""Deep Cave, by Al Sweigart al@inventwithpython.com
An animation of a deep cave that goes forever into the earth.
This and other games are available at https://nostarch.com/XX
Tags: tiny, beginner, scrolling, artistic"""
__version__ = 0
import random, sys, time
# Set up the constants:
WIDTH = 70 # (!) Try changing this to 10 or 30.
PAUSE_AMOUNT = 0.05 # (!) Try changing this to 0 or 1.0.
print('Deep Cave, by Al Sweigart al@inventwithpython.com')
print('Press Ctrl-C to stop.')
time.sleep(2)
leftWidth = 20
gapWidth = 10
while True:
# Display the tunnel segment:
rightWidth = WIDTH - gapWidth - leftWidth
print(('#' * leftWidth) + (' ' * gapWidth) + ('#' * rightWidth))
# Check for Ctrl-C press during the brief pause:
try:
time.sleep(PAUSE_AMOUNT)
except KeyboardInterrupt:
sys.exit() # When Ctrl-C is pressed, end the program.
# Adjust the left side width:
diceRoll = random.randint(1, 6)
if diceRoll == 1 and leftWidth > 1:
leftWidth = leftWidth - 1 # Decrease left side width.
elif diceRoll == 2 and leftWidth + gapWidth < WIDTH - 1:
leftWidth = leftWidth + 1 # Increase left side width.
else:
pass # Do nothing; no change in left side width.
# Adjust the gap width:
# (!) Try uncommenting out all of the following code:
#diceRoll = random.randint(1, 6)
#if diceRoll == 1 and gapWidth > 1:
# gapWidth = gapWidth - 1 # Decrease gap width.
#elif diceRoll == 2 and leftWidth + gapWidth < WIDTH - 1:
# gapWidth = gapWidth + 1 # Increase gap width.
#else:
# pass # Do nothing; no change in gap width.
"""Diagonal Maze, by Al Sweigart al@inventwithpython.com
Prints out a random, diagonal maze. (It is not a true
maze, but rather an artistic maze-like picture.)
Inspired by the "10 PRINT CHR$(205.5+RND(1)); : GOTO 10" program.
This and other games are available at https://nostarch.com/XX
Tags: tiny, beginner, artistic, maze"""
__version__ = 0
import random
FORWARD_SLASH = chr(9585) # The ╱ character.
BACK_SLASH = chr(9586) # The ╲ character.
# (A list of chr() codes is at https://inventwithpython.com/charactermap)
for x in range(2000): # Loop for each slash in the current line.
# Randomly add a forward or back slash to the line.
if random.randint(0, 1) == 0:
print(FORWARD_SLASH, end='')
else:
print(BACK_SLASH, end='')
r"""Diamonds, by Al Sweigart al@inventwithpython.com
Draws diamonds of various sizes.
/\ /\
/ \ //\\
/\ /\ / \ ///\\\
/ \ //\\ / \ ////\\\\
/\ /\ / \ ///\\\ \ / \\\\////
/ \ //\\ \ / \\\/// \ / \\\///
\ / \\// \ / \\// \ / \\//
\/ \/ \/ \/ \/ \/
Tags: tiny, beginner, artistic"""
__version__ = 0
def main():
print('Diamonds, by Al Sweigart al@inventwithpython.com')
# Display diamonds of sizes 0 through 6:
for diamondSize in range(0, 6):
displayOutlineDiamond(diamondSize)
print() # Print a newline.
displayFilledDiamond(diamondSize)
print() # Print a newline.
def displayOutlineDiamond(size):
# Display the top half of the diamond:
for i in range(size):
print(' ' * (size - i - 1), end='') # Left side space.
print('/', end='') # Left side of diamond.
print(' ' * (i * 2), end='') # Interior of diamond.
print('\\') # Right side of diamond.
# Display the bottom half of the diamond:
for i in range(size):
print(' ' * i, end='') # Left side space.
print('\\', end='') # Left side of diamond.
print(' ' * ((size - i - 1) * 2), end='') # Interior of diamond.
print('/') # Right side of diamond.
def displayFilledDiamond(size):
# Display the top half of the diamond:
for i in range(size):
print(' ' * (size - i - 1), end='') # Left side space.
print('/' * (i + 1), end='') # Left half of diamond.
print('\\' * (i + 1)) # Right half of diamond.
# Display the bottom half of the diamond:
for i in range(size):
print(' ' * i, end='') # Left side space.
print('\\' * (size - i), end='') # Left half of diamond.
print('/' * (size - i)) # Right half of diamond.
# If this program was run (instead of imported), run the game:
if __name__ == '__main__':
main()
"""
Кубики та математика, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import random
import time
# Set up the constants:
DICE_WIDTH = 9
DICE_HEIGHT = 5
CANVAS_WIDTH = 79
CANVAS_HEIGHT = 24 - 3 # -3 for room to enter the sum at the bottom.
# The duration is in seconds:
QUIZ_DURATION = 30 # (!) Try changing this to 10 or 60.
MIN_DICE = 2 # (!) Try changing this to 1 or 5.
MAX_DICE = 6 # (!) Try changing this to 14.
# (!) Try changing these to different numbers:
REWARD = 4 # (!) Points awarded for correct answers.
PENALTY = 1 # (!) Points removed for incorrect answers.
# (!) Try setting PENALTY to a negative number to give points for
# wrong answers!
# The program hangs if all of the dice can't fit on the screen:
assert MAX_DICE <= 14
D1 = (['+-------+',
'| |',
'| O |',
'| |',
'+-------+'], 1)
D2a = (['+-------+',
'| O |',
'| |',
'| O |',
'+-------+'], 2)
D2b = (['+-------+',
'| O |',
'| |',
'| O |',
'+-------+'], 2)
D3a = (['+-------+',
'| O |',
'| O |',
'| O |',
'+-------+'], 3)
D3b = (['+-------+',
'| O |',
'| O |',
'| O |',
'+-------+'], 3)
D4 = (['+-------+',
'| O O |',
'| |',
'| O O |',
'+-------+'], 4)
D5 = (['+-------+',
'| O O |',
'| O |',
'| O O |',
'+-------+'], 5)
D6a = (['+-------+',
'| O O |',
'| O O |',
'| O O |',
'+-------+'], 6)
D6b = (['+-------+',
'| O O O |',
'| |',
'| O O O |',
'+-------+'], 6)
ALL_DICE = [D1, D2a, D2b, D3a, D3b, D4, D5, D6a, D6b]
print('''
Додай всі числа на кубиках які є на екрані. У тебе є {} секунд, щоб
зробити якомога більше ігор. Ти отримаєш {} очків за кожну правильну відповідь
і втратиш {} очків за неправильну.
'''.format(QUIZ_DURATION, REWARD, PENALTY))
input('Тисни Enter щоб почати...')
# Keep track of how many answers were correct and incorrect:
correctAnswers = 0
incorrectAnswers = 0
startTime = time.time()
while time.time() < startTime + QUIZ_DURATION: # Main game loop.
# Come up with the dice to display:
sumAnswer = 0
diceFaces = []
for i in range(random.randint(MIN_DICE, MAX_DICE)):
die = random.choice(ALL_DICE)
# die[0] contains the list of strings of the die face:
diceFaces.append(die[0])
# die[1] contains the integer number of pips on the face:
sumAnswer += die[1]
# Contains (x, y) tuples of the top-left corner of each die.
topLeftDiceCorners = []
# Figure out where dice should go:
for i in range(len(diceFaces)):
while True:
# Find a random place on the canvas to put the die:
left = random.randint(0, CANVAS_WIDTH - 1 - DICE_WIDTH)
top = random.randint(0, CANVAS_HEIGHT - 1 - DICE_HEIGHT)
# Get the x, y coordinates for all four corners:
# left
# v
#top > +-------+ ^
# | O | |
# | O | DICE_HEIGHT (5)
# | O | |
# +-------+ v
# <------->
# DICE_WIDTH (9)
topLeftX = left
topLeftY = top
topRightX = left + DICE_WIDTH
topRightY = top
bottomLeftX = left
bottomLeftY = top + DICE_HEIGHT
bottomRightX = left + DICE_WIDTH
bottomRightY = top + DICE_HEIGHT
# Check if this die overlaps with previous dice.
overlaps = False
for prevDieLeft, prevDieTop in topLeftDiceCorners:
prevDieRight = prevDieLeft + DICE_WIDTH
prevDieBottom = prevDieTop + DICE_HEIGHT
# Check each corner of this die to see if it is inside
# of the area the previous die:
for cornerX, cornerY in ((topLeftX, topLeftY),
(topRightX, topRightY),
(bottomLeftX, bottomLeftY),
(bottomRightX, bottomRightY)):
if (prevDieLeft <= cornerX < prevDieRight
and prevDieTop <= cornerY < prevDieBottom):
overlaps = True
if not overlaps:
# It doesn't overlap, so we can put it here:
topLeftDiceCorners.append((left, top))
break
# Draw the dice on the canvas:
# Keys are (x, y) tuples of ints, values the character at that
# position on the canvas:
canvas = {}
# Loop over each die:
for i, (dieLeft, dieTop) in enumerate(topLeftDiceCorners):
# Loop over each character in the die's face:
dieFace = diceFaces[i]
for dx in range(DICE_WIDTH):
for dy in range(DICE_HEIGHT):
# Copy this character to the correct place on the canvas:
canvasX = dieLeft + dx
canvasY = dieTop + dy
# Note that in dieFace, a list of strings, the x and y
# are swapped:
canvas[(canvasX, canvasY)] = dieFace[dy][dx]
# Display the canvas on the screen:
for cy in range(CANVAS_HEIGHT):
for cx in range(CANVAS_WIDTH):
print(canvas.get((cx, cy), ' '), end='')
print() # Print a newline.
# Let the player enter their answer:
response = input('Введи суму: ').strip()
if response.isdecimal() and int(response) == sumAnswer:
correctAnswers += 1
else:
print('Невірно, сума дорівнює', sumAnswer)
time.sleep(2)
incorrectAnswers += 1
# Display the final score:
score = (correctAnswers * REWARD) - (incorrectAnswers * PENALTY)
print('Вірно: ', correctAnswers)
print('Невірно: ', incorrectAnswers)
print('Рахунок: ', score)
"""
Цифровий годинник, Al Sweigart al@inventwithpython.com, адаптував Данило (danbst)
"""
import sys, time
def getSevSegStr(number, padcount):
digits = [
' _ .| |.|_|',
' . |. |',
' _ . _|.|_ ',
' _ . _|. _|',
' .|_|. |',
' _ .|_ . _|',
' _ .|_ .|_|',
' _ . |. |',
' _ .|_|.|_|',
' _ .|_|. _|',
]
num_d = [ ord(x) - ord('0') for x in str(number).ljust(padcount,'0')]
num_s = [ digits[d].split('.') for d in num_d ]
num_real = [ ''.join(row) for row in zip(*num_s) ]
return '\n'.join(num_real)
try:
while True: # Main program loop.
# Clear the screen by printing several newlines:
print('\n' * 60)
# Get the current time from the computer's clock:
currentTime = time.localtime()
# % 12 so we use a 12-hour clock, not 24:
hours = str(currentTime.tm_hour % 12)
if hours == '0':
hours = '12' # 12-hour clocks show 12:00, not 00:00.
minutes = str(currentTime.tm_min)
seconds = str(currentTime.tm_sec)
# Get the digit strings from the sevseg module:
hDigits = getSevSegStr(hours, 2)
hTopRow, hMiddleRow, hBottomRow = hDigits.splitlines()
mDigits = getSevSegStr(minutes, 2)
mTopRow, mMiddleRow, mBottomRow = mDigits.splitlines()
sDigits = getSevSegStr(seconds, 2)
sTopRow, sMiddleRow, sBottomRow = sDigits.splitlines()
# Display the digits:
print(hTopRow + ' ' + mTopRow + ' ' + sTopRow)
print(hMiddleRow + ' * ' + mMiddleRow + ' * ' + sMiddleRow)
print(hBottomRow + ' * ' + mBottomRow + ' * ' + sBottomRow)
print()
print('Press Ctrl-C to quit.')
# Keep looping until the second changes:
while True:
time.sleep(0.01)
if time.localtime().tm_sec != currentTime.tm_sec:
break
except KeyboardInterrupt:
print('Digital Clock, by Al Sweigart al@inventwithpython.com')
sys.exit() # When Ctrl-C is pressed, end the program.
"""Digital Stream, by Al Sweigart al@inventwithpython.com
A screensaver in the style of The Matrix movie's visuals.
This and other games are available at https://nostarch.com/XX
Tags: tiny, artistic, beginner, scrolling"""
__version__ = 0
import random, shutil, sys, time
# Set up the constants:
MIN_STREAM_LENGTH = 6 # (!) Try changing this to 1 or 50.
MAX_STREAM_LENGTH = 14 # (!) Try changing this to 100.
PAUSE = 0.1 # (!) Try changing this to 0.0 or 2.0.
STREAM_CHARS = ['0', '1'] # (!) Try changing this other characters.
# Density can range from 0.0 to 1.0:
DENSITY = 0.02 # (!) Try changing this to 0.10 or 0.30.
# Get the size of the terminal window:
WIDTH = shutil.get_terminal_size()[0]
# We can't print to the last column on Windows without it adding a
# newline automatically, so reduce the width by one:
WIDTH -= 1
print('Digital Stream Screensaver, by Al Sweigart al@inventwithpython.com')
print('Press Ctrl-C to quit.')
time.sleep(2)
try:
# For each column, when the counter is 0, no stream is shown.
# Otherwise, it acts as a counter for how many times a 1 or 0
# should be displayed in that column.
columns = [0] * WIDTH
while True:
# Set up the counter for each column:
for i in range(WIDTH):
if columns[i] == 0:
if random.random() <= DENSITY:
# Restart a stream on this column.
columns[i] = random.randint(MIN_STREAM_LENGTH,
MAX_STREAM_LENGTH)
# Display an empty space or a 1/0 character.
if columns[i] > 0:
print(random.choice(STREAM_CHARS), end='')
columns[i] -= 1
else:
print(' ', end='')
print() # Print a newline at the end of the row of columns.
sys.stdout.flush() # Make sure text appears on the screen.
time.sleep(PAUSE)
except KeyboardInterrupt:
sys.exit() # When Ctrl-C is pressed, end the program.
"""DNA, by Al Sweigart al@inventwithpython.com
A simple animation of a DNA double-helix. Press Ctrl-C to stop.
Inspired by matoken https://asciinema.org/a/155441
This and other games are available at https://nostarch.com/XX
Tags: short, artistic, scrolling, science"""
__version__ = 0
import random, sys, time
PAUSE = 0.15 # (!) Try changing this to 0.5 or 0.0.
# These are the individual rows of the DNA animation:
ROWS = [
#123456789 <- Use this to measure the number of spaces:
' ##', # Index 0 has no {}.
' #{}-{}#',
' #{}---{}#',
' #{}-----{}#',
' #{}------{}#',
' #{}------{}#',
' #{}-----{}#',
' #{}---{}#',
' #{}-{}#',
' ##', # Index 9 has no {}.
' #{}-{}#',
' #{}---{}#',
' #{}-----{}#',
' #{}------{}#',
' #{}------{}#',
' #{}-----{}#',
' #{}---{}#',
' #{}-{}#']
#123456789 <- Use this to measure the number of spaces:
try:
print('DNA Animation, by Al Sweigart al@inventwithpython.com')
print('Press Ctrl-C to quit...')
time.sleep(2)
rowIndex = 0
while True: # Main program loop.
# Increment rowIndex to draw next row:
rowIndex = rowIndex + 1
if rowIndex == len(ROWS):
rowIndex = 0
# Row indexes 0 and 9 don't have nucleotides:
if rowIndex == 0 or rowIndex == 9:
print(ROWS[rowIndex])
continue
# Select random nucleotide pairs, guanine-cytosine and
# adenine-thymine:
randomSelection = random.randint(1, 4)
if randomSelection == 1:
leftNucleotide, rightNucleotide = 'A', 'T'
elif randomSelection == 2:
leftNucleotide, rightNucleotide = 'T', 'A'
elif randomSelection == 3:
leftNucleotide, rightNucleotide = 'C', 'G'
elif randomSelection == 4:
leftNucleotide, rightNucleotide = 'G', 'C'
# Print the row.
print(ROWS[rowIndex].format(leftNucleotide, rightNucleotide))
time.sleep(PAUSE) # Add a slight pause.
except KeyboardInterrupt:
sys.exit() # When Ctrl-C is pressed, end the program.
if True:
import turtle
turtle.speed(0)
turtle.clear()
def dragon(level):
if level == 1:
return [90]
else:
previous = dragon(level - 1)
return previous + [90] + [-x for x in previous][::-1]
for action in dragon(15):
turtle.forward(3)
turtle.left(action)
"""Etching Drawer, by Al Sweigart al@inventwithpython.com
An art program that draws a continuous line around the screen using the
WASD keys. Inspired by Etch A Sketch toys.
For example, you can draw Hilbert Curve fractal with:
SDWDDSASDSAAWASSDSASSDWDSDWWAWDDDSASSDWDSDWWAWDWWASAAWDWAWDDSDW
Or an even larger Hilbert Curve fractal with:
DDSAASSDDWDDSDDWWAAWDDDDSDDWDDDDSAASDDSAAAAWAASSSDDWDDDDSAASDDSAAAAWA
ASAAAAWDDWWAASAAWAASSDDSAASSDDWDDDDSAASDDSAAAAWAASSDDSAASSDDWDDSDDWWA
AWDDDDDDSAASSDDWDDSDDWWAAWDDWWAASAAAAWDDWAAWDDDDSDDWDDSDDWDDDDSAASDDS
AAAAWAASSDDSAASSDDWDDSDDWWAAWDDDDDDSAASSDDWDDSDDWWAAWDDWWAASAAAAWDDWA
AWDDDDSDDWWAAWDDWWAASAAWAASSDDSAAAAWAASAAAAWDDWAAWDDDDSDDWWWAASAAAAWD
DWAAWDDDDSDDWDDDDSAASSDDWDDSDDWWAAWDD
This and other games are available at https://nostarch.com/XX
Tags: large, artistic"""
__version__ = 0
import shutil, sys
# Set up the constants for line characters:
UP_DOWN_CHAR = chr(9474) # Character 9474 is '│'
LEFT_RIGHT_CHAR = chr(9472) # Character 9472 is '─'
DOWN_RIGHT_CHAR = chr(9484) # Character 9484 is '┌'
DOWN_LEFT_CHAR = chr(9488) # Character 9488 is '┐'
UP_RIGHT_CHAR = chr(9492) # Character 9492 is '└'
UP_LEFT_CHAR = chr(9496) # Character 9496 is '┘'
UP_DOWN_RIGHT_CHAR = chr(9500) # Character 9500 is '├'
UP_DOWN_LEFT_CHAR = chr(9508) # Character 9508 is '┤'
DOWN_LEFT_RIGHT_CHAR = chr(9516) # Character 9516 is '┬'
UP_LEFT_RIGHT_CHAR = chr(9524) # Character 9524 is '┴'
CROSS_CHAR = chr(9532) # Character 9532 is '┼'
# A list of chr() codes is at https://inventwithpython.com/chr
# Get the size of the terminal window:
CANVAS_WIDTH, CANVAS_HEIGHT = shutil.get_terminal_size()
# We can't print to the last column on Windows without it adding a
# newline automatically, so reduce the width by one:
CANVAS_WIDTH -= 1
# Leave room at the bottom few rows for the command info lines.
CANVAS_HEIGHT -= 5
"""The keys for canvas will be (x, y) integer tuples for the coordinate,
and the value is a set of letters W, A, S, D that tell what kind of line
should be drawn."""
canvas = {}
cursorX = 0
cursorY = 0
def getCanvasString(canvasData, cx, cy):
"""Returns a multiline string of the line drawn in canvasData."""
canvasStr = ''
"""canvasData is a dictionary with (x, y) tuple keys and values that
are sets of 'W', 'A', 'S', and/or 'D' strings to show which
directions the lines are drawn at each xy point."""
for rowNum in range(CANVAS_HEIGHT):
for columnNum in range(CANVAS_WIDTH):
if columnNum == cx and rowNum == cy:
canvasStr += '#'
continue
# Add the line character for this point to canvasStr.
cell = canvasData.get((columnNum, rowNum))
if cell in (set(['W', 'S']), set(['W']), set(['S'])):
canvasStr += UP_DOWN_CHAR
elif cell in (set(['A', 'D']), set(['A']), set(['D'])):
canvasStr += LEFT_RIGHT_CHAR
elif cell == set(['S', 'D']):
canvasStr += DOWN_RIGHT_CHAR
elif cell == set(['A', 'S']):
canvasStr += DOWN_LEFT_CHAR
elif cell == set(['W', 'D']):
canvasStr += UP_RIGHT_CHAR
elif cell == set(['W', 'A']):
canvasStr += UP_LEFT_CHAR
elif cell == set(['W', 'S', 'D']):
canvasStr += UP_DOWN_RIGHT_CHAR
elif cell == set(['W', 'S', 'A']):
canvasStr += UP_DOWN_LEFT_CHAR
elif cell == set(['A', 'S', 'D']):
canvasStr += DOWN_LEFT_RIGHT_CHAR
elif cell == set(['W', 'A', 'D']):
canvasStr += UP_LEFT_RIGHT_CHAR
elif cell == set(['W', 'A', 'S', 'D']):
canvasStr += CROSS_CHAR
elif cell == None:
canvasStr += ' '
canvasStr += '\n' # Add a newline at the end of each row.
return canvasStr
moves = []
while True: # Main program loop.
# Draw the lines based on the data in canvas:
print(getCanvasString(canvas, cursorX, cursorY))
print('WASD keys to move, H for help, C to clear, '
+ 'F to save, or QUIT.')
response = input('> ').upper()
if response == 'QUIT':
print('Thanks for playing!')
sys.exit() # Quit the program.
elif response == 'H':
print('Enter W, A, S, and D characters to move the cursor and')
print('draw a line behind it as it moves. For example, ddd')
print('draws a line going right and sssdddwwwaaa draws a box.')
print()
print('You can save your drawing to a text file by entering F.')
input('Press Enter to return to the program...')
continue
elif response == 'C':
canvas = {} # Erase the canvas data.
moves.append('C') # Record this move.
elif response == 'F':
# Save the canvas string to a text file:
try:
print('Enter filename to save to:')
filename = input('> ')
# Make sure the filename ends with .txt:
if not filename.endswith('.txt'):
filename += '.txt'
with open(filename, 'w', encoding='utf-8') as file:
file.write(''.join(moves) + '\n')
file.write(getCanvasString(canvas, None, None))
except:
print('ERROR: Could not save file.')
for command in response:
if command not in ('W', 'A', 'S', 'D'):
continue # Ignore this letter and continue to the next one.
moves.append(command) # Record this move.
# The first line we add needs to form a full line:
if canvas == {}:
if command in ('W', 'S'):
# Make the first line a horizontal one:
canvas[(cursorX, cursorY)] = set(['W', 'S'])
elif command in ('A', 'D'):
# Make the first line a vertical one:
canvas[(cursorX, cursorY)] = set(['A', 'D'])
# Update x and y:
if command == 'W' and cursorY > 0:
canvas[(cursorX, cursorY)].add(command)
cursorY = cursorY - 1
elif command == 'S' and cursorY < CANVAS_HEIGHT - 1:
canvas[(cursorX, cursorY)].add(command)
cursorY = cursorY + 1
elif command == 'A' and cursorX > 0:
canvas[(cursorX, cursorY)].add(command)
cursorX = cursorX - 1
elif command == 'D' and cursorX < CANVAS_WIDTH - 1:
canvas[(cursorX, cursorY)].add(command)
cursorX = cursorX + 1
else:
# If the cursor doesn't move because it would have moved off
# the edge of the canvas, then don't change the set at
# canvas[(cursorX, cursorY)].
continue
# If there's no set for (cursorX, cursorY), add an empty set:
if (cursorX, cursorY) not in canvas:
canvas[(cursorX, cursorY)] = set()
# Add the direction string to this xy point's set:
if command == 'W':
canvas[(cursorX, cursorY)].add('S')
elif command == 'S':
canvas[(cursorX, cursorY)].add('W')
elif command == 'A':
canvas[(cursorX, cursorY)].add('D')
elif command == 'D':
canvas[(cursorX, cursorY)].add('A')
"""
Ковбой, Al Sweigart al@inventwithpython.com, переклав Данило (danbst)
"""
import random, sys, time
print('''
Найшвидший ковбой
Час перевірити твої рефлекси, і побачити хто найшвидший ковбой
на всьому Дикому Заході!
Коли ти побачиш "ТЯГНИ!", у тебе є 0.3 секунди щоб натиснути Enter.
Якщо ти будеш повільний, то програєш. Але якщо натиснеш наперед -- також програєш.
Тисни Enter для початку...
''')
input()
while True:
print()
print('Жарке полуденне сонце освічувало майже порожню вулицю...')
time.sleep(random.randint(20, 50) / 10.0)
print('ТЯГНИ!')
drawTime = time.time()
input() # This function call doesn't return until Enter is pressed.
timeElapsed = time.time() - drawTime
if timeElapsed < 0.01:
# If the player pressed Enter before DRAW! appeared, the input()
# call returns almost instantly.
print('Ти витягнув зарано, ти програв!')
elif timeElapsed > 0.3:
timeElapsed = round(timeElapsed, 4)
print('Ти витягнув за', timeElapsed, 'секунд. Повільний як черепаха!')
else:
timeElapsed = round(timeElapsed, 4)
print('Ти витягнув за', timeElapsed, 'секунд.')
print('Ти найшвидший ковбой на всьому Дикому Заході! Молодець!')
print('Введи QUIT щоб вийти, або натисни Enter щоб зіграти ще раз')
response = input('> ').upper()
if response == 'QUIT':
print('Дякую за гру!')
sys.exit()
"""Fireflies, by Al Sweigart al@inventwithpython.com
A beautiful animation of fireflies. Press Ctrl-C to stop.
This program MUST be run in a Terminal/Command Prompt window.
This and other games are available at https://nostarch.com/XX
Tags: large, artistic, bext"""
__version__ = 0
import math, time, sys, os, random
# This program draws 3D points that rotate around a center point. This
# gives the fireflies a "swirling" kind of movement.
# Set up the constants:
PAUSE_AMOUNT = 0.15 # (!) Try changing this to 0.05 or 0.5.
NUMBER_OF_FIREFLIES = 16 # (!) Try changing this to 2 or 100.
LIT_DURATION = 3 # (!) Try changing this to 100.
MIN_LIT_FREQ = 10
MAX_LIT_FREQ = 40
WIDTH, HEIGHT = 80, 24 # Width & height of the swarm, in text cells.
SCALEX = (WIDTH - 4) // 4
SCALEY = (HEIGHT - 4) // 4
# Text cells are twice as tall as they are wide, so adjust SCALEY:
SCALEY = SCALEY * 2
TRANSLATEX = (WIDTH - 4) // 2 # Put the swarm in the screen's center.
TRANSLATEY = (HEIGHT - 4) // 2
FIREFLY_DARK = '.' # Draw a period for normal fireflies.
FIREFLY_LIGHT = chr(9604) # Draw a block for lit up fireflies.
# Several of the data structures are lists/tuples with x, y, z at
# indexes 0, 1, and 2 respectively. We'll use constants for them:
X, Y, Z = 0, 1, 2
def main():
# First we create data structures for our fireflies.
# Each firefly is represented by dictionary with keys
# 'originalPosition', 'rotationAmount', 'rotVelocity',
# 'timeToLit', 'isLit'.
fireflies = []
for i in range(NUMBER_OF_FIREFLIES):
firefly = {} # The dictionary for a new, single firefly.
# Create the original XYZ positions of the firefly. (Really,
# they're just random points on a sphere that rotate around.)
# Create points on a sphere from random latitude and longitude:
latitude = math.acos(2 * random.random() - 1) - (math.pi / 2)
longitude = 2 * math.pi * random.random()
# Convert the latitude and longitude to an xyz point:
x = math.cos(latitude) * math.cos(longitude)
y = math.cos(latitude) * math.sin(longitude)
z = math.sin(latitude)
firefly['originalPosition'] = (x, y, z)
# Firefly positions start with no rotation:
firefly['rotAmounts'] = [0, 0, 0] # x, y, and z rotation.
# Randomly choose rotation velocity for each axis:
firefly['rotVelocity'] = [
random.randint(-100, 100) / 1000.0,
random.randint(-100, 100) / 1000.0,
random.randint(-100, 100) / 1000.0,
]
# Holds time until the firefly changes between light/dark:
firefly['timeToLit'] = random.randint(MIN_LIT_FREQ, MAX_LIT_FREQ)
# Fireflies start off dark:
firefly['isLit'] = False
# Append this dictionary to the list of firefly dictionaries:
fireflies.append(firefly)
# Next, we animate and display the fireflies on the screen:
while True: # Main program loop.
# lightPoints is a list of (x, y) tuples for where lit up
# fireflies should be displayed on the screen. darkPoints is
# for dark fireflies.
lightPoints = []
darkPoints = []
# Move the fireflies and figure out where to display them:
for firefly in fireflies:
# Change the rotation amount by the rotation velocity:
firefly['rotAmounts'][X] += firefly['rotVelocity'][X]
firefly['rotAmounts'][Y] += firefly['rotVelocity'][Y]
firefly['rotAmounts'][Z] += firefly['rotVelocity'][Z]
# To avoid rounding errors from accumulating, we recalculate
# the rotated position by rotating the original position
# instead of the firefly's last position.
# For example, if the firefly rotates 5 degrees, and then 6
# more degrees, we calculate it's rotation 5 degrees from
# it's original position, and then 11 degrees from its
# original position.
rotatedPoint = rotatePoint(
firefly['originalPosition'][X],
firefly['originalPosition'][Y],
firefly['originalPosition'][Z],
firefly['rotAmounts'][X],
firefly['rotAmounts'][Y],
firefly['rotAmounts'][Z],
)
rotatedAndTransformedPoint = transformPoint(rotatedPoint)
# Determine if the firelies are light or dark:
firefly['timeToLit'] -= 1 # Decrease this each iteration.
if firefly['timeToLit'] <= 0:
if firefly['isLit']:
# Firefly will be dark for a random amount of time:
firefly['timeToLit'] = random.randint(MIN_LIT_FREQ,
MAX_LIT_FREQ)
else:
# Firefly will be light for a set amount of time:
firefly['timeToLit'] = LIT_DURATION
# Toggle isLit to the opposite value:
firefly['isLit'] = not firefly['isLit']
# Determine which character to draw on the screen:
if firefly['isLit']:
lightPoints.append(rotatedAndTransformedPoint)
else:
darkPoints.append(rotatedAndTransformedPoint)
# Display the animate firefly scene:
displayFireflies(lightPoints, darkPoints)
time.sleep(PAUSE_AMOUNT) # Pause before erasing the screen.
clearScreen()
def rotatePoint(x, y, z, ax, ay, az):
"""Returns a 3D point that is rotated from the x, y, z point
arguments. This new point is rotated around the (0, 0, 0) origin
by angles ax, ay, az (in radians).
Directions of each axis:
-y
|
+-- +x
/
+z
"""
# Rotate around x axis:
rotatedX = x
rotatedY = (y * math.cos(ax)) - (z * math.sin(ax))
rotatedZ = (y * math.sin(ax)) + (z * math.cos(ax))
x, y, z = rotatedX, rotatedY, rotatedZ
# Rotate around y axis:
rotatedX = (z * math.sin(ay)) + (x * math.cos(ay))
rotatedY = y
rotatedZ = (z * math.cos(ay)) - (x * math.sin(ay))
x, y, z = rotatedX, rotatedY, rotatedZ
# Rotate around z axis:
rotatedX = (x * math.cos(az)) - (y * math.sin(az))
rotatedY = (x * math.sin(az)) + (y * math.cos(az))
rotatedZ = z
return (rotatedX, rotatedY, rotatedZ)
def transformPoint(point):
"""Resizes this 2D point by a scale of scalex and scaley, then moves
the point by translatex and translatey."""
return (int(point[X] * SCALEX + TRANSLATEX),
int(point[Y] * SCALEY + TRANSLATEY))
def displayFireflies(lightPoints, darkPoints):
# Loop over every place on the screen and draw fireflies:
for y in range(HEIGHT):
for x in range(WIDTH):
if (x, y) in lightPoints:
print(FIREFLY_LIGHT, end='') # Display lit firefly.
elif (x, y) in darkPoints:
print(FIREFLY_DARK, end='') # Display dark firefly.
else:
print(' ', end='') # Display an empty space.
print() # Print a newline.
print('Press Ctrl-C to quit.', end='', flush=True)
def clearScreen():
"""Clear the terminal window screen by running cls or clear."""
if sys.platform == 'win32':
os.system('cls') # Windows uses the cls command.
else:
os.system('clear') # macOS and Linux use the clear command.
# If this program was run (instead of imported), run the game:
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('Fireflies, by Al Sweigart al@inventwithpython.com')
sys.exit() # When Ctrl-C is pressed, end the program.
"""Flood It (Letter Version), by Al Sweigart al@inventwithpython.com
A colorful game where you try to fill the board with a single color.
(This version uses letters instead of colors for colorblind users.)
This and other games are available at https://nostarch.com/XX
Tags: short, game"""
__version__ = 0
import random, sys
# Set up the constants:
WIDTH = 16
HEIGHT = 14
# All the letters used on the board:
LETTERS = ('s', 'o', 'x', 'm', 'a', 'i')
def main():
print('''Flood It (Letter Version)
By Al Sweigart al@inventwithpython.com
Set the letter of the upper left square, which fills in all the
adjacent squares of that letter. Try to make the entire board the
same letter.''')
gameBoard = getNewBoard()
movesLeft = 20
while True: # Main game loop.
displayBoard(gameBoard)
print('Moves left:', movesLeft)
playerMove = askForPlayerMove()
changeTile(playerMove, gameBoard, 0, 0)
movesLeft -= 1
if hasWon(gameBoard):
displayBoard(gameBoard)
print('You have won!')
break
elif movesLeft == 0:
displayBoard(gameBoard)
print('You have run out of moves!')
break
def getNewBoard():
"""Return a dictionary of a new Flood It board."""
board = {}
# Create random letters for the board.
for x in range(WIDTH):
for y in range(HEIGHT):
board[(x, y)] = random.choice(LETTERS)
# Make several tiles the same letter as their neighbor.
for i in range(WIDTH * HEIGHT):
x = random.randint(0, WIDTH - 2)
y = random.randint(0, HEIGHT - 2)
if random.randint(0, 1) == 0:
board[(x + 1, y)] = board[(x, y)]
else:
board[(x, y + 1)] = board[(x, y)]
return board
def displayBoard(board):
"""Display the board on the screen."""
# Print first row with '>'.
print(' >', end='')
for x in range(WIDTH):
print(board[(x, 0)], end='')
print()
# Print each row after the first.
for y in range(1, HEIGHT):
print(' ', end='')
for x in range(WIDTH):
print(board[(x, y)], end='')
print()
def askForPlayerMove():
"""Let the player select a letter to paint the upper left tile."""
while True:
print('Choose one of s o x m a i or QUIT.')
move = input('> ').lower()
if move == 'quit':
sys.exit()
if move in LETTERS:
return move
def changeTile(move, board, x, y, charToChange=None):
"""Change the letter of a tile."""
if x == 0 and y == 0:
charToChange = board[(x, y)]
if move == charToChange:
return # Already is the same letter.
board[(x, y)] = move
if x > 0 and board[(x - 1, y)] == charToChange:
changeTile(move, board, x - 1, y, charToChange)
if y > 0 and board[(x, y - 1)] == charToChange:
changeTile(move, board, x, y - 1, charToChange)
if x < WIDTH - 1 and board[(x + 1, y)] == charToChange:
changeTile(move, board, x + 1, y, charToChange)
if y < HEIGHT - 1 and board[(x, y + 1)] == charToChange:
changeTile(move, board, x, y + 1, charToChange)
def hasWon(board):
"""Return True if the entire board is one letter."""
tile = board[(0, 0)]
for x in range(WIDTH):
for y in range(HEIGHT):
if board[(x, y)] != tile:
return False
return True
# If this program was run (instead of imported), run the game:
if __name__ == '__main__':
main()
"""Four in a Row, by Al Sweigart al@inventwithpython.com
A tile-dropping game to get four in a row, similar to Connect Four.
This and other games are available at https://nostarch.com/XX
Tags: large, game, board game, two-player"""
__version__ = 0
import sys
# Constants used for displaying the board:
EMPTY_SPACE = '.' # A period is easier to count than a space.
PLAYER_X = 'X'
PLAYER_O = 'O'
# Note: Update displayBoard() & COLUMN_LABELS if BOARD_WIDTH is changed.
BOARD_WIDTH = 7
BOARD_HEIGHT = 6
COLUMN_LABELS = ('1', '2', '3', '4', '5', '6', '7')
assert len(COLUMN_LABELS) == BOARD_WIDTH
def main():
print("""Four in a Row, by Al Sweigart al@inventwithpython.com
Two players take turns dropping tiles into one of seven columns, trying
to make four in a row horizontally, vertically, or diagonally.
""")
# Set up a new game:
gameBoard = getNewBoard()
playerTurn = PLAYER_X
while True: # Run a player's turn.
# Display the board and get player's move:
displayBoard(gameBoard)
playerMove = askForPlayerMove(playerTurn, gameBoard)
gameBoard[playerMove] = playerTurn
# Check for a win or tie:
if isWinner(playerTurn, gameBoard):
displayBoard(gameBoard) # Display the board one last time.
print('Player ' + playerTurn + ' has won!')
sys.exit()
elif isFull(gameBoard):
displayBoard(gameBoard) # Display the board one last time.
print('There is a tie!')
sys.exit()
# Switch turns to other player:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
def getNewBoard():
"""Returns a dictionary that represents a Four in a Row board.
The keys are (columnIndex, rowIndex) tuples of two integers, and the
values are one of the 'X', 'O' or '.' (empty space) strings."""
board = {}
for columnIndex in range(BOARD_WIDTH):
for rowIndex in range(BOARD_HEIGHT):
board[(columnIndex, rowIndex)] = EMPTY_SPACE
return board
def displayBoard(board):
"""Display the board and its tiles on the screen."""
'''Prepare a list to pass to the format() string method for the
board template. The list holds all of the board's tiles (and empty
spaces) going left to right, top to bottom:'''
tileChars = []
for rowIndex in range(BOARD_HEIGHT):
for columnIndex in range(BOARD_WIDTH):
tileChars.append(board[(columnIndex, rowIndex)])
# Display the board:
print("""
1234567
+-------+
|{}{}{}{}{}{}{}|
|{}{}{}{}{}{}{}|
|{}{}{}{}{}{}{}|
|{}{}{}{}{}{}{}|
|{}{}{}{}{}{}{}|
|{}{}{}{}{}{}{}|
+-------+""".format(*tileChars))
def askForPlayerMove(playerTile, board):
"""Let a player select a column on the board to drop a tile into.
Returns a tuple of the (column, row) that the tile falls into."""
while True: # Keep asking player until they enter a valid move.
print('Player {}, enter a column or QUIT:'.format(playerTile))
response = input('> ').upper().strip()
if response == 'QUIT':
print('Thanks for playing!')
sys.exit()
if response not in COLUMN_LABELS:
print('Enter a number from 1 to {}.'.format(BOARD_WIDTH))
continue # Ask player again for their move.
columnIndex = int(response) - 1 # -1 for 0-based the index.
# If the column is full, ask for a move again:
if board[(columnIndex, 0)] != EMPTY_SPACE:
print('That column is full, select another one.')
continue # Ask player again for their move.
# Starting from the bottom, find the first empty space.
for rowIndex in range(BOARD_HEIGHT - 1, -1, -1):
if board[(columnIndex, rowIndex)] == EMPTY_SPACE:
return (columnIndex, rowIndex)
def isFull(board):
"""Returns True if the `board` has no empty spaces, otherwise
returns False."""
for rowIndex in range(BOARD_HEIGHT):
for columnIndex in range(BOARD_WIDTH):
if board[(columnIndex, rowIndex)] == EMPTY_SPACE:
return False # Found an empty space, so return False.
return True # All spaces are full.
def isWinner(playerTile, board):
"""Returns True if `playerTile` has four tiles in a row on `board`,
otherwise returns False."""
# Go through the entire board, checking for four-in-a-row:
for columnIndex in range(BOARD_WIDTH - 3):
for rowIndex in range(BOARD_HEIGHT):
# Check for horizontal four-in-a-row going right:
tile1 = board[(columnIndex, rowIndex)]
tile2 = board[(columnIndex + 1, rowIndex)]
tile3 = board[(columnIndex + 2, rowIndex)]
tile4 = board[(columnIndex + 3, rowIndex)]
if tile1 == tile2 == tile3 == tile4 == playerTile:
return True
for columnIndex in range(BOARD_WIDTH):
for rowIndex in range(BOARD_HEIGHT - 3):
# Check for vertical four-in-a-row going down:
tile1 = board[(columnIndex, rowIndex)]
tile2 = board[(columnIndex, rowIndex + 1)]
tile3 = board[(columnIndex, rowIndex + 2)]
tile4 = board[(columnIndex, rowIndex + 3)]
if tile1 == tile2 == tile3 == tile4 == playerTile:
return True
for columnIndex in range(BOARD_WIDTH - 3):
for rowIndex in range(BOARD_HEIGHT - 3):
# Check for four-in-a-row going right-down diagonal:
tile1 = board[(columnIndex, rowIndex)]
tile2 = board[(columnIndex + 1, rowIndex + 1)]
tile3 = board[(columnIndex + 2, rowIndex + 2)]
tile4 = board[(columnIndex + 3, rowIndex + 3)]
if tile1 == tile2 == tile3 == tile4 == playerTile:
return True
# Check for four-in-a-row going left-down diagonal:
tile1 = board[(columnIndex + 3, rowIndex)]
tile2 = board[(columnIndex + 2, rowIndex + 1)]
tile3 = board[(columnIndex + 1, rowIndex + 2)]
tile4 = board[(columnIndex, rowIndex + 3)]
if tile1 == tile2 == tile3 == tile4 == playerTile:
return True
return False
# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
main()
"""Nonuniform Fractal Tree Drawer, by Al Sweigart al@inventwithpython.com
Draws nonuniform fractal trees with turtle graphics."""
__version__ = 0
import turtle
import random
import time
PALE_TAN = '#FEF9EE'
DARK_BROWN = '#130d0f'
turtle.bgcolor(PALE_TAN)
turtle.pencolor(DARK_BROWN)
turtle.tracer(10000, 0) # Make the turtle draw faster.
def main():
seed = 0
while True:
# Get psuedorandom numbers for the branch properties:
random.seed(seed)
drawTree(0, -310, 90, seed)
time.sleep(2)
turtle.clear()
seed += 1
turtle.update() # Finish drawing the screen.
turtle.exitonclick() # When user clicks on the window, close it.
def drawBranch(x, y, direction, branchLength):
# if the branch is too small, just quit
if branchLength < 5:
return
# Draw the branch:
branchThickness = max(branchLength / 7.0, 1) + random.randint(-1, 1)
turtle.pensize(branchThickness)
for i in range(4):
turtle.forward(branchLength / 4.0 + random.randint(-10, 10))
turtle.left(random.randint(-8, 8))
if random.randint(0, 5) == 0:
tinyBranchAngle = random.randint(-LEFT_ANGLE, RIGHT_ANGLE)
turtle.right(tinyBranchAngle)
drawBranch(turtle.xcor(), turtle.ycor(), turtle.heading(), branchLength / 2)
turtle.left(tinyBranchAngle)
turtle.pensize(branchThickness)
if random.randint(0, 5) == 0:
branchLength = branchLength * 0.9
# Draw the two recursive branches:
if random.randint(0, 9) != 0:
turtle.left(LEFT_ANGLE)
drawBranch(turtle.xcor(), turtle.ycor(), turtle.heading(), branchLength - LEFT_DECREASE)
turtle.right(LEFT_ANGLE)
if random.randint(0, 9) != 0:
turtle.right(RIGHT_ANGLE)
drawBranch(turtle.xcor(), turtle.ycor(), turtle.heading(), branchLength - RIGHT_DECREASE)
turtle.left(RIGHT_ANGLE)
# Return back to the starting point:
turtle.penup()
turtle.goto(x, y)
turtle.setheading(direction)
turtle.pendown()
def drawTree(x, y, direction, seed):
global LEFT_ANGLE, RIGHT_ANGLE, LEFT_DECREASE, RIGHT_DECREASE
# Go to the starting point:
turtle.penup()
turtle.goto(x, y)
turtle.setheading(direction)
turtle.pendown()
# Try changing these values and looking at the results:
random.seed(seed)
LEFT_ANGLE = random.randint(10, 30)
RIGHT_ANGLE = random.randint(10, 30)
LEFT_DECREASE = random.randint( 6, 15)
RIGHT_DECREASE = random.randint( 6, 15)
START_SIZE = random.randint(80, 120)
# Draw the tree:
drawBranch(x, y, direction, START_SIZE)
turtle.update() # Finish drawing the screen.
try:
main()
except turtle.Terminator:
pass # Do nothing when the turtle window is closed.
"""Fractal Tree Drawer, by Al Sweigart al@inventwithpython.com
Draws fractal trees with turtle graphics."""
__version__ = 0
import random
import time
import turtle
turtle.tracer(1000, 0) # Make the turtle draw faster.
turtle.setworldcoordinates(0, 0, 700, 700)
turtle.hideturtle()
def drawBranch(startPosition, direction, branchLength):
if branchLength < 5:
# Base case; the branches are two small to keep drawing more:
return
# Go to the starting point & direction:
turtle.penup()
turtle.goto(startPosition)
turtle.setheading(direction)
# Draw the branch (thickness is 1/7 the length):
turtle.pendown()
turtle.pensize(max(branchLength / 7.0, 1))
turtle.forward(branchLength)
# Record the position of the branch's end:
endPosition = turtle.position()
leftDirection = direction + LEFT_ANGLE
leftBranchLength = branchLength - LEFT_DECREASE
rightDirection = direction - RIGHT_ANGLE
rightBranchLength = branchLength - RIGHT_DECREASE
# Recursive case; draw two more branches:
drawBranch(endPosition, leftDirection, leftBranchLength)
drawBranch(endPosition, rightDirection, rightBranchLength)
try:
seed = 0
while True: # Main program loop.
# Get psuedorandom numbers for the branch properties:
random.seed(seed)
LEFT_ANGLE = random.randint(10, 30)
LEFT_DECREASE = random.randint( 6, 15)
RIGHT_ANGLE = random.randint(10, 30)
RIGHT_DECREASE = random.randint( 6, 15)
START_LENGTH = random.randint(80, 120)
# Write out the seed number:
turtle.clear()
turtle.penup()
turtle.goto(10, 10)
turtle.write('Seed: %s' % (seed))
# Draw the tree:
drawBranch((350, 10), 90, START_LENGTH)
turtle.update() # Finish drawing the screen.
time.sleep(2)
seed = seed + 1 # Use the next number for the next seed.
except turtle.Terminator:
pass # Do nothing when the turtle window is closed.
"""Hex Grid, by Al Sweigart al@inventwithpython.com
Displays a simple tessellation of a hexagon grid.
This and other games are available at https://nostarch.com/XX
Tags: tiny, beginner, artistic"""
__version__ = 0
# Set up the constants:
# (!) Try changing these values to other numbers:
X_REPEAT = 19 # How many times to tessellate horizontally.
Y_REPEAT = 12 # How many times to tessellate vertically.
for y in range(Y_REPEAT):
# Display the top half of the hexagon:
for x in range(X_REPEAT):
print(r'/ \_', end='')
print()
# Display the bottom half of the hexagon:
for x in range(X_REPEAT):
print(r'\_/ ', end='')
print()
"""Hilbert Curve, by Al Sweigart al@inventwithpython.com
Draws the Hilbert Curve fractal with turtle graphics.
More info at: https://en.wikipedia.org/wiki/hilbertCurve
Good videos on space-filling curves: https://youtu.be/RU0wScIj36o
and https://youtu.be/3s7h2MHQtxc"""
__version__ = 0
import turtle
# Set up the constants:
SIZE = 10 # (!) Try changing the line length by a litte.
ANGLE = 90 # (!) Try changing the turning angle by a litte.
LEVEL = 5 # (!) Try changing the recursive level by a litte.
MAGENTA = '#B20059'
PINK = '#FFE6F2'
def main():
turtle.bgcolor(MAGENTA)
turtle.pencolor(PINK)
turtle.fillcolor(PINK)
turtle.tracer(1, 0) # Make the turtle draw faster.
turtle.penup()
turtle.goto(-320, 0)
turtle.pendown()
#turtle.setheading(20) # (!) Try uncommenting this line.
filledInHilbert()
turtle.update() # Finish drawing the screen.
turtle.exitonclick() # When user clicks on the window, close it.
def hilbertCurve(level, angle):
if level == 0:
return
turtle.right(angle)
hilbertCurve(level - 1, -angle)
turtle.forward(SIZE)
turtle.left(angle)
hilbertCurve(level - 1, angle)
turtle.forward(SIZE)
hilbertCurve(level - 1, angle)
turtle.left(angle)
turtle.forward(SIZE)
hilbertCurve(level - 1, -angle)
turtle.right(angle)
def filledInHilbert():
turtle.begin_fill()
hilbertCurve(LEVEL, ANGLE) # draw first quadrant
turtle.forward(SIZE)
hilbertCurve(LEVEL, ANGLE) # draw second quadrant
turtle.left(ANGLE)
turtle.forward(SIZE)
turtle.left(ANGLE)
hilbertCurve(LEVEL, ANGLE) # draw third quadrant
turtle.forward(SIZE)
hilbertCurve(LEVEL, ANGLE) # draw fourth quadrant
turtle.left(ANGLE)
turtle.forward(SIZE)
turtle.left(ANGLE)
turtle.end_fill()
try:
main()
except turtle.Terminator:
pass # Do nothing when the turtle window is closed.
"""Koch Snowflake, by Al Sweigart al@inventwithpython.com
Draws a Koch snowflake fractal with turtle graphics."""
__version__ = 0
import turtle
turtle.tracer(1, 0) # Make the turtle draw faster.
LEVELS = 5 # More than 5 levels becomes too small to see.
def main():
# Move turtle into the starting position:
LENGTH = 300.0
turtle.penup()
turtle.backward(LENGTH / 2.0)
turtle.right(90)
turtle.backward(1.75 * LENGTH / 2.0)
turtle.left(90)
turtle.pendown()
# Draw the snowflake:
for lev in range(LEVELS):
drawSnowflake(LENGTH, lev)
turtle.update() # Finish drawing the screen.
turtle.exitonclick() # When user clicks on the window, close it.
def snowflakeSide(sideLength, levels):
# Draw a single side of the snowflake (this is called a Koch curve):
turtle.pencolor('black')
if levels == 0:
turtle.forward(sideLength)
return
sideLength = sideLength / 3.0
snowflakeSide(sideLength, levels-1)
# "Erase" the middle segment by drawing a white line over it.
turtle.pencolor('white')
turtle.pensize(2)
turtle.forward(sideLength)
turtle.forward(-sideLength)
turtle.pencolor('black')
turtle.pensize(1)
turtle.left(60)
snowflakeSide(sideLength, levels-1)
turtle.right(120)
snowflakeSide(sideLength, levels-1)
turtle.left(60)
snowflakeSide(sideLength, levels-1)
def drawSnowflake(sideLength, levels):
# Draw 6 Koch curves to draw a Koch snowflake.
for i in range(6):
snowflakeSide(sideLength, levels)
turtle.right(60)
try:
main()
except turtle.Terminator:
pass # Do nothing when the turtle window is closed.
"""Maze Maker, by Al Sweigart al@inventwithpython.com
Make mazes with the recursive backtracker algorithm.
An animated demo: https://scratch.mit.edu/projects/17358777/
This and other games are available at https://nostarch.com/XX
Tags: large, maze"""
__version__ = 0
import random
# Set up the constants:
WALL = '#'
EMPTY = ' '
START = 'S'
EXIT = 'E'
BLOCK = chr(9617) # Character 9617 is '░'
NORTH = 'north'
SOUTH = 'south'
EAST = 'east'
WEST = 'west'
def displayMaze(maze, travelerX=None, travelerY=None):
result = "" # speeding up drawing in Thonny by printing only one line
for y in range(HEIGHT):
for x in range(WIDTH):
if maze[(x, y)] == WALL:
result += BLOCK
#print(BLOCK, end='')
elif travelerX == x and travelerY == y:
result += "@"
#print('@', end='')
else:
result += maze[(x, y)]
#print(maze[(x, y)], end='')
#print() # Print a newline after printing the row.
result += "\n"
print(result)
def saveMaze(maze, filename):
mazeFile = open(filename, 'w')
for y in range(HEIGHT):
for x in range(WIDTH):
mazeFile.write(maze[(x, y)])
mazeFile.write('\n')
mazeFile.close()
print('''Maze Maker (Recursive Backtracker algorithm)
By Al Sweigart al@inventwithpython.com
This program creates maze files. You can play these mazes with
mazerunner.py or maze3d.py''')
WIDTH = 49
while not WIDTH:
response = input('Enter width (must be odd and greater than 2): ')
if response.isdecimal():
WIDTH = int(response)
if WIDTH % 2 == 1 and WIDTH > 2:
break
WIDTH = None
HEIGHT = 21
while not HEIGHT:
response = input('Enter height (must be odd and greater than 2): ')
if response.isdecimal():
HEIGHT = int(response)
if HEIGHT % 2 == 1 and HEIGHT > 2:
break
HEIGHT = None
SEED = random.randrange(10000)
while not SEED:
response = input('Enter seed (must be a positive integer): ')
if response.isdecimal():
SEED = int(response)
break
SEED = None
random.seed(SEED)
#response = input('Watch maze generation step by step? (y/n): ')
#watchGeneration = response.upper().startswith('Y')
watchGeneration = True
# Create the filled-in maze to start:
maze = {}
for x in range(WIDTH):
for y in range(HEIGHT):
maze[(x, y)] = WALL
# Create the maze:
print('Generating maze...')
pathFromStart = [(1, 1)]
hasVisited = [(1, 1)]
while len(pathFromStart) > 0:
x, y = pathFromStart[-1]
maze[(x, y)] = EMPTY
# Display the maze so far:
if watchGeneration:
displayMaze(maze, x, y)
# (!) Uncomment this next line to see how pathFromStart grows
# and shrinks while the algorithm runs.
#print('pathFromStart =', pathFromStart)
print('Press Enter to continue...')
input()
print('\n' * 60) # Clear the screen by printing newlines.
unvisitedNeighbors = []
# Check the north neighbor:
if y > 1 and (x, y - 2) not in hasVisited:
unvisitedNeighbors.append(NORTH)
# Check the south neighbor:
if y < HEIGHT - 2 and (x, y + 2) not in hasVisited:
unvisitedNeighbors.append(SOUTH)
# Check the west neighbor:
if x > 1 and (x - 2, y) not in hasVisited:
unvisitedNeighbors.append(WEST)
# Check the east neighbor:
if x < WIDTH - 2 and (x + 2, y) not in hasVisited:
unvisitedNeighbors.append(EAST)
if len(unvisitedNeighbors) > 0:
nextIntersection = random.choice(unvisitedNeighbors)
if nextIntersection == NORTH:
pathFromStart.append((x, y - 2))
hasVisited.append((x, y - 2))
maze[(x, y - 1)] = EMPTY
elif nextIntersection == SOUTH:
pathFromStart.append((x, y + 2))
hasVisited.append((x, y + 2))
maze[(x, y + 1)] = EMPTY
elif nextIntersection == WEST:
pathFromStart.append((x - 2, y))
hasVisited.append((x - 2, y))
maze[(x - 1, y)] = EMPTY
elif nextIntersection == EAST:
pathFromStart.append((x + 2, y))
hasVisited.append((x + 2, y))
maze[(x + 1, y)] = EMPTY
else:
pathFromStart.pop()
# Add the start and end positions:
maze[(1, 1)] = START
maze[(WIDTH - 2, HEIGHT - 2)] = EXIT
# Display the maze and save it to a text file.
displayMaze(maze)
filename = 'maze{}x{}s{}.txt'.format(WIDTH, HEIGHT, SEED)
saveMaze(maze, filename)
print('Saved to {}.'.format(filename))
"""Maze Runner 2D, by Al Sweigart al@inventwithpython.com
Move around a maze and try to escape. Maze files are generated by
mazemakerrec.py.
This and other games are available at https://nostarch.com/XX
Tags: large, maze"""
__version__ = 0
import sys, os
# Maze file constants:
WALL = '#'
EMPTY = ' '
START = 'S'
EXIT = 'E'
PLAYER = '@'
BLOCK = chr(9617) # Character 9617 is '░'
def displayMaze(maze):
# Display the maze:
for y in range(HEIGHT):
for x in range(WIDTH):
if (x, y) == (playerx, playery):
print(PLAYER, end='')
elif (x, y) == (exitx, exity):
print('X', end='')
elif maze[(x, y)] == WALL:
print(BLOCK, end='')
else:
print(maze[(x, y)], end='')
print() # Print a newline after printing the row.
print('''Maze Runner 2D, by Al Sweigart al@inventwithpython.com
(Maze files are generated by mazemakerrec.py)''')
# Get the maze file's filename from the user:
while True:
print('Enter the filename of the maze (or LIST or QUIT):')
filename = input('> ')
# List all the maze files in the current folder:
if filename.upper() == 'LIST':
print('Maze files found in', os.getcwd())
for fileInCurrentFolder in os.listdir():
if (fileInCurrentFolder.startswith('maze') and
fileInCurrentFolder.endswith('.txt')):
print(' ', fileInCurrentFolder)
continue
if filename.upper() == 'QUIT':
sys.exit()
if os.path.exists(filename):
break
print('There is no file named', filename)
# Load the maze from a file:
mazeFile = open(filename)
maze = {}
lines = mazeFile.readlines()
playerx = None
playery = None
exitx = None
exity = None
y = 0
for line in lines:
WIDTH = len(line.rstrip())
for x, character in enumerate(line.rstrip()):
assert character in (WALL, EMPTY, START, EXIT), 'Invalid character at column {}, line {}'.format(x + 1, y + 1)
if character in (WALL, EMPTY):
maze[(x, y)] = character
elif character == START:
playerx, playery = x, y
maze[(x, y)] = EMPTY
elif character == EXIT:
exitx, exity = x, y
maze[(x, y)] = EMPTY
y += 1
HEIGHT = y
assert playerx != None and playery != None, 'No start in maze file.'
assert exitx != None and exity != None, 'No exit in maze file.'
forward_moves = []
def get_move():
global forward_moves
if forward_moves:
return (False, forward_moves.pop(0))
else:
print(' W')
print('Enter direction, or QUIT: ASD')
moves = input('> ').upper()
if len(moves) > 1:
if moves == 'QUIT':
return (False, 'QUIT')
forward_moves = list(moves)
return (True, [])
return (False, moves)
while True: # Main game loop.
displayMaze(maze)
while True: # Get user move.
skip, move = get_move()
if skip:
continue
if move == 'QUIT':
print('Thanks for playing!')
sys.exit()
if move not in ['W', 'A', 'S', 'D']:
print('Invalid direction. Enter one of W, A, S, or D.')
continue
# Check if the player can move in that direction:
if move == 'W' and maze[(playerx, playery - 1)] == EMPTY:
break
elif move == 'S' and maze[(playerx, playery + 1)] == EMPTY:
break
elif move == 'A' and maze[(playerx - 1, playery)] == EMPTY:
break
elif move == 'D' and maze[(playerx + 1, playery)] == EMPTY:
break
print('You cannot move in that direction.')
# Keep moving in this direction until you encounter a branch point.
if move == 'W':
while True:
playery -= 1
if (playerx, playery) == (exitx, exity):
break
if maze[(playerx, playery - 1)] == WALL:
break # Break if we've hit a wall.
if (maze[(playerx - 1, playery)] == EMPTY
or maze[(playerx + 1, playery)] == EMPTY):
break # Break if we've reached a branch point.
elif move == 'S':
while True:
playery += 1
if (playerx, playery) == (exitx, exity):
break
if maze[(playerx, playery + 1)] == WALL:
break # Break if we've hit a wall.
if (maze[(playerx - 1, playery)] == EMPTY
or maze[(playerx + 1, playery)] == EMPTY):
break # Break if we've reached a branch point.
elif move == 'A':
while True:
playerx -= 1
if (playerx, playery) == (exitx, exity):
break
if maze[(playerx - 1, playery)] == WALL:
break # Break if we've hit a wall.
if (maze[(playerx, playery - 1)] == EMPTY
or maze[(playerx, playery + 1)] == EMPTY):
break # Break if we've reached a branch point.
elif move == 'D':
while True:
playerx += 1
if (playerx, playery) == (exitx, exity):
break
if maze[(playerx + 1, playery)] == WALL:
break # Break if we've hit a wall.
if (maze[(playerx, playery - 1)] == EMPTY
or maze[(playerx, playery + 1)] == EMPTY):
break # Break if we've reached a branch point.
if (playerx, playery) == (exitx, exity):
displayMaze(maze)
print('You have reached the exit! Good job!')
print('Thanks for playing!')
sys.exit()
"""Maze 3D, by Al Sweigart al@inventwithpython.com
Move around a maze and try to escape... in 3D!
This and other games are available at https://nostarch.com/XX
Tags: extra-large, maze, game, artistic"""
__version__ = 0
import copy, sys, os
# Set up the constants:
WALL = '#'
EMPTY = ' '
START = 'S'
EXIT = 'E'
BLOCK = chr(9617) # Character 9617 is '░'
NORTH = 'NORTH'
SOUTH = 'SOUTH'
EAST = 'EAST'
WEST = 'WEST'
def wallStrToWallDict(wallStr):
"""Takes a string representation of a wall drawing (like those in
ALL_OPEN or CLOSED) and returns a representation in a dictionary
with (x, y) tuples as keys and single-character strings of the
character to draw at that x, y location."""
wallDict = {}
height = 0
width = 0
for y, line in enumerate(wallStr.splitlines()):
if y > height:
height = y
for x, character in enumerate(line):
if x > width:
width = x
wallDict[(x, y)] = character
wallDict['height'] = height + 1
wallDict['width'] = width + 1
return wallDict
EXIT_DICT = {(0, 0): 'E', (1, 0): 'X', (2, 0): 'I',
(3, 0): 'T', 'height': 1, 'width': 4}
# The way we create the strings to display is by converting the pictures
# in these multiline strings to dictionaries using wallStrToWallDict().
# Then we compose the wall for the player's location and direction by
# "pasting" the wall dictionaries in CLOSED on top of the wall dictionary
# in ALL_OPEN.
ALL_OPEN = wallStrToWallDict(r'''
.................
____.........____
...|\......./|...
...||.......||...
...||__...__||...
...||.|\./|.||...
...||.|.X.|.||...
...||.|/.\|.||...
...||_/...\_||...
...||.......||...
___|/.......\|___
.................
.................'''.strip())
# The strip() call is used to remove the newline
# at the start of this multiline string.
CLOSED = {}
CLOSED['A'] = wallStrToWallDict(r'''
_____
.....
.....
.....
_____'''.strip()) # Paste to 6, 4.
CLOSED['B'] = wallStrToWallDict(r'''
.\.
..\
...
...
...
../
./.'''.strip()) # Paste to 4, 3.
CLOSED['C'] = wallStrToWallDict(r'''
___________
...........
...........
...........
...........
...........
...........
...........
...........
___________'''.strip()) # Paste to 3, 1.
CLOSED['D'] = wallStrToWallDict(r'''
./.
/..
...
...
...
\..
.\.'''.strip()) # Paste to 10, 3.
CLOSED['E'] = wallStrToWallDict(r'''
..\..
...\_
....|
....|
....|
....|
....|
....|
....|
....|
....|
.../.
../..'''.strip()) # Paste to 0, 0.
CLOSED['F'] = wallStrToWallDict(r'''
../..
_/...
|....
|....
|....
|....
|....
|....
|....
|....
|....
.\...
..\..'''.strip()) # Paste to 12, 0.
def displayWallDict(wallDict):
"""Display a wall dictionary, as returned by wallStrToWallDict(), on
the screen."""
print(BLOCK * (wallDict['width'] + 2))
for y in range(wallDict['height']):
print(BLOCK, end='')
for x in range(wallDict['width']):
wall = wallDict[(x, y)]
if wall == '.':
wall = ' '
print(wall, end='')
print(BLOCK) # Print block with a newline.
print(BLOCK * (wallDict['width'] + 2))
def pasteWallDict(srcWallDict, dstWallDict, left, top):
"""Copy the wall representation dictionary in srcWallDict on top of
the one in dstWallDict, offset to the position given by left, top."""
dstWallDict = copy.copy(dstWallDict)
for x in range(srcWallDict['width']):
for y in range(srcWallDict['height']):
dstWallDict[(x + left, y + top)] = srcWallDict[(x, y)]
return dstWallDict
def makeWallDict(maze, playerx, playery, playerDirection, exitx, exity):
"""From the player's position and direction in the maze (which has
an exit at exitx, exity), create the wall representation dictionary
by pasting wall dictionaries on top of ALL_OPEN, then return it."""
# The A-F "sections" (which are relative to the player's direction)
# determine which walls in the maze we check to see if we need to
# paste them over the wall representation dictionary we're creating.
if playerDirection == NORTH:
# Map of the sections, relative A
# to the player @: BCD (Player facing north)
# E@F
offsets = (('A', 0, -2), ('B', -1, -1), ('C', 0, -1),
('D', 1, -1), ('E', -1, 0), ('F', 1, 0))
if playerDirection == SOUTH:
# Map of the sections, relative F@E
# to the player @: DCB (Player facing south)
# A
offsets = (('A', 0, 2), ('B', 1, 1), ('C', 0, 1),
('D', -1, 1), ('E', 1, 0), ('F', -1, 0))
if playerDirection == EAST:
# Map of the sections, relative EB
# to the player @: @CA (Player facing east)
# FD
offsets = (('A', 2, 0), ('B', 1, -1), ('C', 1, 0),
('D', 1, 1), ('E', 0, -1), ('F', 0, 1))
if playerDirection == WEST:
# Map of the sections, relative DF
# to the player @: AC@ (Player facing west)
# BE
offsets = (('A', -2, 0), ('B', -1, 1), ('C', -1, 0),
('D', -1, -1), ('E', 0, 1), ('F', 0, -1))
section = {}
for sec, xOff, yOff in offsets:
section[sec] = maze.get((playerx + xOff, playery + yOff), WALL)
if (playerx + xOff, playery + yOff) == (exitx, exity):
section[sec] = EXIT
wallDict = copy.copy(ALL_OPEN)
PASTE_CLOSED_TO = {'A': (6, 4), 'B': (4, 3), 'C': (3, 1),
'D': (10, 3), 'E': (0, 0), 'F': (12, 0)}
for sec in 'ABDCEF':
if section[sec] == WALL:
wallDict = pasteWallDict(CLOSED[sec], wallDict,
PASTE_CLOSED_TO[sec][0], PASTE_CLOSED_TO[sec][1])
# Draw the EXIT sign if needed:
if section['C'] == EXIT:
wallDict = pasteWallDict(EXIT_DICT, wallDict, 7, 9)
if section['E'] == EXIT:
wallDict = pasteWallDict(EXIT_DICT, wallDict, 0, 11)
if section['F'] == EXIT:
wallDict = pasteWallDict(EXIT_DICT, wallDict, 13, 11)
return wallDict
print('Maze Runner 3D, by Al Sweigart al@inventwithpython.com')
print('(Maze files are generated by mazemakerrec.py)')
# Get the maze file's filename from the user:
while True:
print('Enter the filename of the maze (or LIST or QUIT):')
filename = input('> ')
# List all the maze files in the current folder:
if filename.upper() == 'LIST':
print('Maze files found in', os.getcwd())
for fileInCurrentFolder in os.listdir():
if (fileInCurrentFolder.startswith('maze')
and fileInCurrentFolder.endswith('.txt')):
print(' ', fileInCurrentFolder)
continue
if filename.upper() == 'QUIT':
sys.exit()
if os.path.exists(filename):
break
print('There is no file named', filename)
# Load the maze from a file:
mazeFile = open(filename)
maze = {}
lines = mazeFile.readlines()
px = None
py = None
exitx = None
exity = None
y = 0
for line in lines:
WIDTH = len(line.rstrip())
for x, character in enumerate(line.rstrip()):
assert character in (WALL, EMPTY, START, EXIT), 'Invalid character at column {}, line {}'.format(x + 1, y + 1)
if character in (WALL, EMPTY):
maze[(x, y)] = character
elif character == START:
px, py = x, y
maze[(x, y)] = EMPTY
elif character == EXIT:
exitx, exity = x, y
maze[(x, y)] = EMPTY
y += 1
HEIGHT = y
assert px != None and py != None, 'No start point in file.'
assert exitx != None and exity != None, 'No exit point in file.'
pDir = NORTH
while True: # Main game loop.
displayWallDict(makeWallDict(maze, px, py, pDir, exitx, exity))
while True: # Get user move.
print('Location ({}, {}) Direction: {}'.format(px, py, pDir))
print(' (W)')
print('Enter direction: (A) (D) or QUIT.')
move = input('> ').upper()
if move == 'QUIT':
print('Thanks for playing!')
sys.exit()
if (move not in ['F', 'L', 'R', 'W', 'A', 'D']
and not move.startswith('T')):
print('Please enter one of F, L, or R (or W, A, D).')
continue
# Move the player according to their intended move:
if move == 'F' or move == 'W':
if pDir == NORTH and maze[(px, py - 1)] == EMPTY:
py -= 1
break
if pDir == SOUTH and maze[(px, py + 1)] == EMPTY:
py += 1
break
if pDir == EAST and maze[(px + 1, py)] == EMPTY:
px += 1
break
if pDir == WEST and maze[(px - 1, py)] == EMPTY:
px -= 1
break
elif move == 'L' or move == 'A':
pDir = {NORTH: WEST, WEST: SOUTH,
SOUTH: EAST, EAST: NORTH}[pDir]
break
elif move == 'R' or move == 'D':
pDir = {NORTH: EAST, EAST: SOUTH,
SOUTH: WEST, WEST: NORTH}[pDir]
break
elif move.startswith('T'): # Cheat code: 'T x,y'
px, py = move.split()[1].split(',')
px = int(px)
py = int(py)
break
else:
print('You cannot move in that direction.')
if (px, py) == (exitx, exity):
print('You have reached the exit! Good job!')
print('Thanks for playing!')
sys.exit()
# Взято з https://github.com/ripexz/python-tkinter-minesweeper
from tkinter import *
from tkinter import messagebox as tkMessageBox
from collections import deque
import random
import platform
import time
from datetime import time, date, datetime
import base64
SIZE_X = 10
SIZE_Y = 10
STATE_DEFAULT = 0
STATE_CLICKED = 1
STATE_FLAGGED = 2
BTN_CLICK = "<Button-1>"
BTN_FLAG = "<Button-2>" if platform.system() == 'Darwin' else "<Button-3>"
window = None
images = {}
images["tile_wrong.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5EKA2(K6zs0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!Ye_^wRCt_Y*hwN_0OGks1B8ZEL;!RR3}674zQx1}VZg<)Yk<fBRYNo&3u18+TpFSQSv7VI$a>IJ<J5p`FtTduX&}u>a7Ce^p@cn+EDZ@LG<)zxTxDe?kPRg9MI1qZqJgx;M-l)4RfUH1w2DYz00000NkvXXu0mjf'
images["tile_2.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5ElkG68s|b0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!KS@MERCt_YcuXQ-pu2_~rdwzTp9W0Tn0l~iz%PPN17RDmIuD;82&%@e0gq}d8t|(|*Fa{llAwVYKzj`UFP37=@pX8200000NkvXXu0mjf'
images["tile_3.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5EljmqxZ|#0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!I!Q!9RCt_YcuXQ-7zhn}m~J5>0vga%W9q@K0T-9BA4t$ZtRKkNK&+EU_B6@Cim8V*KVSmdYXAV?MSNA%eJ*+c0000<MNUMnLSTX'
images["tile_7.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5Ela<%7J6u0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!ElET{RCt_YcuXQ-ps$8oOsrTD^)z4t(llVIrm6<4s;Q>|m+Ar3fCtcC0|3`$a36jYD>(oF002ovPDHLkV1f'
images["tile_plain.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj4-qp8bnS}10000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!B1uF+RCt_Y*hwN_0OGks1B8ZEM1WBZqZ)|OKw9D>2><{l4*<XNp=LP%0000<MNUMnLSTX'
images["tile_mine.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj4-qvRNCyqd0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!IY~r8RCt_Y*hwN_0OGks1B8ZEM1X<Pz`(!&A>j<dHZULoqHI6|)Yd?blSuY7E<k4uq$NI*006ed$mpFe*RB8n002ovPDHLkV1f'
images["tile_4.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5Elg<a@D1G0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!DM>^@RCt_YcuXQ-pu2`!Ov`}?7nfoUn9{V-fQhK50TT=d4VZxT8UW52doM#7A9er$002ovPDHLkV1f'
images["tile_6.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5Eld!jCQ#(0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!Gf6~2RCt_YcuXQ-pu2`!Osr@Kp9W0Tn0l~iAi+swYM`$lXrqAyCt=lt&(p*J+G_v+yp%^L*oKYG00000NkvXXu0mjf'
images["tile_clicked.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj4-+UP0*RP~0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!6iGxuRCt_YcuXQ-7}YSUVfbnQ00=FqAHgP?hX4Qo07*qoM6N<$f&'
images["tile_8.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5ElYAktoXW0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!Gf6~2RCt_YcuXQ-pu2`!Osr@Kp9W0Tn0l~iz%N3X29o_ivIg4wf#hH%*$>13+G_v+Z_Y(u0Q+>$00000NkvXXu0mjf'
images["tile_flag.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj4-q#7fId<y0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!R!KxbRCt_Y*hwN_0OGks1B8ZEL;wOBZZWZvpaH0w1Pu_?G}8cAO_~N0JPlVzS}28vh5|JJNn$lHFfaf$07+ssR9033RRc+4HDCoO8c0igBmn?0jNwj~A7J?a0000<MNUMnLSTX'
images["tile_5.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5EleFSIuze0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!F-b&0RCt_YcuXQ-ps$8oOkr3NwKb6JB#Qh%vIYWvzyu_Fn%cpNRS%j1I;SOK008jsS_M8d$OZra002ovPDHLkV1f'
images["tile_1.png"] = b'iBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs2XskIMF-sj5Elm>K;y^t0000NbVXQnQ*UN;cVTj607pzjP)<i6c4cxPGcGi7g{0vC000Pda85@@OhhvP0000=fGHmU000DMK}|sb0I`n?{9y$E000JJOGiWi{{a60|De66lK=n!FG)l}RCt_YcuXQ-7$6POOt*lDSPc->#A<-6rkMt0Z9`Q9vZt|XqgVq$Kzj`Uw(fB)KLFlz00000NkvXXu0mjf'
def unpack_images(images):
"""
Картинки в коді запаковані в Base85. Потрібно перетворити в PhotoImage
"""
for name, im in images.items():
data = base64.b85decode(im)
image = PhotoImage(format="png", data=data)
images[name] = image
class Minesweeper:
def __init__(self, tk):
# import images
self.images = {
"plain": images['tile_plain.png'],
"clicked": images['tile_clicked.png'],
"mine": images['tile_mine.png'],
"flag": images['tile_flag.png'],
"wrong": images['tile_wrong.png'],
"numbers": []
}
for i in range(1, 9):
self.images["numbers"].append(images["tile_"+str(i)+".png"])
# set up frame
self.tk = tk
self.frame = Frame(self.tk)
self.frame.pack()
# set up labels/UI
self.labels = {
"time": Label(self.frame, text = "00:00:00"),
"mines": Label(self.frame, text = "Mines: 0"),
"flags": Label(self.frame, text = "Flags: 0")
}
self.labels["time"].grid(row = 0, column = 0, columnspan = SIZE_Y) # top full width
self.labels["mines"].grid(row = SIZE_X+1, column = 0, columnspan = int(SIZE_Y/2)) # bottom left
self.labels["flags"].grid(row = SIZE_X+1, column = int(SIZE_Y/2)-1, columnspan = int(SIZE_Y/2)) # bottom right
self.restart() # start game
self.updateTimer() # init timer
def setup(self):
# create flag and clicked tile variables
self.flagCount = 0
self.correctFlagCount = 0
self.clickedCount = 0
self.startTime = None
# create buttons
self.tiles = dict({})
self.mines = 0
for x in range(0, SIZE_X):
for y in range(0, SIZE_Y):
if y == 0:
self.tiles[x] = {}
id = str(x) + "_" + str(y)
isMine = False
# tile image changeable for debug reasons:
gfx = self.images["plain"]
# currently random amount of mines
if random.uniform(0.0, 1.0) < 0.1:
isMine = True
self.mines += 1
tile = {
"id": id,
"isMine": isMine,
"state": STATE_DEFAULT,
"coords": {
"x": x,
"y": y
},
"button": Button(self.frame, image = gfx),
"mines": 0 # calculated after grid is built
}
tile["button"].bind(BTN_CLICK, self.onClickWrapper(x, y))
tile["button"].bind(BTN_FLAG, self.onRightClickWrapper(x, y))
tile["button"].grid( row = x+1, column = y ) # offset by 1 row for timer
self.tiles[x][y] = tile
# loop again to find nearby mines and display number on tile
for x in range(0, SIZE_X):
for y in range(0, SIZE_Y):
mc = 0
for n in self.getNeighbors(x, y):
mc += 1 if n["isMine"] else 0
self.tiles[x][y]["mines"] = mc
def restart(self):
self.setup()
self.refreshLabels()
def refreshLabels(self):
self.labels["flags"].config(text = "Flags: "+str(self.flagCount))
self.labels["mines"].config(text = "Mines: "+str(self.mines))
def gameOver(self, won):
for x in range(0, SIZE_X):
for y in range(0, SIZE_Y):
if self.tiles[x][y]["isMine"] == False and self.tiles[x][y]["state"] == STATE_FLAGGED:
self.tiles[x][y]["button"].config(image = self.images["wrong"])
if self.tiles[x][y]["isMine"] == True and self.tiles[x][y]["state"] != STATE_FLAGGED:
self.tiles[x][y]["button"].config(image = self.images["mine"])
self.tk.update()
msg = "You Win! Play again?" if won else "You Lose! Play again?"
res = tkMessageBox.askyesno("Game Over", msg)
if res:
self.restart()
else:
self.tk.quit()
def updateTimer(self):
ts = "00:00:00"
if self.startTime != None:
delta = datetime.now() - self.startTime
ts = str(delta).split('.')[0] # drop ms
if delta.total_seconds() < 36000:
ts = "0" + ts # zero-pad
self.labels["time"].config(text = ts)
self.frame.after(100, self.updateTimer)
def getNeighbors(self, x, y):
neighbors = []
coords = [
{"x": x-1, "y": y-1}, #top right
{"x": x-1, "y": y}, #top middle
{"x": x-1, "y": y+1}, #top left
{"x": x, "y": y-1}, #left
{"x": x, "y": y+1}, #right
{"x": x+1, "y": y-1}, #bottom right
{"x": x+1, "y": y}, #bottom middle
{"x": x+1, "y": y+1}, #bottom left
]
for n in coords:
try:
neighbors.append(self.tiles[n["x"]][n["y"]])
except KeyError:
pass
return neighbors
def onClickWrapper(self, x, y):
return lambda Button: self.onClick(self.tiles[x][y])
def onRightClickWrapper(self, x, y):
return lambda Button: self.onRightClick(self.tiles[x][y])
def onClick(self, tile):
if self.startTime == None:
self.startTime = datetime.now()
if tile["isMine"] == True:
# end game
self.gameOver(False)
return
# change image
if tile["mines"] == 0:
tile["button"].config(image = self.images["clicked"])
self.clearSurroundingTiles(tile["id"])
else:
tile["button"].config(image = self.images["numbers"][tile["mines"]-1])
# if not already set as clicked, change state and count
if tile["state"] != STATE_CLICKED:
tile["state"] = STATE_CLICKED
self.clickedCount += 1
if self.clickedCount == (SIZE_X * SIZE_Y) - self.mines:
self.gameOver(True)
def onRightClick(self, tile):
if self.startTime == None:
self.startTime = datetime.now()
# if not clicked
if tile["state"] == STATE_DEFAULT:
tile["button"].config(image = self.images["flag"])
tile["state"] = STATE_FLAGGED
tile["button"].unbind(BTN_CLICK)
# if a mine
if tile["isMine"] == True:
self.correctFlagCount += 1
self.flagCount += 1
self.refreshLabels()
# if flagged, unflag
elif tile["state"] == 2:
tile["button"].config(image = self.images["plain"])
tile["state"] = 0
tile["button"].bind(BTN_CLICK, self.onClickWrapper(tile["coords"]["x"], tile["coords"]["y"]))
# if a mine
if tile["isMine"] == True:
self.correctFlagCount -= 1
self.flagCount -= 1
self.refreshLabels()
def clearSurroundingTiles(self, id):
queue = deque([id])
while len(queue) != 0:
key = queue.popleft()
parts = key.split("_")
x = int(parts[0])
y = int(parts[1])
for tile in self.getNeighbors(x, y):
self.clearTile(tile, queue)
def clearTile(self, tile, queue):
if tile["state"] != STATE_DEFAULT:
return
if tile["mines"] == 0:
tile["button"].config(image = self.images["clicked"])
queue.append(tile["id"])
else:
tile["button"].config(image = self.images["numbers"][tile["mines"]-1])
tile["state"] = STATE_CLICKED
self.clickedCount += 1
### END OF CLASSES ###
def main():
# create Tk instance
window = Tk()
unpack_images(images)
# set program title
window.title("Minesweeper")
# create game instance
minesweeper = Minesweeper(window)
# run event loop
window.mainloop()
if __name__ == "__main__":
main()
"""Mona Lisa, by Al Sweigart al@inventwithpython.com
Draws an Andy Warhol-like drawing of the Mona Lisa with turtle
graphics."""
__version__ = 0
import turtle
turtle.tracer(400, 0) # Make the turtle draw faster.
"""The image data for the Mona Lisa. I created this through a complicated
process: I found a picture of the Mona Lisa online, converted it to
grayscale in Photoshop, then greatly increased the contrast, then shrunk
it down, and converted that image into a pure black/white image. I wrote
a script using the Pillow module to turn the black/white pixel
information in to a stream of 1s and 0s, and then turned that binary
number into this hexadecimal number."""
monaLisaData = '0x54a9554ebaaab5555b776eeb56addebdb5db5b33fd9b6d5d6db55affcaeed576d559dd71576ab7a9a76ee32ceb59b556edd591df6b5aead5b265add256954aa52ad5aa55aa96ab55fd576d569d2b556affea992a955b4aa94effd4dd555496aa57f7feb45554a51534b9dfecb2aa36caa4a627ff14a49c254922d12ffd69345b54552c037f88a951423249a89ffe6905494892bc44bfda6689e74925a22bfd7125432a927800bff9d24bdeac83b5edfef6935fb7757fbbfff6d10adddd4ba9b5ffff4d5eeef37a913ff55255fabaff86aaffff92aafffd59103feafaadfb6fffc99fffe8ab5bff5ffc947ffffbdffd6f7f571ffffeeb6f7bfefe3d57eeffffffff77d9afbf7f5b7bbd7ffe5b7fff7efbff7fbff29fffafbffeffdebf97ffffdfedff6ffffdffffded7feffdd6fffffff7fd5fdb76ffedefffffffffffb7ff77fbb7dbbfef5b7feb57fdd6ddbf5efbdeb5bfffd6feeffdffe9afffdedefbb7fff8227fefafbfdfbefe5116bfcbbb7eeffde048fffe4dddfbbffca027ffbb6ff75f7fa090bf7fdd7bbabdfc0096fbee33ffdf7e2484ffbfbd1ddebff000170dffbef7fcfca910affffe9fb5ffe00897bffffdbdc7ff90017fffffefabffee805ffffeafefefefb757beefffb76ebf7fbfffffbffbf76ffbeedbfffffdffdbdffff7ffffffffffffffbbeff6bfefb76ffffdffffff7fbffb3fbfffffffbbfefd59efffdbefeffffbeafffffffffffffff7f7fefffffffffeedfbeffedfbffffffffeffffffbffeffffff7efdf7ffffffffff7fffefffffffffdfffeffffffbefffffbfbffdffffffff7bffff7ffffffffbfffffffbdfffbbdfffffffbdffebbffffffffffffff7efffffffffffff7feff5ffffff7f7ffbf76f05ffdffdfffff7bf892bffffffdfffffbe4a5fffffffefffffd50affffffffffffdf6a43fffffffffffffbb51f7fdfbfffffffd4baad57ffdfbfffd6b4f7ffffffffffff3ae7affffffffbff5be73f77effffeff7e8bbdffffffddffff5bfcefbf7ffffff7fd8def7fffefffffffeffffbfffffffffffb7fffffffffffffffefb77fffffffffffffffffffffffbffffffbfffffffffffffffffffffffffffffff7fffffffffffffffffffffff7ffffffffffffffffffffffff7ff7ffdfffffffeffffffffffffffffffffffff7fffffffffffffffffffffffffff'
def main():
turtle.bgcolor('#FFF7D0')
turtle.fillcolor('#FF0C6B')
drawFromData(monaLisaData, 68, 100, -272, 400, 4)
turtle.fillcolor('#CE18FF')
drawFromData(monaLisaData, 68, 100, 0, 400, 4)
turtle.fillcolor('#7C0BE8')
drawFromData(monaLisaData, 68, 100, -272, 0, 4)
turtle.fillcolor('#460CFF')
drawFromData(monaLisaData, 68, 100, 0, 0, 4)
turtle.update() # Finish drawing the screen.
turtle.exitonclick() # When user clicks on the window, close it.
def drawFromData(image_data, image_width, image_height, left, top, pixel_size):
turtle.penup()
inBinary = bin(int(image_data, 16))
# Remove '0b' from the start of the hex number:
inBinary = inBinary[2:]
# Add leading zeros to the binary number, if needed:
inBinary = inBinary.rjust(image_width * image_height, '0')
for y in range(image_height):
for x in range(image_width):
turtle.goto(left + (x * pixel_size), top - (y * pixel_size))
if inBinary[y * image_width + x] == '1': # (!) Try switching this to '0'.
turtle.begin_fill()
turtle.setheading(0)
turtle.forward(pixel_size) # draw top of the box
turtle.right(90)
turtle.forward(pixel_size) # draw right edge of the box
turtle.right(90)
turtle.forward(pixel_size) # draw bottom of the box
turtle.right(90)
turtle.forward(pixel_size) # draw left edge of the box
turtle.end_fill() # fill in the box
try:
main()
except turtle.Terminator:
pass # Do nothing when the turtle window is closed.
"""Multiplication Table, by Al Sweigart al@inventwithpython.com
Print a multiplication table.
This and other games are available at https://nostarch.com/XX
Tags: tiny, beginner, math"""
__version__ = 0
print('Multiplication Table, by Al Sweigart al@inventwithpython.com')
# Print the horizontal number labels:
print(' | 0 1 2 3 4 5 6 7 8 9 10 11 12')
print('--+---------------------------------------------------')
# Display each row of products:
for number1 in range(0, 13):
# Print the vertical numbers labels:
print(str(number1).rjust(2), end='')
# Print a separating bar:
print('|', end='')
for number2 in range(0, 13):
# Print the product:
print(str(number1 * number2).rjust(3), end=' ')
print() # Finish the row by printing a newline.
"""Multiplicative Persistence, by Al Sweigart al@inventwithpython.com
A fun math challenge.
For more information about this topic, see https://youtu.be/Wim9WJeDTHQ
This and other games are available at https://nostarch.com/XX
Tags: tiny, math"""
__version__ = 0
import time, sys
print('Multiplicative Persistence Game')
print('By Al Sweigart al@inventwithpython.com')
print()
while True: # Main program loop.
print('Try to get the longest multiplicative persistence chain!')
print('(Start with 277777788888899, which has the longest known')
print('chain length.)')
while True: # Keep asking until the player enters a number.
print('Enter a number (or "QUIT" to quit):')
try:
response = input('> ')
if response.upper().startswith('Q'):
sys.exit()
number = int(response)
except ValueError:
continue # If the user entered a non-integer, ask again.
break
chainLength = 0
while number > 9: # Loop as long as number is 2 or more digits.
chainLength += 1
print(number, end='', flush=True)
time.sleep(0.2)
print(' -> ', end='', flush=True)
time.sleep(0.2)
print('*'.join(list(str(number))), end='', flush=True)
time.sleep(0.2)
print(' = ', end='', flush=True)
time.sleep(0.2)
# Calculate the next number in the multiplicative persistence
# chain by multiplying all of the digits in the number:
product = 1
for digit in str(number):
product *= int(digit)
number = product
print(number, flush=True)
time.sleep(0.6)
print(number)
print('Length of', response, 'chain:', chainLength)
print()
import random
import time
# сорі за суржик
phrases = [
"{}, вставай!",
"все пропало, {}!",
"ми все уронілі, {}!",
"{}, ти спіш?",
]
cat1 = r"""
|\---/|
| o_o |
\_^_/
"""
cat2 = r"""
/\_/\
( o.o )
> ^ <
"""
cat3 = r"""
|\__/,| (`\
_.|o o |_ ) )
-(((---(((--------
"""
def prepare_cat(cat):
"""
Перетворити картинку котика в список рядків. І зробити картинку прямокутною,
додавши в кінці кожного рядку прогаликів
In[]: cat = r'''
|\__/|
| OO |._
-(((---(((-
'''
In[]: prepare_cat(cat)
Out[]: [
'|\__/| ',
'| OO |._ ',
'-(((---(((-'
]
"""
lines = cat.split("\n")
max_length = max([ len(line) for line in lines ])
return [ x.ljust(max_length) for x in lines[1:-1]]
def symbol_reverse(sym):
"""
Віддзеркалити символ. Це потрібно для відзеркалення картинки котика.
Наприклад, якщо котик виглядає як
cat = r'|\_/| '
то при розвертанні рядка нахилені символи / та \ поміняються місцями:
r'|\_/| '[::-1] == r' |/_\|'
От для цих несиметричних символів і потрібна ця функція.
"""
if sym == '(':
return ')'
elif sym == ')':
return '('
elif sym == '/':
return '\\'
elif sym == '\\':
return '/'
elif sym == '>':
return '<'
elif sym == '<':
return '>'
else:
return sym
def ascii_mirror(cat_lines, offset=0):
"""
Віддзеркалити всього котика. Параметр offset автоматично посуне котика
вліво.
"""
result = []
for line in cat_lines:
line_reverse = line[::-1]
line_correct = ''.join([ symbol_reverse(x) for x in line_reverse ])
result.append(line_correct.rjust(offset))
return result
# нормальні котики
all_cats = [ prepare_cat(cat) for cat in [cat1, cat2] ]
# дзеркальні котики
all_cats += [ ascii_mirror(prepare_cat(cat)) for cat in [cat3] ]
try:
while True:
time.sleep(0.7)
cat = random.choice(all_cats)
phrase = random.choice(phrases)
name = "Наташ"
if random.random() < 0.5: # картинка справа
print("\n".join(cat))
print(phrase.format(name))
else: # картинка зліва
cat = ascii_mirror(cat, offset=60)
print("\n".join(cat))
print(phrase.format(name).rjust(60))
except KeyboardInterrupt:
pass
import turtle
import math
import itertools
import time
import random
turtle.tracer(0, 0)
time_start = time.time()
def beat(size):
turtle.pendown()
turtle.color("red")
turtle.pensize(4)
turtle.forward(size)
turtle.penup()
def music_spectrum(angle, music):
return abs(50 * (math.sin(2*(time.time() - time_start))-1) + random.randrange(100))
def draw(radius, music=None, N=60):
turtle.penup()
turtle.goto(0, radius)
for i in range(N+1):
angle = i * 360 / N
x = radius * math.cos(angle*math.pi/180 + math.pi/2)
y = radius * math.sin(angle*math.pi/180 + math.pi/2)
turtle.goto(x, y)
turtle.setheading(angle + 90)
spec_size = music_spectrum(angle, music)
beat(spec_size)
turtle.color("black")
turtle.goto(-90, 00)
turtle.write("Turtle", font=("Courier", 35, "bold"))
turtle.goto(-100, -40)
turtle.write(" Nation", font=("Courier", 35, "bold"))
class ParticleSystem:
def reset_particle(self, t):
t.penup()
t.goto(0, 0)
t.shape("circle")
t.shapesize(random.random())
t.color("#BBBBBB")
t.setheading(random.randrange(361))
t._spd = random.randrange(10, 50)
def __init__(self, num):
self.pool = [turtle.Turtle() for _ in range(num)]
self.previous_time = time.time() - 10
for t in self.pool:
self.reset_particle(t)
def update(self, time):
dt = time - self.previous_time
self.previous_time = time
for t in self.pool:
t.forward(dt*t._spd)
if t.xcor()**2 + t.ycor()**2 > 400**2:
self.reset_particle(t)
ps = ParticleSystem(40)
i = 0
while True:
ps.update(time.time())
if i % 2:
turtle.clear()
draw(100)
turtle.update()
time.sleep(0.05)
i += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment