├── .gitpod.yml ├── README.md ├── client.py ├── game.py ├── network.py ├── requirements.txt └── server.py /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: gitpod/workspace-full-vnc 2 | ports: 3 | - port: 5900 4 | onOpen: ignore 5 | - port: 6080 6 | onOpen: open-preview 7 | tasks: 8 | - init: pip3 install -r requirements.txt 9 | command: python3 client.py 10 | - command: python3 server.py 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Online-Rock-Paper-Scissors 2 | An online game of rock paper scissors, supporting infinite games. Created with pygame and sockets. 3 | 4 | # Running The Game 5 | To run the game you will need to run an instane of *server.py* on one machine. Then you can run instances of *client.py* on other machines to connect. 6 | 7 | You will need to change the **server** address in both *server.py* and *client.py* to be the IPV4 address of your machine or the server ips you'll be using. 8 | 9 | # 💻 Launch Your Software Development Career Today! 10 | 11 | 🎓 **No degree? No problem!** My program equips you with everything you need to break into tech and land an entry-level software development role. 12 | 13 | 🚀 **Why Join?** 14 | - 💼 **$70k+ starting salary potential** 15 | - 🕐 **Self-paced:** Complete on your own time 16 | - 🤑 **Affordable:** Low risk compared to expensive bootcamps or degrees 17 | - 🎯 **45,000+ job openings** in the market 18 | 19 | 👉 **[Start your journey today!](https://techwithtim.net/dev)** 20 | No experience needed—just your determination. Future-proof your career and unlock six-figure potential like many of our students have! 21 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from network import Network 3 | import pickle 4 | pygame.font.init() 5 | 6 | width = 700 7 | height = 700 8 | win = pygame.display.set_mode((width, height)) 9 | pygame.display.set_caption("Client") 10 | 11 | 12 | class Button: 13 | def __init__(self, text, x, y, color): 14 | self.text = text 15 | self.x = x 16 | self.y = y 17 | self.color = color 18 | self.width = 150 19 | self.height = 100 20 | 21 | def draw(self, win): 22 | pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height)) 23 | font = pygame.font.SysFont("comicsans", 40) 24 | text = font.render(self.text, 1, (255,255,255)) 25 | win.blit(text, (self.x + round(self.width/2) - round(text.get_width()/2), self.y + round(self.height/2) - round(text.get_height()/2))) 26 | 27 | def click(self, pos): 28 | x1 = pos[0] 29 | y1 = pos[1] 30 | if self.x <= x1 <= self.x + self.width and self.y <= y1 <= self.y + self.height: 31 | return True 32 | else: 33 | return False 34 | 35 | 36 | def redrawWindow(win, game, p): 37 | win.fill((128,128,128)) 38 | 39 | if not(game.connected()): 40 | font = pygame.font.SysFont("comicsans", 80) 41 | text = font.render("Waiting for Player...", 1, (255,0,0), True) 42 | win.blit(text, (width/2 - text.get_width()/2, height/2 - text.get_height()/2)) 43 | else: 44 | font = pygame.font.SysFont("comicsans", 60) 45 | text = font.render("Your Move", 1, (0, 255,255)) 46 | win.blit(text, (80, 200)) 47 | 48 | text = font.render("Opponents", 1, (0, 255, 255)) 49 | win.blit(text, (380, 200)) 50 | 51 | move1 = game.get_player_move(0) 52 | move2 = game.get_player_move(1) 53 | if game.bothWent(): 54 | text1 = font.render(move1, 1, (0,0,0)) 55 | text2 = font.render(move2, 1, (0, 0, 0)) 56 | else: 57 | if game.p1Went and p == 0: 58 | text1 = font.render(move1, 1, (0,0,0)) 59 | elif game.p1Went: 60 | text1 = font.render("Locked In", 1, (0, 0, 0)) 61 | else: 62 | text1 = font.render("Waiting...", 1, (0, 0, 0)) 63 | 64 | if game.p2Went and p == 1: 65 | text2 = font.render(move2, 1, (0,0,0)) 66 | elif game.p2Went: 67 | text2 = font.render("Locked In", 1, (0, 0, 0)) 68 | else: 69 | text2 = font.render("Waiting...", 1, (0, 0, 0)) 70 | 71 | if p == 1: 72 | win.blit(text2, (100, 350)) 73 | win.blit(text1, (400, 350)) 74 | else: 75 | win.blit(text1, (100, 350)) 76 | win.blit(text2, (400, 350)) 77 | 78 | for btn in btns: 79 | btn.draw(win) 80 | 81 | pygame.display.update() 82 | 83 | 84 | btns = [Button("Rock", 50, 500, (0,0,0)), Button("Scissors", 250, 500, (255,0,0)), Button("Paper", 450, 500, (0,255,0))] 85 | def main(): 86 | run = True 87 | clock = pygame.time.Clock() 88 | n = Network() 89 | player = int(n.getP()) 90 | print("You are player", player) 91 | 92 | while run: 93 | clock.tick(60) 94 | try: 95 | game = n.send("get") 96 | except: 97 | run = False 98 | print("Couldn't get game") 99 | break 100 | 101 | if game.bothWent(): 102 | redrawWindow(win, game, player) 103 | pygame.time.delay(500) 104 | try: 105 | game = n.send("reset") 106 | except: 107 | run = False 108 | print("Couldn't get game") 109 | break 110 | 111 | font = pygame.font.SysFont("comicsans", 90) 112 | if (game.winner() == 1 and player == 1) or (game.winner() == 0 and player == 0): 113 | text = font.render("You Won!", 1, (255,0,0)) 114 | elif game.winner() == -1: 115 | text = font.render("Tie Game!", 1, (255,0,0)) 116 | else: 117 | text = font.render("You Lost...", 1, (255, 0, 0)) 118 | 119 | win.blit(text, (width/2 - text.get_width()/2, height/2 - text.get_height()/2)) 120 | pygame.display.update() 121 | pygame.time.delay(2000) 122 | 123 | for event in pygame.event.get(): 124 | if event.type == pygame.QUIT: 125 | run = False 126 | pygame.quit() 127 | 128 | if event.type == pygame.MOUSEBUTTONDOWN: 129 | pos = pygame.mouse.get_pos() 130 | for btn in btns: 131 | if btn.click(pos) and game.connected(): 132 | if player == 0: 133 | if not game.p1Went: 134 | n.send(btn.text) 135 | else: 136 | if not game.p2Went: 137 | n.send(btn.text) 138 | 139 | redrawWindow(win, game, player) 140 | 141 | def menu_screen(): 142 | run = True 143 | clock = pygame.time.Clock() 144 | 145 | while run: 146 | clock.tick(60) 147 | win.fill((128, 128, 128)) 148 | font = pygame.font.SysFont("comicsans", 60) 149 | text = font.render("Click to Play!", 1, (255,0,0)) 150 | win.blit(text, (100,200)) 151 | pygame.display.update() 152 | 153 | for event in pygame.event.get(): 154 | if event.type == pygame.QUIT: 155 | pygame.quit() 156 | run = False 157 | if event.type == pygame.MOUSEBUTTONDOWN: 158 | run = False 159 | 160 | main() 161 | 162 | while True: 163 | menu_screen() 164 | -------------------------------------------------------------------------------- /game.py: -------------------------------------------------------------------------------- 1 | class Game: 2 | def __init__(self, id): 3 | self.p1Went = False 4 | self.p2Went = False 5 | self.ready = False 6 | self.id = id 7 | self.moves = [None, None] 8 | self.wins = [0,0] 9 | self.ties = 0 10 | 11 | def get_player_move(self, p): 12 | """ 13 | :param p: [0,1] 14 | :return: Move 15 | """ 16 | return self.moves[p] 17 | 18 | def play(self, player, move): 19 | self.moves[player] = move 20 | if player == 0: 21 | self.p1Went = True 22 | else: 23 | self.p2Went = True 24 | 25 | def connected(self): 26 | return self.ready 27 | 28 | def bothWent(self): 29 | return self.p1Went and self.p2Went 30 | 31 | def winner(self): 32 | 33 | p1 = self.moves[0].upper()[0] 34 | p2 = self.moves[1].upper()[0] 35 | 36 | winner = -1 37 | if p1 == "R" and p2 == "S": 38 | winner = 0 39 | elif p1 == "S" and p2 == "R": 40 | winner = 1 41 | elif p1 == "P" and p2 == "R": 42 | winner = 0 43 | elif p1 == "R" and p2 == "P": 44 | winner = 1 45 | elif p1 == "S" and p2 == "P": 46 | winner = 0 47 | elif p1 == "P" and p2 == "S": 48 | winner = 1 49 | 50 | return winner 51 | 52 | def resetWent(self): 53 | self.p1Went = False 54 | self.p2Went = False -------------------------------------------------------------------------------- /network.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | 4 | 5 | class Network: 6 | def __init__(self): 7 | self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | self.server = "localhost" 9 | self.port = 5555 10 | self.addr = (self.server, self.port) 11 | self.p = self.connect() 12 | 13 | def getP(self): 14 | return self.p 15 | 16 | def connect(self): 17 | try: 18 | self.client.connect(self.addr) 19 | return self.client.recv(2048).decode() 20 | except: 21 | pass 22 | 23 | def send(self, data): 24 | try: 25 | self.client.send(str.encode(data)) 26 | return pickle.loads(self.client.recv(2048*2)) 27 | except socket.error as e: 28 | print(e) 29 | 30 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pygame 2 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from _thread import * 3 | import pickle 4 | from game import Game 5 | 6 | server = "localhost" 7 | port = 5555 8 | 9 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | 11 | try: 12 | s.bind((server, port)) 13 | except socket.error as e: 14 | str(e) 15 | 16 | s.listen(2) 17 | print("Waiting for a connection, Server Started") 18 | 19 | connected = set() 20 | games = {} 21 | idCount = 0 22 | 23 | 24 | def threaded_client(conn, p, gameId): 25 | global idCount 26 | conn.send(str.encode(str(p))) 27 | 28 | reply = "" 29 | while True: 30 | try: 31 | data = conn.recv(4096).decode() 32 | 33 | if gameId in games: 34 | game = games[gameId] 35 | 36 | if not data: 37 | break 38 | else: 39 | if data == "reset": 40 | game.resetWent() 41 | elif data != "get": 42 | game.play(p, data) 43 | 44 | conn.sendall(pickle.dumps(game)) 45 | else: 46 | break 47 | except: 48 | break 49 | 50 | print("Lost connection") 51 | try: 52 | del games[gameId] 53 | print("Closing Game", gameId) 54 | except: 55 | pass 56 | idCount -= 1 57 | conn.close() 58 | 59 | 60 | 61 | while True: 62 | conn, addr = s.accept() 63 | print("Connected to:", addr) 64 | 65 | idCount += 1 66 | p = 0 67 | gameId = (idCount - 1)//2 68 | if idCount % 2 == 1: 69 | games[gameId] = Game(gameId) 70 | print("Creating a new game...") 71 | else: 72 | games[gameId].ready = True 73 | p = 1 74 | 75 | 76 | start_new_thread(threaded_client, (conn, p, gameId)) 77 | --------------------------------------------------------------------------------