├── 1_Rock-paper-scissors-lizard-Spock.py ├── 2_Guess-the number-game.py ├── 3_Stopwatch-The Game.py ├── 4_Pong.py ├── 5_Memory.py ├── 6_Blackjack.py ├── 7_Spaceship.py ├── 8_RiceRocks.py └── README.md /1_Rock-paper-scissors-lizard-Spock.py: -------------------------------------------------------------------------------- 1 | # Rock-paper-scissors-lizard-Spock template 2 | 3 | 4 | # The key idea of this program is to equate the strings 5 | # "rock", "paper", "scissors", "lizard", "Spock" to numbers 6 | # as follows: 7 | # 8 | # 0 - rock 9 | # 1 - Spock 10 | # 2 - paper 11 | # 3 - lizard 12 | # 4 - scissors 13 | 14 | # helper functions 15 | import random 16 | def name_to_number(name): 17 | # delete the follwing pass statement and fill in your code below 18 | if name == "rock": 19 | return 0 20 | elif name == "Spock": 21 | return 1 22 | elif name == "paper": 23 | return 2 24 | elif name == "lizard": 25 | return 3 26 | elif name == "scissors": 27 | return 4 28 | else: 29 | print "Error: Wrong name!" 30 | return 31 | 32 | # convert name to number using if/elif/else 33 | # don't forget to return the result! 34 | 35 | 36 | def number_to_name(number): 37 | # delete the follwing pass statement and fill in your code below 38 | if number == 0: 39 | return "rock" 40 | elif number == 1: 41 | return "Spock" 42 | elif number == 2: 43 | return "paper" 44 | elif number == 3: 45 | return "lizard" 46 | elif number == 4: 47 | return "scissors" 48 | else: 49 | print "Error: Wrong number!" 50 | return 51 | 52 | # convert number to a name using if/elif/else 53 | # don't forget to return the result! 54 | 55 | 56 | def rpsls(player_choice): 57 | # delete the follwing pass statement and fill in your code below 58 | 59 | 60 | # print a blank line to separate consecutive games 61 | print "" 62 | # print out the message for the player's choice 63 | print "Player chooses %s" % player_choice 64 | # convert the player's choice to player_number using the function name_to_number() 65 | player_number = name_to_number(player_choice) 66 | # compute random guess for comp_number using random.randrange() 67 | comp_number = random.randrange(0, 5) 68 | # convert comp_number to comp_choice using the function number_to_name() 69 | comp_choice = number_to_name(comp_number) 70 | # print out the message for computer's choice 71 | print "Computer chooses %s" % comp_choice 72 | # compute difference of comp_number and player_number 73 | difference = player_number - comp_number 74 | # use if/elif/else to determine winner, print winner message 75 | if difference == 0: 76 | print "Player and computer tie!" 77 | elif difference == 4 or difference == 3 or difference == -1 or difference == -2: 78 | print "Computer wins!" 79 | else: 80 | print "Player wins!" 81 | 82 | # test your code - LEAVE THESE CALLS IN YOUR SUBMITTED CODE 83 | rpsls("rock") 84 | rpsls("Spock") 85 | rpsls("paper") 86 | rpsls("lizard") 87 | rpsls("scissors") 88 | 89 | # always remember to check your completed program against the grading rubric 90 | 91 | 92 | -------------------------------------------------------------------------------- /2_Guess-the number-game.py: -------------------------------------------------------------------------------- 1 | # template for "Guess the number" mini-project 2 | # input will come from buttons and an input field 3 | # all output for the game will be printed in the console 4 | 5 | """import some modules""" 6 | import random, simplegui 7 | 8 | # initialize global variables used in your code 9 | secret_number = random.randrange(0, 100) 10 | secret_number_range = 100 11 | number_allowed_guess = 0 12 | 13 | # helper function to start and restart the game 14 | def new_game(): 15 | """ This fonction is to start new game, and print out some introductions. """ 16 | global secret_number, number_allowed_guess 17 | print 18 | print "=== A new game start ===" 19 | if secret_number_range == 100: 20 | number_allowed_guess = 7 21 | secret_number = random.randrange(0, 100) 22 | else: 23 | number_allowed_guess = 10 24 | secret_number = random.randrange(0, 1000) 25 | print "Range: [0, " + str(secret_number_range) + ")" 26 | print 27 | 28 | # define event handlers for control panel 29 | def range100(): 30 | """ This function is to get a secret number in the range of [0, 100) """ 31 | global secret_number, secret_number_range 32 | secret_number = random.randrange(0, 100) 33 | secret_number_range = 100 34 | new_game() 35 | 36 | 37 | def range1000(): 38 | """ This function is to get a secret number in the range of [0, 1000) """ 39 | global secret_number, secret_number_range 40 | secret_number = random.randrange(0, 1000) 41 | secret_number_range = 1000 42 | new_game() 43 | 44 | 45 | def input_guess(guess): 46 | """ This function is to deal with the number that player entered. """ 47 | global number_allowed_guess 48 | # Using a try-except to catch wrong input 49 | try: 50 | guess = int(guess) 51 | end = False 52 | print "Your guess number is: " + str(guess) 53 | if guess > secret_number: 54 | print "Lower" 55 | elif guess < secret_number: 56 | print "Higher" 57 | else: 58 | print "Correct!" 59 | end = True 60 | number_allowed_guess -= 1 61 | if end == True: 62 | print "You win!" 63 | print 64 | new_game() 65 | elif end == False and number_allowed_guess == 0: 66 | print "You lose!" 67 | print 68 | new_game() 69 | else: 70 | print "You remain " + str(number_allowed_guess) + " times to guess." 71 | print 72 | except Exception as e: 73 | print "Error:" 74 | print "Something wrong with the number you've entered," 75 | print "please to enter an integer." 76 | print 77 | 78 | 79 | # create frame 80 | frame = simplegui.create_frame('Guess the number', 200, 400) 81 | 82 | # register event handlers for control elements 83 | frame.add_button('Range: [0, 100)', range100, 150) 84 | frame.add_button('Range: [0, 1000)', range1000, 150) 85 | frame.add_input('Enter a number to guess:', input_guess, 50) 86 | 87 | 88 | # call new_game and start frame 89 | new_game() 90 | frame.start() 91 | 92 | 93 | # always remember to check your completed program against the grading rubric 94 | -------------------------------------------------------------------------------- /3_Stopwatch-The Game.py: -------------------------------------------------------------------------------- 1 | """ Mini-project # 3 - "Stopwatch: The Game" """ 2 | 3 | """ 1. import module """ 4 | import simplegui 5 | 6 | """ 2. define global variables """ 7 | counter = 0 # This variable counts each tenths of second when the timer starts 8 | number_of_successful_stops = 0 # This variable counts the number of successful stops, like "0:10.0" 9 | number_of_total_stops = 0 # This variable counts the number of total stops 10 | 11 | 12 | """ 3. define helper function format that converts time 13 | in tenths of seconds into formatted string A:BC.D """ 14 | def format(t): 15 | tenths_of_seconds = t % 10 16 | seconds = (t - tenths_of_seconds) / 10 % 10 17 | ten_seconds = (t - seconds * 10 - tenths_of_seconds) / 100 % 6 18 | minutes = (t - ten_seconds * 100 - seconds * 10 - tenths_of_seconds) / 600 19 | return str(minutes) + ":" + str(ten_seconds) + str(seconds) + "." + str(tenths_of_seconds) 20 | 21 | """ 4. define event handlers for buttons; "Start", "Stop", "Reset" """ 22 | # handler for button "Start" 23 | def btnStart(): 24 | if not timer.is_running(): 25 | timer.start() 26 | 27 | # handler for button "Stop" 28 | def btnStop(): 29 | global number_of_successful_stops, number_of_total_stops 30 | if timer.is_running(): 31 | timer.stop() 32 | number_of_total_stops += 1 33 | if counter % 10 == 0: 34 | number_of_successful_stops += 1 35 | 36 | # handler for button "Reset" 37 | def btnReset(): 38 | global counter, number_of_successful_stops, number_of_total_stops 39 | if timer.is_running(): 40 | timer.stop() 41 | # reset all the global variables 42 | counter = 0 43 | number_of_successful_stops = 0 44 | number_of_total_stops = 0 45 | 46 | """ handler for button "Start & Stop" (PS: it's useful but not necessary) """ 47 | def btnStartAndStop(): 48 | global counter, number_of_successful_stops, number_of_total_stops 49 | if timer.is_running(): 50 | timer.stop() 51 | number_of_total_stops += 1 52 | if counter % 10 == 0: 53 | number_of_successful_stops += 1 54 | else: 55 | timer.start() 56 | 57 | """ 5. define event handler for timer with 0.1 sec interval """ 58 | def timer_handler(): 59 | global counter 60 | counter += 1 61 | 62 | """ 6. define draw handler """ 63 | def draw_handler(canvas): 64 | # draw "0:00.0" 65 | canvas.draw_text(format(counter), (100, 150), 80, 'Blue') 66 | # draw "0/0" 67 | canvas.draw_text(str(number_of_successful_stops), (250, 50), 50, 'Red') # display corretly range: 0-99 68 | canvas.draw_text("/"+str(number_of_total_stops), (300, 50), 50, 'Gray') # display corretly range: 0-999 69 | 70 | """ 7. create frame """ 71 | frame = simplegui.create_frame('Stopwatch', 400, 200, 150) 72 | frame.set_canvas_background('White') 73 | 74 | """ 8. register event handlers """ 75 | frame.set_draw_handler(draw_handler) 76 | frame.add_button('Start', btnStart, 100) 77 | frame.add_button('Stop', btnStop, 100) 78 | frame.add_button('Reset', btnReset, 100) 79 | timer = simplegui.create_timer(100, timer_handler) 80 | """ Attention: 81 | I add this button to make the Stopwatch easier for control, 82 | and it's also easier for test. """ 83 | frame.add_button('Start & Stop', btnStartAndStop, 100) 84 | 85 | 86 | """ 9. start frame """ 87 | frame.start() 88 | -------------------------------------------------------------------------------- /4_Pong.py: -------------------------------------------------------------------------------- 1 | # Implementation of classic arcade game Pong 2 | 3 | import simplegui 4 | import random 5 | 6 | # initialize globals - pos and vel encode vertical info for paddles 7 | WIDTH = 600 8 | HEIGHT = 400 9 | BALL_RADIUS = 20 10 | PAD_WIDTH = 8 11 | PAD_HEIGHT = 80 12 | LEFT = False 13 | RIGHT = True 14 | 15 | # add some global variables 16 | ball_pos = [WIDTH / 2.0, HEIGHT / 2.0] 17 | ball_vel = [0.0, 0.0] 18 | score_left = 0 19 | score_right = 0 20 | paddle_left_pos = HEIGHT / 2 - PAD_HEIGHT / 2 21 | paddle_right_pos = HEIGHT / 2 - PAD_HEIGHT / 2 22 | paddle_left_vel = 0 23 | paddle_right_vel = 0 24 | PAD_VEL_CST = 3 # constant of velocity of paddles 25 | 26 | # add some global temps 27 | temp_ball_vel = 0 28 | temp_PAD_VEL_CST = 0 29 | is_pause = False 30 | 31 | 32 | 33 | 34 | 35 | # initialize ball_pos and ball_vel for new bal in middle of table 36 | # if direction is RIGHT, the ball's velocity is upper right, else upper left 37 | def spawn_ball(direction): 38 | global ball_pos, ball_vel # these are vectors stored as lists 39 | ball_pos = [WIDTH / 2.0, HEIGHT / 2.0] 40 | if direction == LEFT: # direction: upper left 41 | ball_vel = [-(random.randrange(2, 4) + random.randrange(0, 100) * 0.01), -(random.randrange(1, 3) + random.randrange(0, 100) * 0.01)] 42 | else: # direction: upper right 43 | ball_vel = [(random.randrange(2, 4) + random.randrange(0, 100) * 0.01), -(random.randrange(1, 3) + random.randrange(0, 100) * 0.01)] 44 | 45 | 46 | 47 | 48 | 49 | # define event handlers 50 | def new_game(): 51 | global paddle_left_pos, paddle_right_pos, paddle_left_vel, paddle_right_vel 52 | global score_left, score_right 53 | # choose the direction randomly by default 54 | if random.randrange(0,2) == 0: 55 | spawn_ball(LEFT) 56 | else: 57 | spawn_ball(RIGHT) 58 | # reset the score 59 | score_left = 0 60 | score_right = 0 61 | 62 | # draw handler 63 | def draw(canvas): 64 | global score_left, score_right, paddle_left_pos, paddle_right_pos, paddle_left_vel, paddle_right_vel, ball_pos, ball_vel 65 | # draw mid line and gutters 66 | canvas.draw_line([WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1, "White") 67 | canvas.draw_line([PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1, "White") 68 | canvas.draw_line([WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1, "White") 69 | 70 | # draw scores 71 | canvas.draw_text(str(score_left), [WIDTH / 4 - 25, (HEIGHT / 2) + 30], 100, 'Red') 72 | canvas.draw_text(str(score_right), [(WIDTH / 4) * 3 - 25, (HEIGHT / 2) + 30], 100, 'Green') 73 | 74 | # update ball 75 | # if the ball is going to pass through left gutter 76 | if ball_pos[0] - BALL_RADIUS + ball_vel[0] < PAD_WIDTH: 77 | # while the ball is touching left gutter without paddle left 78 | if ball_pos[1] < paddle_left_pos or ball_pos[1] > paddle_left_pos + PAD_HEIGHT: 79 | # print some information for debug 80 | print 'The ball hit the left gutter, at the point: [' + str(ball_pos[0] - BALL_RADIUS) + ', ' + str(ball_pos[1]) + ']' 81 | print 'The upper right corner of left paddle is: [' + str(PAD_WIDTH) + ', ' + str(paddle_left_pos) + ']' 82 | print 'The bottom right corner of left paddle is: [' + str(PAD_WIDTH) + ', ' + str(paddle_left_pos + PAD_HEIGHT) + ']' 83 | print 84 | score_right += 1 85 | spawn_ball(RIGHT) 86 | else: 87 | # while the ball is touching left gutter with paddle left 88 | ball_vel[0] = -(ball_vel[0] * 1.1) 89 | ball_vel[1] = (ball_vel[1] * 1.1) 90 | # if the ball is going to pass through right gutter 91 | if ball_pos[0] + BALL_RADIUS + ball_vel[0] > WIDTH - PAD_WIDTH: 92 | # while the ball is touching right gutter without paddle right 93 | if ball_pos[1] < paddle_right_pos or ball_pos[1] > paddle_right_pos + PAD_HEIGHT: 94 | # print some information for debug 95 | print 'The ball hit the right gutter, at the point: [' + str(ball_pos[0] + BALL_RADIUS) + ', ' + str(ball_pos[1]) + ']' 96 | print 'The upper left corner of right paddle is: [' + str(WIDTH - PAD_WIDTH) + ', ' + str(paddle_right_pos) + ']' 97 | print 'The bottom left corner of right paddle is: [' + str(WIDTH - PAD_WIDTH) + ', ' + str(paddle_right_pos + PAD_HEIGHT) + ']' 98 | print 99 | score_left += 1 100 | spawn_ball(LEFT) 101 | else: 102 | # while the ball is touching right gutter with paddle right 103 | ball_vel[0] = -(ball_vel[0] * 1.1) 104 | ball_vel[1] = (ball_vel[1] * 1.1) 105 | 106 | # if the ball is going to pass through upper of the canvas or bottom of the canvas 107 | if ball_pos[1] - BALL_RADIUS + ball_vel[1] < 0 or ball_pos[1] + BALL_RADIUS + ball_vel[1] > HEIGHT: 108 | ball_vel[1] = -ball_vel[1] 109 | ball_pos[0] = ball_pos[0] + ball_vel[0] 110 | ball_pos[1] = ball_pos[1] + ball_vel[1] 111 | 112 | # draw ball 113 | canvas.draw_circle(ball_pos, BALL_RADIUS-2, 2, 'Yellow', 'Orange') 114 | 115 | # update paddle's vertical position, keep paddle on the screen 116 | # make sure paddle left stay in the canvas 117 | if paddle_left_pos + paddle_left_vel >= 0 and paddle_left_pos + paddle_left_vel <= HEIGHT - PAD_HEIGHT: 118 | paddle_left_pos += paddle_left_vel 119 | # make sure paddle right stay in the canvas 120 | if paddle_right_pos + paddle_right_vel >= 0 and paddle_right_pos + paddle_right_vel <= HEIGHT - PAD_HEIGHT: 121 | paddle_right_pos += paddle_right_vel 122 | 123 | # draw paddles 124 | # paddle left 125 | canvas.draw_polygon([[0, paddle_left_pos], [PAD_WIDTH, paddle_left_pos], [PAD_WIDTH, paddle_left_pos + PAD_HEIGHT], [0, paddle_left_pos + PAD_HEIGHT]], 1, 'Red', 'Red') 126 | # paddle right 127 | canvas.draw_polygon([[WIDTH - PAD_WIDTH, paddle_right_pos], [WIDTH, paddle_right_pos], [WIDTH, paddle_right_pos + PAD_HEIGHT], [WIDTH - PAD_WIDTH, paddle_right_pos + PAD_HEIGHT]], 1, 'Green', 'Green') 128 | #print ball_vel 129 | 130 | # key down handler 131 | def keydown(key): 132 | global paddle_left_vel, paddle_right_vel 133 | if key == simplegui.KEY_MAP['w']: 134 | paddle_left_vel = -PAD_VEL_CST 135 | elif key == simplegui.KEY_MAP['s']: 136 | paddle_left_vel = PAD_VEL_CST 137 | elif key == simplegui.KEY_MAP['up']: 138 | paddle_right_vel = -PAD_VEL_CST 139 | elif key == simplegui.KEY_MAP['down']: 140 | paddle_right_vel = PAD_VEL_CST 141 | 142 | # key up handler 143 | def keyup(key): 144 | global paddle_left_vel, paddle_right_vel 145 | if key == simplegui.KEY_MAP['w']: 146 | paddle_left_vel = 0 147 | elif key == simplegui.KEY_MAP['s']: 148 | paddle_left_vel = 0 149 | elif key == simplegui.KEY_MAP['up']: 150 | paddle_right_vel = 0 151 | elif key == simplegui.KEY_MAP['down']: 152 | paddle_right_vel = 0 153 | 154 | # 'Restart' button handler 155 | def btn_restart(): 156 | global is_pause, PAD_VEL_CST, paddle_left_pos, paddle_right_pos 157 | # Resume the game 158 | if is_pause == True: 159 | is_pause = False 160 | PAD_VEL_CST = temp_PAD_VEL_CST 161 | # reset the position of paddles 162 | paddle_left_pos = HEIGHT / 2 - PAD_HEIGHT / 2 163 | paddle_right_pos = HEIGHT / 2 - PAD_HEIGHT / 2 164 | # make a new game 165 | new_game() 166 | 167 | # 'Pause / Resume' button handler 168 | def btn_pause_resume(): 169 | global temp_ball_vel, temp_PAD_VEL_CST, is_pause, ball_vel, PAD_VEL_CST 170 | if is_pause == False: 171 | is_pause = True 172 | temp_ball_vel = ball_vel 173 | ball_vel = [0, 0] 174 | temp_PAD_VEL_CST = PAD_VEL_CST 175 | PAD_VEL_CST = 0 176 | else: 177 | is_pause = False 178 | ball_vel = temp_ball_vel 179 | PAD_VEL_CST = temp_PAD_VEL_CST 180 | 181 | 182 | 183 | 184 | 185 | # create frame 186 | frame = simplegui.create_frame("Pong", WIDTH, HEIGHT) 187 | frame.set_draw_handler(draw) 188 | frame.set_keydown_handler(keydown) 189 | frame.set_keyup_handler(keyup) 190 | frame.add_button('Restart', btn_restart, 100) 191 | frame.add_button('Pause / Resume', btn_pause_resume, 150) # add one more button for debug 192 | 193 | # start frame 194 | new_game() 195 | frame.start() 196 | -------------------------------------------------------------------------------- /5_Memory.py: -------------------------------------------------------------------------------- 1 | # implementation of card game - Memory 2 | 3 | import simplegui 4 | import random 5 | 6 | # globals variables 7 | WIDTH = 800 # width of canvas 8 | HEIGHT = 100 # height of canvas 9 | deck = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7] 10 | WIDTH_CARD = WIDTH / len(deck) # width of each card 11 | MARGIN = 2 # margin between the edge of card and the blue line 12 | turns = 0 13 | state_list = [] 14 | previous_exposed_num = -1 # -1 means null 15 | previous_exposed_index = -1 # -1 means null 16 | 17 | # helper function to initialize globals 18 | def new_game(): 19 | global deck, turns, state_list, previous_exposed_num, previous_exposed_index 20 | random.shuffle(deck) 21 | turns = 0 22 | label.set_text("Turns = " + str(turns)) 23 | # states of each number of deck: hidden, exposed, paired 24 | state_list = ["hidden", "hidden", "hidden", "hidden", 25 | "hidden", "hidden", "hidden", "hidden", 26 | "hidden", "hidden", "hidden", "hidden", 27 | "hidden", "hidden", "hidden", "hidden"] 28 | previous_exposed_num = -1 29 | previous_exposed_index = -1 30 | 31 | # define event handlers 32 | def mouseclick(pos): 33 | global previous_exposed_num, previous_exposed_index, exposed_cards, turns 34 | on_click_card_index = pos[0] / WIDTH_CARD 35 | # if pos[0] % WIDTH_CARD == 0: 36 | # on_click_card_index = pos[0] / WIDTH_CARD 37 | # else: 38 | # on_click_card_index = pos[0] / WIDTH_CARD + 1 39 | 40 | # only respond when the card is hidden 41 | if state_list[on_click_card_index] == "hidden": 42 | # case: no previous exposed card 43 | if previous_exposed_num == -1 and state_list.count("exposed") == 0: 44 | previous_exposed_num = deck[on_click_card_index] 45 | previous_exposed_index = on_click_card_index 46 | state_list[on_click_card_index] = "exposed" 47 | # case: two previous exposed cards are not matched 48 | elif previous_exposed_num == -1 and state_list.count("exposed") == 2: 49 | # hide the two previous exposed cards 50 | for n in range(len(state_list)): 51 | if state_list[n] == "exposed": 52 | state_list[n] = "hidden" 53 | previous_exposed_num = deck[on_click_card_index] 54 | previous_exposed_index = on_click_card_index 55 | state_list[on_click_card_index] = "exposed" 56 | # case: there is a previous exposed card 57 | else: 58 | # increase counter firstly 59 | turns += 1 60 | label.set_text("Turns = " + str(turns)) 61 | # if this card is matched with the previous exposed card 62 | if previous_exposed_num == deck[on_click_card_index]: 63 | state_list[previous_exposed_index] = "paired" 64 | state_list[on_click_card_index] = "paired" 65 | previous_exposed_num = -1 66 | previous_exposed_index = -1 67 | # otherwise 68 | else: 69 | previous_exposed_num = -1 70 | previous_exposed_index = -1 71 | state_list[on_click_card_index] = "exposed" 72 | 73 | # cards are logically 50x100 pixels in size 74 | def draw(canvas): 75 | for n in range(len(deck)): 76 | if state_list[n] == "hidden": 77 | # four point for drawing the square of blue lines, and also two yellow diagonals 78 | point_upper_left = (MARGIN + n * WIDTH_CARD, MARGIN) 79 | point_upper_right = (WIDTH_CARD - MARGIN + n * WIDTH_CARD, MARGIN) 80 | point_bottom_right = (WIDTH_CARD - MARGIN + n * WIDTH_CARD, HEIGHT - MARGIN) 81 | point_bottom_left = (MARGIN + n * WIDTH_CARD, HEIGHT - MARGIN) 82 | canvas.draw_polygon([point_upper_left, point_upper_right, point_bottom_right, point_bottom_left], 2, 'Blue') 83 | canvas.draw_line(point_upper_left, point_bottom_right, 2, 'Yellow') 84 | canvas.draw_line(point_upper_right, point_bottom_left, 2, 'Yellow') 85 | elif state_list[n] == "paired": 86 | canvas.draw_text(str(deck[n]), (5 + n * WIDTH_CARD, 80), 80, 'Green') 87 | else: 88 | canvas.draw_text(str(deck[n]), (5 + n * WIDTH_CARD, 80), 80, 'White') 89 | 90 | # create frame and add a button and labels 91 | frame = simplegui.create_frame("Memory", WIDTH, HEIGHT) 92 | frame.add_button("Reset", new_game) 93 | label = frame.add_label("Turns = " + str(turns)) 94 | 95 | # register event handlers 96 | frame.set_mouseclick_handler(mouseclick) 97 | frame.set_draw_handler(draw) 98 | 99 | # get things rolling 100 | new_game() 101 | frame.start() 102 | -------------------------------------------------------------------------------- /6_Blackjack.py: -------------------------------------------------------------------------------- 1 | # Mini-project # 6 - Blackjack 2 | 3 | # Step 1: import modules 4 | import simplegui 5 | import random 6 | 7 | # Step 2: declare some global variables 8 | CANVAS_SIZE = (740, 650) 9 | IMG_CARDS = simplegui.load_image('http://commondatastorage.googleapis.com/codeskulptor-assets/cards.jfitz.png') 10 | IMG_BACK = simplegui.load_image('http://commondatastorage.googleapis.com/codeskulptor-assets/card_back.png') 11 | CARD_WIDTH = 73 12 | CARD_HEIGHT = 98 13 | RANKS = ('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K') 14 | COLORS = ('Club', 'Spade', 'Heart', 'Diamond') 15 | VALUES = {'A':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10, 'J':10, 'Q':10, 'K':10} 16 | FONT_OFFSET = 2 17 | TABLE_UPPER_LEFT_CORNER = (CANVAS_SIZE[0] - 200, CANVAS_SIZE[1] - 120) 18 | score_dealer = 0 19 | score_player = 0 20 | message_upper = '' 21 | message_lower = '' 22 | state = 'stop' # There are 2 states: 'stop' and 'running' 23 | deck = None 24 | dealer_hand = None 25 | player_hand = None 26 | 27 | # Step 3: create 3 classes: Card, Deck, Hand 28 | class Card: 29 | def __init__(self, rank, color, exposed = True): 30 | self.rank = rank 31 | self.color = color 32 | self.exposed = exposed 33 | def __str__(self): 34 | return "Rank is " + self.rank + ", Color is " + self.color + ", exposed is " + str(self.exposed) 35 | def get_rank(self): 36 | return self.rank 37 | def get_color(self): 38 | return self.color 39 | def is_exposed(self): 40 | return self.exposed 41 | def expose_it(self): 42 | self.exposed = True 43 | def hide_it(self): 44 | self.exposed = False 45 | 46 | class Deck: 47 | def __init__(self): 48 | self.cards = [] 49 | for color in COLORS: 50 | for rank in RANKS: 51 | self.cards.append(Card(rank, color)) 52 | random.shuffle(self.cards) 53 | def __str__(self): 54 | for card in self.cards: 55 | print card 56 | return "" 57 | def get_one_card(self): 58 | return self.cards.pop() 59 | def get_all_cards(self): 60 | return self.cards 61 | 62 | class Hand: 63 | def __init__(self): 64 | self.cards = [] 65 | def __str__(self): 66 | for card in self.cards: 67 | print card 68 | return "" 69 | def get_sum(self): 70 | sum_cards = 0 71 | has_ace = False 72 | for card in self.cards: 73 | sum_cards += VALUES[card.get_rank()] 74 | if card.get_rank() == 'A': 75 | has_ace = True 76 | sum_max = sum_cards 77 | sum_min = sum_cards 78 | if has_ace == True: 79 | if sum_cards + 10 <= 21: 80 | sum_max += 10 81 | return sum_max, sum_min 82 | def add_one_card(self, deck): 83 | self.cards.append(deck.get_one_card()) 84 | def hide_one_card(self, index): 85 | self.cards[index].hide_it() 86 | def expose_one_card(self, index): 87 | self.cards[index].expose_it() 88 | def get_all_cards(self): 89 | return self.cards 90 | 91 | # Step 4: add a function to create new game 92 | def new_game(): 93 | global message_upper, message_lower, state, deck, dealer_hand, player_hand 94 | message_upper = 'This is a new round.' 95 | message_lower = 'Hit or stand?' 96 | state = 'running' 97 | # initialize the deck, dealer's hand and player's hand 98 | deck = Deck() 99 | dealer_hand = Hand() 100 | player_hand = Hand() 101 | # distribute cards for dealer and player 102 | for i in range(2): 103 | dealer_hand.add_one_card(deck) 104 | player_hand.add_one_card(deck) 105 | # make the first card of dealer's hand hidden 106 | dealer_hand.hide_one_card(0) 107 | 108 | # Step 5: create a draw handler 109 | def draw_handler(canvas): 110 | # add a Title in the canvas 111 | canvas.draw_text('BlackJack', (225, 80), 80, 'Black') 112 | canvas.draw_text('BlackJack', (225 - FONT_OFFSET, 80 - FONT_OFFSET), 80, 'Blue') 113 | # add a table of score in the bottom right corner 114 | canvas.draw_polygon([[TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 120], [TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 120], TABLE_UPPER_LEFT_CORNER, [TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1]]], 2, 'Yellow') 115 | canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 80), (TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 80), 2, 'Yellow') 116 | canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 40), (TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 40), 2, 'Yellow') 117 | canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0] + 130, TABLE_UPPER_LEFT_CORNER[1] + 40), (TABLE_UPPER_LEFT_CORNER[0] + 130, TABLE_UPPER_LEFT_CORNER[1] + 120), 2, 'Yellow') 118 | # add 3 labels in the table 119 | canvas.draw_text('Score', (TABLE_UPPER_LEFT_CORNER[0] + 60, TABLE_UPPER_LEFT_CORNER[1] + 35), 35, 'Black') 120 | canvas.draw_text('Score', (TABLE_UPPER_LEFT_CORNER[0] + 60 - FONT_OFFSET, TABLE_UPPER_LEFT_CORNER[1] + 35 - FONT_OFFSET), 35, 'Yellow') 121 | canvas.draw_text('Dealer', (TABLE_UPPER_LEFT_CORNER[0] + 20, TABLE_UPPER_LEFT_CORNER[1] + 75), 35, 'Black') 122 | canvas.draw_text('Dealer', (TABLE_UPPER_LEFT_CORNER[0] + 20 - FONT_OFFSET, TABLE_UPPER_LEFT_CORNER[1] + 75 - FONT_OFFSET), 35, 'Red') 123 | canvas.draw_text('Player', (TABLE_UPPER_LEFT_CORNER[0] + 20, TABLE_UPPER_LEFT_CORNER[1] + 113), 35, 'Black') 124 | canvas.draw_text('Player', (TABLE_UPPER_LEFT_CORNER[0] + 20 - FONT_OFFSET, TABLE_UPPER_LEFT_CORNER[1] + 113 - FONT_OFFSET), 35, 'Orange') 125 | # add 2 scores in the table 126 | canvas.draw_text(str(score_dealer), (TABLE_UPPER_LEFT_CORNER[0] + 150, TABLE_UPPER_LEFT_CORNER[1] + 75), 35, 'Black') 127 | canvas.draw_text(str(score_dealer), (TABLE_UPPER_LEFT_CORNER[0] + 150 - FONT_OFFSET, TABLE_UPPER_LEFT_CORNER[1] + 75 - FONT_OFFSET), 35, 'Red') 128 | canvas.draw_text(str(score_player), (TABLE_UPPER_LEFT_CORNER[0] + 150, TABLE_UPPER_LEFT_CORNER[1] + 115), 35, 'Black') 129 | canvas.draw_text(str(score_player), (TABLE_UPPER_LEFT_CORNER[0] + 150 - FONT_OFFSET, TABLE_UPPER_LEFT_CORNER[1] + 115 - FONT_OFFSET), 35, 'Orange') 130 | # add label for dealer and player 131 | canvas.draw_text('Dealer', (70, 150), 35, 'Black') 132 | canvas.draw_text('Dealer', (70 - FONT_OFFSET, 150 - FONT_OFFSET), 35, 'Red') 133 | canvas.draw_text('Player', (70, 400), 35, 'Black') 134 | canvas.draw_text('Player', (70 - FONT_OFFSET, 400 - FONT_OFFSET), 35, 'Orange') 135 | # add 2 message in canvas 136 | canvas.draw_text(message_upper, (150, 350), 50, 'Black') 137 | canvas.draw_text(message_upper, (150 - FONT_OFFSET, 350 - FONT_OFFSET), 50, 'Yellow') 138 | canvas.draw_text(message_lower, (30, 550), 35, 'Black') 139 | canvas.draw_text(message_lower, (30 - FONT_OFFSET, 550 - FONT_OFFSET), 35, 'Orange') 140 | # drawing setting 141 | cards_margin = 30 142 | dealer_cards_line = 210 143 | player_cards_line = 460 144 | index_of_dealer_cards = 0 145 | index_of_player_cards = 0 146 | center_in_png = (CARD_WIDTH / 2.0, CARD_HEIGHT / 2.0) 147 | # draw dealer's cards 148 | for card in dealer_hand.get_all_cards(): 149 | index_rank = RANKS.index(card.get_rank()) 150 | index_color = COLORS.index(card.get_color()) 151 | if card.is_exposed() == True: 152 | canvas.draw_image(IMG_CARDS, (center_in_png[0] + index_rank * CARD_WIDTH, center_in_png[1] + index_color * CARD_HEIGHT), (CARD_WIDTH, CARD_HEIGHT), (cards_margin * (index_of_dealer_cards + 1) + center_in_png[0] + CARD_WIDTH * index_of_dealer_cards, dealer_cards_line), (CARD_WIDTH, CARD_HEIGHT)) 153 | else: 154 | canvas.draw_image(IMG_BACK, (35.5, 48), (71, 96), (center_in_png[0] + cards_margin, dealer_cards_line), (CARD_WIDTH, CARD_HEIGHT)) 155 | index_of_dealer_cards += 1 156 | # draw player's cards 157 | for card in player_hand.get_all_cards(): 158 | index_rank = RANKS.index(card.get_rank()) 159 | index_color = COLORS.index(card.get_color()) 160 | canvas.draw_image(IMG_CARDS, (center_in_png[0] + index_rank * CARD_WIDTH, center_in_png[1] + index_color * CARD_HEIGHT), (CARD_WIDTH, CARD_HEIGHT), (cards_margin * (index_of_player_cards + 1) + center_in_png[0] + CARD_WIDTH * index_of_player_cards, player_cards_line), (CARD_WIDTH, CARD_HEIGHT)) 161 | index_of_player_cards += 1 162 | 163 | # Step 6: create 3 button handlers 164 | def btn_deal(): 165 | global score_dealer 166 | if state == 'running': 167 | score_dealer += 1 168 | new_game() 169 | 170 | def btn_hit(): 171 | global score_dealer, message_upper, message_lower, state, dealer_hand, player_hand 172 | if state != 'stop': 173 | message_upper = '' 174 | player_hand.add_one_card(deck) 175 | sum_max, sum_min = player_hand.get_sum() 176 | if sum_min > 21: 177 | dealer_hand.expose_one_card(0) 178 | score_dealer += 1 179 | message_upper = 'You went bust and lose.' 180 | message_lower = 'New deal?' 181 | state = 'stop' 182 | 183 | def btn_stand(): 184 | global score_dealer, score_player, message_upper, message_lower, state, dealer_hand, player_hand 185 | if state != 'stop': 186 | player_max, player_min = player_hand.get_sum() 187 | play_sum = 0 188 | if player_max <= 21: 189 | play_sum = player_max 190 | else: 191 | play_sum = player_min 192 | dealer_sum = 0 193 | while True: 194 | dealer_max, dealer_min = dealer_hand.get_sum() 195 | if dealer_max <= 21: 196 | dealer_sum = dealer_max 197 | else: 198 | dealer_sum = dealer_min 199 | if dealer_sum >= 17: 200 | break 201 | else: 202 | dealer_hand.add_one_card(deck) 203 | dealer_hand.expose_one_card(0) 204 | if dealer_sum > 21: 205 | score_player += 1 206 | message_upper = 'Dealer went bust and lose.' 207 | message_lower = 'You win! New deal?' 208 | state = 'stop' 209 | else: 210 | if dealer_sum < play_sum: 211 | score_player += 1 212 | message_upper = 'You win!' 213 | message_lower = 'New deal?' 214 | state = 'stop' 215 | else: 216 | score_dealer += 1 217 | message_upper = 'You lose!' 218 | message_lower = 'New deal?' 219 | state = 'stop' 220 | 221 | 222 | 223 | # Step 7: create a frame 224 | frame = simplegui.create_frame('Blackjack', CANVAS_SIZE[0], CANVAS_SIZE[1], 150) 225 | frame.set_canvas_background('Green') 226 | 227 | # Step 8: register all event handlers 228 | frame.set_draw_handler(draw_handler) 229 | frame.add_button('Deal', btn_deal, 150) 230 | frame.add_button('Hit', btn_hit, 150) 231 | frame.add_button('Stand', btn_stand, 150) 232 | 233 | # Step 9: start a new game 234 | new_game() 235 | 236 | # Step 10: start frame 237 | frame.start() -------------------------------------------------------------------------------- /7_Spaceship.py: -------------------------------------------------------------------------------- 1 | # program template for Spaceship 2 | import simplegui 3 | import math 4 | import random 5 | 6 | # globals for user interface 7 | WIDTH = 800 8 | HEIGHT = 600 9 | score = 0 10 | lives = 3 11 | time = 0.5 12 | 13 | # global constants 14 | CST_ANG_VEL = 0.07 # constant of angle velocity of ship 15 | CST_ACC_SPEED = 0.055 # constant of acceleration speed of ship 16 | COE_FRI = 0.008 # coefficient of friction 17 | MIS_SPEED = 10 # constant of missile 18 | 19 | class ImageInfo: 20 | def __init__(self, center, size, radius = 0, lifespan = None, animated = False): 21 | self.center = center 22 | self.size = size 23 | self.radius = radius 24 | if lifespan: 25 | self.lifespan = lifespan 26 | else: 27 | self.lifespan = float('inf') 28 | self.animated = animated 29 | 30 | def get_center(self): 31 | return self.center 32 | 33 | def get_size(self): 34 | return self.size 35 | 36 | def get_radius(self): 37 | return self.radius 38 | 39 | def get_lifespan(self): 40 | return self.lifespan 41 | 42 | def get_animated(self): 43 | return self.animated 44 | 45 | 46 | # art assets created by Kim Lathrop, may be freely re-used in non-commercial projects, please credit Kim 47 | 48 | # debris images - debris1_brown.png, debris2_brown.png, debris3_brown.png, debris4_brown.png 49 | # debris1_blue.png, debris2_blue.png, debris3_blue.png, debris4_blue.png, debris_blend.png 50 | debris_info = ImageInfo([320, 240], [640, 480]) 51 | debris_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png") 52 | 53 | # nebula images - nebula_brown.png, nebula_blue.png 54 | nebula_info = ImageInfo([400, 300], [800, 600]) 55 | nebula_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/nebula_blue.s2014.png") 56 | 57 | # splash image 58 | splash_info = ImageInfo([200, 150], [400, 300]) 59 | splash_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/splash.png") 60 | 61 | # ship image 62 | ship_info = ImageInfo([45, 45], [90, 90], 35) 63 | ship_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/double_ship.png") 64 | 65 | # missile image - shot1.png, shot2.png, shot3.png 66 | missile_info = ImageInfo([5,5], [10, 10], 3, 50) 67 | missile_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/shot2.png") 68 | 69 | # asteroid images - asteroid_blue.png, asteroid_brown.png, asteroid_blend.png 70 | asteroid_info = ImageInfo([45, 45], [90, 90], 40) 71 | asteroid_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png") 72 | 73 | # animated explosion - explosion_orange.png, explosion_blue.png, explosion_blue2.png, explosion_alpha.png 74 | explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True) 75 | explosion_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/explosion_alpha.png") 76 | 77 | # sound assets purchased from sounddogs.com, please do not redistribute 78 | soundtrack = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/soundtrack.mp3") 79 | missile_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/missile.mp3") 80 | missile_sound.set_volume(0) 81 | ship_thrust_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/thrust.mp3") 82 | explosion_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/explosion.mp3") 83 | 84 | # helper functions to handle transformations 85 | def angle_to_vector(ang): 86 | return [math.cos(ang), math.sin(ang)] 87 | 88 | def dist(p,q): 89 | return math.sqrt((p[0] - q[0]) ** 2+(p[1] - q[1]) ** 2) 90 | 91 | 92 | # Ship class 93 | class Ship: 94 | def __init__(self, pos, vel, angle, image, info): 95 | self.pos = [pos[0],pos[1]] 96 | self.vel = [vel[0],vel[1]] 97 | self.thrust = False 98 | self.angle = angle 99 | self.angle_vel = 0 100 | self.image = image 101 | self.image_center = info.get_center() 102 | self.image_size = info.get_size() 103 | self.radius = info.get_radius() 104 | 105 | def draw(self,canvas): 106 | canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle) 107 | 108 | def update(self): 109 | self.angle += self.angle_vel 110 | vec = [0, 0] 111 | ang_t_vel = angle_to_vector(self.angle) 112 | if self.thrust: 113 | vec = [ang_t_vel[0] * CST_ACC_SPEED, ang_t_vel[1] * CST_ACC_SPEED] 114 | friction = [self.vel[0] * COE_FRI, self.vel[1] * COE_FRI] 115 | self.vel[0] += (vec[0] - friction[0]) 116 | self.vel[1] += (vec[1] - friction[1]) 117 | self.pos[0] += self.vel[0] 118 | self.pos[1] += self.vel[1] 119 | self.pos[0] %= WIDTH 120 | self.pos[1] %= HEIGHT 121 | 122 | def thrust_up(self): 123 | self.thrust = True 124 | self.image_center[0] = 135 125 | ship_thrust_sound.play() 126 | ship_thrust_sound.rewind() 127 | ship_thrust_sound.play() 128 | 129 | def stop_thrust(self): 130 | self.thrust = False 131 | self.image_center[0] = 45 132 | ship_thrust_sound.rewind() 133 | 134 | def shoot(self): 135 | global missile_sound, a_missile 136 | missile_sound.set_volume(1) 137 | ang_t_vel = angle_to_vector(self.angle) 138 | a_missile = Sprite([self.pos[0] + (self.radius + 7) * ang_t_vel[0], self.pos[1] + (self.radius + 7) * ang_t_vel[1]], [self.vel[0] + ang_t_vel[0] * MIS_SPEED, self.vel[1] + ang_t_vel[1] * MIS_SPEED], 0, 0, missile_image, missile_info, missile_sound) 139 | 140 | # Sprite class 141 | class Sprite: 142 | def __init__(self, pos, vel, ang, ang_vel, image, info, sound = None): 143 | self.pos = [pos[0],pos[1]] 144 | self.vel = [vel[0],vel[1]] 145 | self.angle = ang 146 | self.angle_vel = ang_vel 147 | self.image = image 148 | self.image_center = info.get_center() 149 | self.image_size = info.get_size() 150 | self.radius = info.get_radius() 151 | self.lifespan = info.get_lifespan() 152 | self.animated = info.get_animated() 153 | self.age = 0 154 | if sound: 155 | sound.rewind() 156 | sound.play() 157 | 158 | def draw(self, canvas): 159 | canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle) 160 | 161 | def update(self): 162 | self.angle += self.angle_vel 163 | self.pos[0] += self.vel[0] 164 | self.pos[1] += self.vel[1] 165 | self.pos[0] %= WIDTH 166 | self.pos[1] %= HEIGHT 167 | 168 | 169 | def draw(canvas): 170 | global time 171 | 172 | # animiate background 173 | time += 1 174 | wtime = (time / 4) % WIDTH 175 | center = debris_info.get_center() 176 | size = debris_info.get_size() 177 | canvas.draw_image(nebula_image, nebula_info.get_center(), nebula_info.get_size(), [WIDTH / 2, HEIGHT / 2], [WIDTH, HEIGHT]) 178 | canvas.draw_image(debris_image, center, size, (wtime - WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) 179 | canvas.draw_image(debris_image, center, size, (wtime + WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) 180 | 181 | # draw ship and sprites 182 | my_ship.draw(canvas) 183 | a_rock.draw(canvas) 184 | a_missile.draw(canvas) 185 | 186 | # update ship and sprites 187 | my_ship.update() 188 | a_rock.update() 189 | a_missile.update() 190 | 191 | # update user interface 192 | canvas.draw_text('lives: ' + str(lives), (70, 40), 40, 'white') 193 | canvas.draw_text('score: ' + str(score), (WIDTH - 200, 40), 40, 'yellow') 194 | 195 | # timer handler that spawns a rock 196 | def rock_spawner(): 197 | global a_rock 198 | a_rock = Sprite([random.randrange(WIDTH), random.randrange(HEIGHT)], [random.choice([-3, -2, -1, 1, 2, 3]), random.choice([-3, -2, -1, 1, 2, 3])], random.randrange(360), random.choice([-1, 1]) * random.random() * 0.1, asteroid_image, asteroid_info) 199 | 200 | # key handlers 201 | def keydown_handler(key): 202 | if key == simplegui.KEY_MAP['right']: 203 | my_ship.angle_vel += CST_ANG_VEL 204 | if key == simplegui.KEY_MAP['left']: 205 | my_ship.angle_vel -= CST_ANG_VEL 206 | if key == simplegui.KEY_MAP['up']: 207 | my_ship.thrust_up() 208 | if key == simplegui.KEY_MAP['space']: 209 | my_ship.shoot() 210 | 211 | def keyup_handler(key): 212 | if key == simplegui.KEY_MAP['right'] or key == simplegui.KEY_MAP['left']: 213 | my_ship.angle_vel = 0 214 | if key == simplegui.KEY_MAP['up']: 215 | my_ship.stop_thrust() 216 | 217 | # initialize frame 218 | frame = simplegui.create_frame("Asteroids", WIDTH, HEIGHT) 219 | 220 | # initialize ship and two sprites 221 | my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info) 222 | a_rock = Sprite([random.randrange(WIDTH), random.randrange(HEIGHT)], [random.choice([-3, -2, -1, 1, 2, 3]), random.choice([-3, -2, -1, 1, 2, 3])], random.randrange(360), random.choice([-1, 1]) * random.random() * 0.1, asteroid_image, asteroid_info) 223 | a_missile = Sprite([0, 0], [0, 0], 0, 0, simplegui.load_image("#"),missile_info, missile_sound) 224 | 225 | # register handlers 226 | frame.set_draw_handler(draw) 227 | 228 | timer = simplegui.create_timer(1000.0, rock_spawner) 229 | frame.set_keydown_handler(keydown_handler) 230 | frame.set_keyup_handler(keyup_handler) 231 | 232 | # get things rolling 233 | timer.start() 234 | frame.start() 235 | -------------------------------------------------------------------------------- /8_RiceRocks.py: -------------------------------------------------------------------------------- 1 | # implementation of Spaceship - program template for RiceRocks 2 | import simplegui 3 | import math 4 | import random 5 | 6 | # globals for user interface 7 | WIDTH = 800 8 | HEIGHT = 600 9 | score = 0 10 | lives = 3 11 | time = 0 12 | rock_group = set([]) 13 | missile_group = set([]) 14 | explosion_group = set([]) 15 | started = False 16 | my_ship = None 17 | 18 | class ImageInfo: 19 | def __init__(self, center, size, radius = 0, lifespan = None, animated = False): 20 | self.center = center 21 | self.size = size 22 | self.radius = radius 23 | if lifespan: 24 | self.lifespan = lifespan 25 | else: 26 | self.lifespan = float('inf') 27 | self.animated = animated 28 | 29 | def get_center(self): 30 | return self.center 31 | 32 | def get_size(self): 33 | return self.size 34 | 35 | def get_radius(self): 36 | return self.radius 37 | 38 | def get_lifespan(self): 39 | return self.lifespan 40 | 41 | def get_animated(self): 42 | return self.animated 43 | 44 | 45 | # art assets created by Kim Lathrop, may be freely re-used in non-commercial projects, please credit Kim 46 | 47 | # debris images - debris1_brown.png, debris2_brown.png, debris3_brown.png, debris4_brown.png 48 | # debris1_blue.png, debris2_blue.png, debris3_blue.png, debris4_blue.png, debris_blend.png 49 | debris_info = ImageInfo([320, 240], [640, 480]) 50 | debris_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png") 51 | 52 | # nebula images - nebula_brown.png, nebula_blue.png 53 | nebula_info = ImageInfo([400, 300], [800, 600]) 54 | nebula_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/nebula_blue.s2014.png") 55 | 56 | # splash image 57 | splash_info = ImageInfo([200, 150], [400, 300]) 58 | splash_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/splash.png") 59 | 60 | # ship image 61 | ship_info = ImageInfo([45, 45], [90, 90], 35) 62 | ship_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/double_ship.png") 63 | 64 | # missile image - shot1.png, shot2.png, shot3.png 65 | missile_info = ImageInfo([5,5], [10, 10], 3, 50) 66 | missile_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/shot2.png") 67 | 68 | # asteroid images - asteroid_blue.png, asteroid_brown.png, asteroid_blend.png 69 | asteroid_info = ImageInfo([45, 45], [90, 90], 40) 70 | asteroid_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png") 71 | 72 | # animated explosion - explosion_orange.png, explosion_blue.png, explosion_blue2.png, explosion_alpha.png 73 | explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True) 74 | explosion_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/explosion_alpha.png") 75 | 76 | # sound assets purchased from sounddogs.com, please do not redistribute 77 | # .ogg versions of sounds are also available, just replace .mp3 by .ogg 78 | soundtrack = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/soundtrack.mp3") 79 | missile_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/missile.mp3") 80 | missile_sound.set_volume(.5) 81 | ship_thrust_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/thrust.mp3") 82 | explosion_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/explosion.mp3") 83 | 84 | # helper functions to handle transformations 85 | def angle_to_vector(ang): 86 | return [math.cos(ang), math.sin(ang)] 87 | 88 | def dist(p, q): 89 | return math.sqrt((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2) 90 | 91 | 92 | # Ship class 93 | class Ship: 94 | 95 | def __init__(self, pos, vel, angle, image, info): 96 | self.pos = [pos[0], pos[1]] 97 | self.vel = [vel[0], vel[1]] 98 | self.thrust = False 99 | self.angle = angle 100 | self.angle_vel = 0 101 | self.image = image 102 | self.image_center = info.get_center() 103 | self.image_size = info.get_size() 104 | self.radius = info.get_radius() 105 | 106 | def draw(self,canvas): 107 | if self.thrust: 108 | canvas.draw_image(self.image, [self.image_center[0] + self.image_size[0], self.image_center[1]] , self.image_size, 109 | self.pos, self.image_size, self.angle) 110 | else: 111 | canvas.draw_image(self.image, self.image_center, self.image_size, 112 | self.pos, self.image_size, self.angle) 113 | # canvas.draw_circle(self.pos, self.radius, 1, "White", "White") 114 | 115 | def update(self): 116 | # update angle 117 | self.angle += self.angle_vel 118 | 119 | # update position 120 | self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH 121 | self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT 122 | 123 | # update velocity 124 | if self.thrust: 125 | acc = angle_to_vector(self.angle) 126 | self.vel[0] += acc[0] * .1 127 | self.vel[1] += acc[1] * .1 128 | 129 | self.vel[0] *= .99 130 | self.vel[1] *= .99 131 | 132 | def set_thrust(self, on): 133 | self.thrust = on 134 | if on: 135 | ship_thrust_sound.rewind() 136 | ship_thrust_sound.play() 137 | else: 138 | ship_thrust_sound.pause() 139 | 140 | def increment_angle_vel(self): 141 | self.angle_vel += .05 142 | 143 | def decrement_angle_vel(self): 144 | self.angle_vel -= .05 145 | 146 | def shoot(self): 147 | global missile_group 148 | forward = angle_to_vector(self.angle) 149 | missile_pos = [self.pos[0] + self.radius * forward[0], self.pos[1] + self.radius * forward[1]] 150 | missile_vel = [self.vel[0] + 6 * forward[0], self.vel[1] + 6 * forward[1]] 151 | missile = Sprite(missile_pos, missile_vel, self.angle, 0, missile_image, missile_info, missile_sound) 152 | missile_group.add(missile) 153 | 154 | def get_position(self): 155 | return self.pos 156 | 157 | def get_radius(self): 158 | return self.radius 159 | 160 | # Sprite class 161 | class Sprite: 162 | def __init__(self, pos, vel, ang, ang_vel, image, info, sound = None): 163 | self.pos = [pos[0],pos[1]] 164 | self.vel = [vel[0],vel[1]] 165 | self.angle = ang 166 | self.angle_vel = ang_vel 167 | self.image = image 168 | self.image_center = info.get_center() 169 | self.image_size = info.get_size() 170 | self.radius = info.get_radius() 171 | self.lifespan = info.get_lifespan() 172 | self.animated = info.get_animated() 173 | self.age = 0 174 | if sound: 175 | sound.rewind() 176 | sound.play() 177 | 178 | def draw(self, canvas): 179 | if self.animated: 180 | canvas.draw_image(self.image, [self.image_center[0] + self.image_size[0] * self.age, self.image_center[1]], self.image_size, 181 | self.pos, self.image_size, self.angle) 182 | else: 183 | canvas.draw_image(self.image, self.image_center, self.image_size, 184 | self.pos, self.image_size, self.angle) 185 | 186 | def update(self): 187 | # update angle 188 | self.angle += self.angle_vel 189 | 190 | # update position 191 | self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH 192 | self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT 193 | 194 | # update age 195 | self.age += 1 196 | if self.age < self.lifespan: 197 | return True 198 | else: 199 | return False 200 | 201 | def get_position(self): 202 | return self.pos 203 | 204 | def get_radius(self): 205 | return self.radius 206 | 207 | def collide(self, other_object): 208 | dis = dist(self.get_position(), other_object.get_position()) 209 | if dis < self.get_radius() + other_object.get_radius(): 210 | return True 211 | else: 212 | return False 213 | 214 | 215 | # key handlers to control ship 216 | def keydown(key): 217 | if key == simplegui.KEY_MAP['left']: 218 | my_ship.decrement_angle_vel() 219 | elif key == simplegui.KEY_MAP['right']: 220 | my_ship.increment_angle_vel() 221 | elif key == simplegui.KEY_MAP['up']: 222 | my_ship.set_thrust(True) 223 | elif key == simplegui.KEY_MAP['space']: 224 | my_ship.shoot() 225 | 226 | def keyup(key): 227 | if key == simplegui.KEY_MAP['left']: 228 | my_ship.increment_angle_vel() 229 | elif key == simplegui.KEY_MAP['right']: 230 | my_ship.decrement_angle_vel() 231 | elif key == simplegui.KEY_MAP['up']: 232 | my_ship.set_thrust(False) 233 | 234 | # mouseclick handlers that reset UI and conditions whether splash image is drawn 235 | def click(pos): 236 | global started, lives, score, time 237 | center = [WIDTH / 2, HEIGHT / 2] 238 | size = splash_info.get_size() 239 | inwidth = (center[0] - size[0] / 2) < pos[0] < (center[0] + size[0] / 2) 240 | inheight = (center[1] - size[1] / 2) < pos[1] < (center[1] + size[1] / 2) 241 | if (not started) and inwidth and inheight: 242 | started = True 243 | lives = 3 244 | score = 0 245 | time = 0 246 | # play soundtrack 247 | soundtrack.rewind() 248 | soundtrack.play() 249 | 250 | def draw(canvas): 251 | global time, started, lives, score, rock_group 252 | 253 | # animiate background 254 | time += 1 255 | 256 | wtime = (time / 4) % WIDTH 257 | center = debris_info.get_center() 258 | size = debris_info.get_size() 259 | canvas.draw_image(nebula_image, nebula_info.get_center(), nebula_info.get_size(), [WIDTH / 2, HEIGHT / 2], [WIDTH, HEIGHT]) 260 | canvas.draw_image(debris_image, center, size, (wtime - WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) 261 | canvas.draw_image(debris_image, center, size, (wtime + WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) 262 | 263 | # draw UI 264 | canvas.draw_text("Lives", [50, 50], 22, "White") 265 | canvas.draw_text("Score", [680, 50], 22, "White") 266 | canvas.draw_text(str(lives), [50, 80], 22, "White") 267 | canvas.draw_text(str(score), [680, 80], 22, "White") 268 | 269 | # draw and update ship 270 | my_ship.draw(canvas) 271 | my_ship.update() 272 | 273 | # draw and update rock_group 274 | process_sprite_group(rock_group, canvas) 275 | 276 | # update ship and sprites 277 | process_sprite_group(missile_group, canvas) 278 | 279 | # update explosion 280 | process_sprite_group(explosion_group, canvas) 281 | 282 | # check Collisions between ship and rocks, and update lives 283 | lives_before = lives 284 | lives -= group_collide(rock_group, my_ship) 285 | lives_after = lives 286 | 287 | # check Collisions between rocks and missile, and update score 288 | score += (group_group_collide(rock_group, missile_group) * 10) 289 | 290 | if lives_before != lives_after and lives_after == 0: 291 | started = False 292 | for rock in rock_group.copy(): 293 | rock_group.discard(rock) 294 | 295 | # draw splash screen if not started 296 | if not started: 297 | canvas.draw_image(splash_image, splash_info.get_center(), 298 | splash_info.get_size(), [WIDTH / 2, HEIGHT / 2], 299 | splash_info.get_size()) 300 | 301 | # adding help function "process_sprite_group" 302 | def process_sprite_group(a_set, canvas): 303 | remove_list = [] 304 | for any_in_set in a_set: 305 | if any_in_set.update() == False: 306 | remove_list.append(any_in_set) 307 | else: 308 | any_in_set.draw(canvas) 309 | for any_in_list in remove_list: 310 | a_set.discard(any_in_list) 311 | 312 | # adding help function "group_collide" 313 | def group_collide(group, other_object): 314 | global explosion_group 315 | remove_list = [] 316 | for any_in_group in group: 317 | if any_in_group.collide(other_object): 318 | remove_list.append(any_in_group) 319 | for any_in_list in remove_list: 320 | group.discard(any_in_list) 321 | explosion = Sprite(other_object.get_position(), [0, 0], 0, 0, explosion_image, explosion_info, explosion_sound) 322 | explosion_group.add(explosion) 323 | return len(remove_list) 324 | 325 | # adding help function "group_group_collide" 326 | def group_group_collide(group_a, group_b): 327 | global explosion_group 328 | remove_list_a = [] 329 | remove_list_b = [] 330 | num_collided = 0 331 | for any_in_group_a in group_a: 332 | for any_in_group_b in group_b: 333 | if any_in_group_b.collide(any_in_group_a): 334 | remove_list_a.append(any_in_group_a) 335 | remove_list_b.append(any_in_group_b) 336 | num_collided += 1 337 | for a in remove_list_a: 338 | group_a.discard(a) 339 | explosion = Sprite(a.get_position(), [0, 0], 0, 0, explosion_image, explosion_info, explosion_sound) 340 | explosion_group.add(explosion) 341 | for b in remove_list_b: 342 | group_b.discard(b) 343 | return num_collided 344 | 345 | # timer handler that spawns a rock 346 | def rock_spawner(): 347 | global rock_group 348 | if started: 349 | if len(list(rock_group)) != 12: 350 | # make rocks not to be so close to the ship 351 | rock_pos = None 352 | ship_x = my_ship.get_position()[0] 353 | ship_y = my_ship.get_position()[1] 354 | gap = 90 355 | while True: 356 | x = random.randrange(0, WIDTH) 357 | y = random.randrange(0, HEIGHT) 358 | if ((x - ship_x) > gap or (x - ship_x) < -gap) and ((y - ship_y) > gap or (y - ship_y) < -gap): 359 | rock_pos = [x, y] 360 | break 361 | #rock_vel = [random.random() * .6 - .3, random.random() * .6 - .3] 362 | rock_vel = [random.random() * random.randrange(-1, 2, 2), random.random() * random.randrange(-1, 2, 2)] 363 | rock_avel = random.random() * .2 - .1 364 | rock = Sprite(rock_pos, rock_vel, 0, rock_avel, asteroid_image, asteroid_info) 365 | rock_group.add(rock) 366 | 367 | 368 | # initialize stuff 369 | frame = simplegui.create_frame("Asteroids", WIDTH, HEIGHT) 370 | 371 | # initialize ship and two sprites 372 | my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info) 373 | 374 | 375 | # register handlers 376 | frame.set_keyup_handler(keyup) 377 | frame.set_keydown_handler(keydown) 378 | frame.set_mouseclick_handler(click) 379 | frame.set_draw_handler(draw) 380 | 381 | timer = simplegui.create_timer(1000.0, rock_spawner) 382 | 383 | # get things rolling 384 | timer.start() 385 | frame.start() 386 | soundtrack.rewind() 387 | soundtrack.play() 388 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mini-projects-while-learning-python 2 | ## Intruduction 3 | This is my source code for the Mini-projects for the course _An Introduction to Interactive Programming in Python_ in [Coursera](https://www.coursera.org). It is a good course for learning how to program in Python. To find more information, please click here: [https://class.coursera.org/interactivepython-004](https://class.coursera.org/interactivepython-004) 4 | 5 | **WARNING:** 6 | Hello, all my classmates! I want to remind you of the [Honor code](https://class.coursera.org/interactivepython-004/wiki/honorcode). You are welcomed to read my code, but you can't just copy it!!! 7 | 8 | ## Editor 9 | We use a unique editor(or IDE) for programming in Python for this course, which calls [codeskulptor](http://www.codeskulptor.org/), so all my source code can only run in this environment. And it also provide a debug mode, which calls [Viz mode](http://www.codeskulptor.org/viz/). Remenber that there is a helpful [document](http://www.codeskulptor.org/docs.html#tabs-Python) where we can find the descriptions of all the libraries that we'll use. 10 | 11 | ## Introduction for each mini project 12 | ### 1. [Rock-paper-scissors-lizard-Spock](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/28/) 13 | ![Rock-paper-scissors-lizard-Spock](http://i.imgur.com/0mRRwyS.png) 14 | 15 | ### 2. ["Guess the number" game](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/29/) 16 | !["Guess the number" game](http://i.imgur.com/6zHDt4l.png) 17 | 18 | ### 3. ["Stopwatch: The Game"](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/30/) 19 | !["Stopwatch: The Game"](http://i.imgur.com/yxjBpX2.png) 20 | 21 | ### 4. ["Pong"](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/31/) 22 | !["Pong"](http://i.imgur.com/qiqSCmZ.png) 23 | 24 | ### 5. [Memory](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/32/) 25 | ![Memory](http://i.imgur.com/Z9WoYBF.png) 26 | 27 | ### 6. [Blackjack](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/33/) 28 | ![Blackjack](http://i.imgur.com/EuRbulo.png) 29 | 30 | ### 7. [Spaceship](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/34/) 31 | ![Spaceship](http://i.imgur.com/phur5Ub.png) 32 | 33 | ### 8. [RiceRocks (Asteroids)](https://class.coursera.org/interactivepython-004/human_grading/view/courses/972072/assessments/35/) 34 | ![RiceRocks (Asteroids)](http://i.imgur.com/3spW3BR.png) --------------------------------------------------------------------------------