Last active
December 15, 2015 09:29
-
-
Save phirework/5239284 to your computer and use it in GitHub Desktop.
Here's a command-line game I wrote for my Hacker School app. (It's also my first independently-written Python script, hurray.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from sys import exit | |
| from collections import defaultdict | |
| from random import randint | |
| import time | |
| # Create a list with 9 spaces in it | |
| grid = [] | |
| for x in range(0, 9): | |
| grid.append(' ') | |
| # Define the win conditions for Tic-Tac-Toe | |
| win_cond = [ | |
| [0,1,2], [3,4,5], [6,7,8], | |
| [0,3,6], [1,4,7], [2,5,8], | |
| [0,4,8], [2,4,6]] | |
| # Print out a visual representation of the board | |
| def board(): | |
| board = " %s | %s | %s \n----------- \n %s | %s | %s \n----------- \n %s | %s | %s" | |
| print board % tuple(grid) | |
| # Initializes the game | |
| def start(): | |
| # Print the intro banner for the game | |
| print start_msg | |
| enter = raw_input("Press Enter to continue. ") | |
| # Resets the grid | |
| for x in range(0,9): | |
| grid[x] = x+1 | |
| # Prints the current board | |
| board() | |
| # Generate either 0 or 1 randomly to decide which way the "coin" came down | |
| if coin_toss() == randint(0,1): | |
| print start_first | |
| your_turn() | |
| else: | |
| print start_second | |
| computer_turn() | |
| ## Create a function that simulates a coin toss to decide who goes first | |
| def coin_toss(): | |
| print coin_toss_msg | |
| starter = raw_input("> ") | |
| if starter == heads: | |
| return 1 | |
| elif starter == tails: | |
| return 0 | |
| else: | |
| print coin_error | |
| coin_toss() | |
| ## Start the player's turn | |
| def your_turn(): | |
| print your_turn_msg | |
| turn() | |
| ## The actual player input part - separated from your_turn() to avoid reprinting instructions when it hits an error | |
| def turn(): | |
| player_move = raw_input("> ") | |
| try: | |
| play = int(player_move) | |
| # If the player entered something other than a number, prompt them again | |
| except ValueError: | |
| print value_error | |
| turn() | |
| # If the player entered a number out of range, prompt them again | |
| if play > 9 or play < 1: | |
| print range_error | |
| turn() | |
| # If the player is trying to play on a space that's already taken, prompt them again | |
| elif isinstance(grid[play-1], int) == False: | |
| print taken_error | |
| turn() | |
| # If everything is correct, set the grid to the player character O and check to see if there are any ties/wins | |
| else: | |
| grid[play-1] = "O" | |
| check_win() | |
| check_tie() | |
| print "\n" | |
| board() | |
| computer_turn() | |
| ## Start the computer's turn | |
| def computer_turn(): | |
| print computer_turn_msg | |
| # Check if the center spot is taken. If not, take it. | |
| if isinstance(grid[4],int): | |
| grid[4] = "X" | |
| # If it is taken, see if there are any rows that have two strings of the same kind in it | |
| else: | |
| almost() | |
| computer_end() | |
| your_turn() | |
| ## Check if there are any rows that have two strings of the same kind in it | |
| def almost(): | |
| # For each set of win conditions in the win condition | |
| for win in win_cond: | |
| # Set a to the first position in the set | |
| a = win[0] | |
| # Set b to the second position in the set | |
| b = win[1] | |
| # Set c to the third position in the set | |
| c = win[2] | |
| # Create an list made up of entries a, b, and c | |
| line = [grid[a], grid[b], grid[c]] | |
| # See if there are duplicate entries in the list | |
| # The number of unique entires will be different from the number of total entries | |
| if len(line) != len(set(line)): | |
| # If Yes, see if each position is empty, and take it if so. | |
| # End the computer's turn and pass it onto the player after something has been played | |
| if isinstance(grid[a],int): | |
| grid[a] = "X" | |
| computer_end() | |
| your_turn() | |
| elif isinstance(grid[b], int): | |
| # if yes, take it | |
| grid[b] = "X" | |
| computer_end() | |
| your_turn() | |
| elif isinstance(grid[c],int): | |
| grid[c] = "X" | |
| computer_end() | |
| your_turn() | |
| # If there are no duplicate entries in this set of win conditions, it goes on to check the next one | |
| # If there are no rows that have two strings of hte same kind in it, make a regular move | |
| computer_move() | |
| ## These are the regular moves the computer can choose from if there are no imminent threats | |
| ## Or chances for winning | |
| def computer_move(): | |
| # If the middle square is a computer-occupied square, use the random_move() algorithm | |
| if grid[4] == "X": | |
| random_move() | |
| # If this is the first move the computer is making, and the middle square is taken | |
| # Play one of the corner positions and end the turn after something has been played | |
| elif not ('X' in grid): | |
| outside = [0,2,6,8] | |
| for pos in outside: | |
| if isinstance(grid[pos], int): | |
| grid[pos] = "X" | |
| break | |
| computer_end() | |
| your_turn() | |
| # If this is not the first move the computer is making, use the same_row() algorithm | |
| else: | |
| same_row() | |
| # Once same_row() has been executed, end the computer's turn | |
| computer_end() | |
| your_turn() | |
| ## This picks the first available spot to play. It's undiscriminating because it only gets | |
| ## executed if the center square belongs to the computer, and it will form a line either way | |
| def random_move(): | |
| for x in range(0,9): | |
| if isinstance(grid[x], int): | |
| grid[x] = "X" | |
| computer_end() | |
| your_turn() | |
| ## If there is already an X on the board, and the center square is not the computer | |
| ## place an X in another corner that lines up with the first one | |
| def same_row(): | |
| # Find where the current X is | |
| position = grid.index('X') | |
| # Define the two corresponding corners for each corner | |
| outer = [(0,2),(0,6),(2,0),(2,8),(6,0),(6,8),(8,2),(8,6)] | |
| same_row = defaultdict(list) | |
| for key, value in outer: | |
| same_row[key].append(value) | |
| for key in same_row: | |
| # Find the two corresponding corners that match the current position of X | |
| if position == key: | |
| remainder = same_row[key] | |
| # Place an X on the first available corresponding corner | |
| for pos in remainder: | |
| if isinstance(grid[pos],int): | |
| grid[pos] = "X" | |
| # Once same row has been executed, go back to computer_move() which will end the computer's turn | |
| ## This ends the computer's turn and shows the new board | |
| def computer_end(): | |
| check_win() | |
| check_tie() | |
| print think_msg | |
| time.sleep(.75) | |
| board() | |
| ## Checks whether or not there is a winner after each turn | |
| def check_win(): | |
| # Iterate the 3 positions of each set of win conditions | |
| for win in win_cond: | |
| a = win[0] | |
| b = win[1] | |
| c = win[2] | |
| # Create a list of the current values of the 3 positions | |
| line = [grid[a], grid[b], grid[c]] | |
| # If the list is all 'X', then the computer has won | |
| if line == ['X', 'X', 'X']: | |
| board() | |
| print you_lose | |
| again() | |
| # If the list is all 'O', then the player has won | |
| elif line == ['O', 'O', 'O']: | |
| board() | |
| print you_win | |
| again() | |
| ## Checks whether or not there is a tie after each turn | |
| def check_tie(): | |
| # If each position in the grid is a string (X or O) and check_win didn't find a winner | |
| # Then declare a tie and offer to play again | |
| tie = all(isinstance(x, str) for x in grid) | |
| if tie == True: | |
| print we_draw | |
| again() | |
| ## Resets the game at the end of the game | |
| def again(): | |
| print play_again | |
| again = raw_input("> ").lower() | |
| if again == "y": | |
| start() | |
| else: | |
| print thanks_msg | |
| exit() | |
| start_msg = """ | |
| ############################################################################# | |
| # # | |
| # TIC: Tac T.O.E # | |
| # # | |
| # Telnet Intrusion/Compromise: Tactical training & Online Evaluation # | |
| # # | |
| ############################################################################# | |
| > Good, you're here. That means you've made it all the other obstacles we've | |
| set you. This is your final test before you can move onto the big leagues. | |
| We've created an advanced simulation of a real-world scenario in which you | |
| are the only thing that stands between crafty Martian hackers and the | |
| integrity of our network security. We'll need you to activate the final | |
| defense system to ward them off. | |
| Unfortunately, we were a little...overzealous in our interface design. You | |
| can't just flip a switch. You'll need to activate three nodes in a linear | |
| pattern to create a virtual firewall. And while you're racing to complete | |
| this task, the hackers are worming into gaps in the protection. | |
| Google ain't gonna help you here. Good luck. """ | |
| heads = "1" | |
| tails = "0" | |
| coin_toss_msg = """ | |
| > To test your nerves and dumb luck we're going to see if you can predict | |
| the outcome of this randomly generated binary variable. Is it %s? Or %s? """ % (heads, tails) | |
| coin_error = """ | |
| > That wasn't one of the options. You're not starting off too well here, I | |
| gotta say. """ | |
| start_first = """ | |
| > Huh, you were right. Who would've thought. Don't waste your chance. """ | |
| start_second = """ | |
| > Good going, hero. The Martians get to make the first move. """ | |
| your_turn_msg = """ | |
| > Okay kid, time to shine. You know how it goes - enter a number from 1-9. """ | |
| value_error = """ | |
| > Uh, that's not a number. How did you even make it this far? | |
| 1-9, base 10. Don't try anything clever. """ | |
| range_error = "\n> Dude, do you even know how to count? 1-9." | |
| taken_error = """ | |
| > Come on now, that switch is clearly taken. I'll overlook it this time. """ | |
| computer_turn_msg = """ | |
| > Now you get to wait as foreign intruders ruin your life's work. Not to be | |
| hyperbolic or anything. """ | |
| think_msg = "\nStanding by...\n" | |
| you_lose = """ | |
| > Welp, the intruders have managed to gain access to your system. Too bad, | |
| kiddo. Looks like you're not quite ready for the big leagues. Better luck | |
| next time. """ | |
| you_win = """ | |
| > Congratulations, you have successfully fended off the foreign intruders and | |
| completed this evaluation. Please report to HS headquarters in New York City | |
| for the next stage of your training. We hope to see you soon. """ | |
| we_draw = """ | |
| > It would seem that you have reached a stalement in this exercise. That's... | |
| unusual. Are you always this much trouble? """ | |
| play_again = "\n> Do you think you can handle this challenge again? Y/N" | |
| thanks_msg = "gg ttyl kthxbye" | |
| start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment