diff --git a/projects/Connect Four/main.py b/projects/Connect Four/main.py index 370fcffe7..eec092b99 100644 --- a/projects/Connect Four/main.py +++ b/projects/Connect Four/main.py @@ -3,40 +3,49 @@ import sys import math +# Colors BLUE = (0, 0, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) YELLOW = (255, 255, 0) +# Constants ROW_COUNT = 6 COLUMN_COUNT = 7 +SQUARESIZE = 100 +RADIUS = int(SQUARESIZE / 2 - 5) +WIDTH = COLUMN_COUNT * SQUARESIZE +HEIGHT = (ROW_COUNT + 1) * SQUARESIZE +SIZE = (WIDTH, HEIGHT) + +# Initialize Pygame +pygame.init() +# Font for winner message (smaller size) +myfont = pygame.font.SysFont("monospace", 50) +winner_font = pygame.font.SysFont("monospace", 30) +# Initialize the game board def create_board(): - board = np.zeros((ROW_COUNT, COLUMN_COUNT)) - return board - + return np.zeros((ROW_COUNT, COLUMN_COUNT)) +# Drop piece on the board def drop_piece(board, row, col, piece): board[row][col] = piece - +# Check if a column is a valid location def is_valid_location(board, col): return board[ROW_COUNT - 1][col] == 0 - +# Get the next available row in a column def get_next_open_row(board, col): for r in range(ROW_COUNT): if board[r][col] == 0: return r - -def print_board(board): - print(np.flip(board, 0)) - - +# Check for a winning move def winning_move(board, piece): - # Check horizontal locations for win + # Horizontal for c in range(COLUMN_COUNT - 3): for r in range(ROW_COUNT): if ( @@ -47,7 +56,7 @@ def winning_move(board, piece): ): return True - # Check vertical locations for win + # Vertical for c in range(COLUMN_COUNT): for r in range(ROW_COUNT - 3): if ( @@ -58,7 +67,7 @@ def winning_move(board, piece): ): return True - # Check positively sloped diaganols + # Diagonal positive slope for c in range(COLUMN_COUNT - 3): for r in range(ROW_COUNT - 3): if ( @@ -69,7 +78,7 @@ def winning_move(board, piece): ): return True - # Check negatively sloped diaganols + # Diagonal negative slope for c in range(COLUMN_COUNT - 3): for r in range(3, ROW_COUNT): if ( @@ -79,127 +88,83 @@ def winning_move(board, piece): and board[r - 3][c + 3] == piece ): return True + return False - -def draw_board(board): +# Draw the game board +def draw_board(board, screen): for c in range(COLUMN_COUNT): for r in range(ROW_COUNT): pygame.draw.rect( - screen, - BLUE, - (c * SQUARESIZE, r * SQUARESIZE + SQUARESIZE, SQUARESIZE, SQUARESIZE), + screen, BLUE, (c * SQUARESIZE, r * SQUARESIZE + SQUARESIZE, SQUARESIZE, SQUARESIZE) ) pygame.draw.circle( - screen, - BLACK, - ( - int(c * SQUARESIZE + SQUARESIZE / 2), - int(r * SQUARESIZE + SQUARESIZE + SQUARESIZE / 2), - ), - RADIUS, + screen, BLACK, (int(c * SQUARESIZE + SQUARESIZE / 2), int(r * SQUARESIZE + SQUARESIZE + SQUARESIZE / 2)), RADIUS ) for c in range(COLUMN_COUNT): for r in range(ROW_COUNT): if board[r][c] == 1: pygame.draw.circle( - screen, - RED, - ( - int(c * SQUARESIZE + SQUARESIZE / 2), - height - int(r * SQUARESIZE + SQUARESIZE / 2), - ), - RADIUS, + screen, RED, (int(c * SQUARESIZE + SQUARESIZE / 2), HEIGHT - int(r * SQUARESIZE + SQUARESIZE / 2)), RADIUS ) elif board[r][c] == 2: pygame.draw.circle( - screen, - YELLOW, - ( - int(c * SQUARESIZE + SQUARESIZE / 2), - height - int(r * SQUARESIZE + SQUARESIZE / 2), - ), - RADIUS, + screen, YELLOW, (int(c * SQUARESIZE + SQUARESIZE / 2), HEIGHT - int(r * SQUARESIZE + SQUARESIZE / 2)), RADIUS ) pygame.display.update() +# Show popup winner message +def show_popup(screen, message): + popup = pygame.Surface((400, 200)) + popup.fill(WHITE) + text = winner_font.render(message, True, BLACK) + popup.blit(text, (50, 70)) -board = create_board() -print_board(board) -game_over = False -turn = 0 - -# initalize pygame -pygame.init() + screen.blit(popup, (WIDTH // 2 - 200, HEIGHT // 2 - 100)) + pygame.display.update() -# define our screen size -SQUARESIZE = 100 +# Main game loop +def main(): + board = create_board() + screen = pygame.display.set_mode(SIZE) + pygame.display.set_caption("Connect Four") -# define width and height of board -width = COLUMN_COUNT * SQUARESIZE -height = (ROW_COUNT + 1) * SQUARESIZE + game_over = False + turn = 0 -size = (width, height) + draw_board(board, screen) -RADIUS = int(SQUARESIZE / 2 - 5) + while not game_over: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() -screen = pygame.display.set_mode(size) -# Calling function draw_board again -draw_board(board) -pygame.display.update() - -myfont = pygame.font.SysFont("monospace", 75) - -while not game_over: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - sys.exit() - - if event.type == pygame.MOUSEMOTION: - pygame.draw.rect(screen, BLACK, (0, 0, width, SQUARESIZE)) - posx = event.pos[0] - if turn == 0: - pygame.draw.circle(screen, RED, (posx, int(SQUARESIZE / 2)), RADIUS) - else: - pygame.draw.circle(screen, YELLOW, (posx, int(SQUARESIZE / 2)), RADIUS) - pygame.display.update() - - if event.type == pygame.MOUSEBUTTONDOWN: - pygame.draw.rect(screen, BLACK, (0, 0, width, SQUARESIZE)) - # print(event.pos) - # Ask for Player 1 Input - if turn == 0: + if event.type == pygame.MOUSEMOTION: + pygame.draw.rect(screen, BLACK, (0, 0, WIDTH, SQUARESIZE)) posx = event.pos[0] - col = int(math.floor(posx / SQUARESIZE)) + if turn == 0: + pygame.draw.circle(screen, RED, (posx, int(SQUARESIZE / 2)), RADIUS) + else: + pygame.draw.circle(screen, YELLOW, (posx, int(SQUARESIZE / 2)), RADIUS) - if is_valid_location(board, col): - row = get_next_open_row(board, col) - drop_piece(board, row, col, 1) - - if winning_move(board, 1): - label = myfont.render("Player 1 wins!!", 1, RED) - screen.blit(label, (40, 10)) - game_over = True - - # # Ask for Player 2 Input - else: - posx = event.pos[0] - col = int(math.floor(posx / SQUARESIZE)) + if event.type == pygame.MOUSEBUTTONDOWN: + pygame.draw.rect(screen, BLACK, (0, 0, WIDTH, SQUARESIZE)) + col = int(math.floor(event.pos[0] / SQUARESIZE)) if is_valid_location(board, col): row = get_next_open_row(board, col) - drop_piece(board, row, col, 2) + drop_piece(board, row, col, turn + 1) - if winning_move(board, 2): - label = myfont.render("Player 2 wins!!", 1, YELLOW) - screen.blit(label, (40, 10)) + if winning_move(board, turn + 1): + show_popup(screen, f"Player {turn + 1} Wins!") + pygame.time.wait(5000) # Wait for 5 seconds before ending the game game_over = True - print_board(board) - draw_board(board) + turn = (turn + 1) % 2 + draw_board(board, screen) - turn += 1 - turn = turn % 2 + pygame.quit() - if game_over: - pygame.time.wait(3000) +if __name__ == "__main__": + main() diff --git a/projects/Drowsiness Detector/main.py b/projects/Drowsiness Detector/main.py index 6c385fa44..78c9fa225 100644 --- a/projects/Drowsiness Detector/main.py +++ b/projects/Drowsiness Detector/main.py @@ -1,6 +1,5 @@ # import the necessary packages from scipy.spatial import distance as dist - from imutils.video import VideoStream from imutils import face_utils from threading import Thread @@ -12,121 +11,80 @@ import dlib import cv2 - # the alarm function - - def sound_alarm(path): playsound.playsound(path) - # Eye Aspect Ratio - - def eye_aspect_ratio(eye): - # find the Euclidean distance between the two sets of vertical eye landmark A = dist.euclidean(eye[1], eye[5]) B = dist.euclidean(eye[2], eye[4]) - - # find the Euclidean distance between the horizontal eye landmark C = dist.euclidean(eye[0], eye[3]) - - # compute the eye aspect ratio ear = (A + B) / (2.0 * C) - - # return the eye aspect ratio return ear - # parse our command line arguments - ap = argparse.ArgumentParser() ap.add_argument( - "-p", "--shape-predictor", required=True, help="path to facial landmark predictor" + "-p", "--shape-predictor", required=False, default="shape_predictor.dat", + help="path to facial landmark predictor (default: shape_predictor.dat)" ) ap.add_argument("-a", "--alarm", type=str, default="", help="path alarm file") ap.add_argument("-w", "--webcam", type=int, default=0, help="index of webcam on system") args = vars(ap.parse_args()) -# define two constants , one for the eye aspect ratio to indicate blink -# second constant for the number of consecutive frames the eye must be below -# the threshold to set the alarm - +# define two constants for the EAR threshold and consecutive frames EYE_AR_THRESH = 0.3 -# if the eye aspect ratio falls below this threshold, we’ll start counting the number of frames the person has closed -# their eyes for. EYE_AR_CONSEC_FRAMES = 48 -# initialize the frame counter as well as a boolean used to indicate if the alarm is going off - +# initialize the frame counter and alarm flag COUNTER = 0 ALARM_ON = False # initialize dlib's face detector -print("[INFO} loading facial landmark predictor...") +print("[INFO] loading facial landmark predictor...") detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor(args["shape_predictor"]) -# Extract the Eye Region +# extract the eye regions (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"] (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] -# start the video stream thread -print("[INFO] starting video stream thread...") +# start the video stream +print("[INFO] Press 'q' to quit the program.") vs = VideoStream(src=args["webcam"]).start() time.sleep(1.0) + # loop over frames from the video stream while True: - # grab the frame from the threaded video file stream, resize - # it, and convert it to grayscale - # channels) frame = vs.read() frame = imutils.resize(frame, width=450) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - # detect faces in the grayscale frame rects = detector(gray, 0) - # loop over the face detections for rect in rects: - # determine the facial landmarks for the face region, then - # convert the facial landmark (x, y)-coordinates to a NumPy - # array shape = predictor(gray, rect) shape = face_utils.shape_to_np(shape) - # extract the left and right eye coordinates, then use the - # coordinates to compute the eye aspect ratio for both eyes leftEye = shape[lStart:lEnd] rightEye = shape[rStart:rEnd] leftEAR = eye_aspect_ratio(leftEye) rightEAR = eye_aspect_ratio(rightEye) - # average the eye aspect ratio together for both eyes ear = (leftEAR + rightEAR) / 2.0 - # compute the convex hull for the left and right eye, then - # visualize each of the eyes leftEyeHull = cv2.convexHull(leftEye) rightEyeHull = cv2.convexHull(rightEye) cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1) cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1) - # check to see if the eye aspect ratio is below the blink - # threshold, and if so, increment the blink frame counter if ear < EYE_AR_THRESH: COUNTER += 1 - # if the eyes were closed for a sufficient number of - # then sound the alarm if COUNTER >= EYE_AR_CONSEC_FRAMES: - # if the alarm is not on, turn it on if not ALARM_ON: ALARM_ON = True - # check to see if an alarm file was supplied, - # and if so, start a thread to have the alarm - # sound played in the background if args["alarm"] != "": t = Thread(target=sound_alarm, args=(args["alarm"],)) t.deamon = True t.start() - # draw an alarm on the frame cv2.putText( frame, "DROWSINESS ALERT!", @@ -136,32 +94,26 @@ def eye_aspect_ratio(eye): (0, 0, 255), 2, ) - # otherwise, the eye aspect ratio is not below the blink - # threshold, so reset the counter and alarm else: COUNTER = 0 ALARM_ON = False - # draw the computed eye aspect ratio on the frame to help - # with debugging and setting the correct eye aspect ratio - # thresholds and frame counters - cv2.putText( - frame, - "EAR: {:.2f}".format(ear), - (300, 30), - cv2.FONT_HERSHEY_SIMPLEX, - 0.7, - (0, 0, 255), - 2, - ) - - # show the frame - cv2.imshow("Frame", frame) - key = cv2.waitKey(1) & 0xFF - - # if the `q` key was pressed, break from the loop - if key == ord("q"): - break -# do a bit of cleanup + cv2.putText( + frame, + "EAR: {:.2f}".format(ear), + (300, 30), + cv2.FONT_HERSHEY_SIMPLEX, + 0.7, + (0, 0, 255), + 2, + ) + + cv2.imshow("Frame", frame) + key = cv2.waitKey(1) & 0xFF + + if key == ord("q"): + break + +# cleanup cv2.destroyAllWindows() vs.stop()