Compare commits

...

4 Commits

Author SHA1 Message Date
cubernetes 6b06beac24 Highscore tracking 2023-08-11 03:14:21 +02:00
cubernetes aa2e9b27e1 Rename 2023-08-11 02:52:14 +02:00
cubernetes 15b53cd262 Let's see... 2023-08-11 02:49:49 +02:00
cubernetes b0d21d30a3 Hm, refactor necessary 2023-08-11 02:40:26 +02:00
7 changed files with 136 additions and 82 deletions

1
.score Normal file
View File

@ -0,0 +1 @@
168

Binary file not shown.

104
game.py
View File

@ -2,38 +2,12 @@
import sys
import random
from enum import Enum
from typing import NoReturn, Generator
from types import ModuleType
from subprocess import Popen
import numpy as np
import mediapipe as mp
import cv2
from cv2 import VideoCapture
class FingerType(Enum):
BASE = 0
BASE_RIGHT = 1
THUMB_BASE = 2
THUMB_KNUCKLE_1 = 3
THUMB_TIP = 4
INDEX_BASE = 5
INDEX_KNUCKLE_1 = 6
INDEX_KNUCKLE_2 = 7
INDEX_TIP = 8
MIDDLE_BASE = 9
MIDDLE_KNUCKLE_1 = 10
MIDDLE_KNUCKLE_2 = 11
MIDDLE_TIP = 12
RING_BASE = 13
RING_KNUCKLE_1 = 14
RING_KNUCKLE_2 = 15
RING_TIP = 16
PINKY_BASE = 17
PINKY_KNUCKLE_1 = 18
PINKY_KNUCKLE_2 = 19
PINKY_TIP = 20
from utils import *
def get_42_img(
img_path: str,
@ -64,10 +38,7 @@ def get_42_img(
return img
mp_hands = mp.solutions.hands
mp_draw: ModuleType = mp.solutions.drawing_utils
img42_side_len = 70
img42_side_len: int = 70
img42: np.ndarray = get_42_img(
"./assets/img/42.png",
margin_top = 100 + 20,
@ -94,17 +65,17 @@ def add_directional_triangle(
side_len: int,
stretch: float,
) -> tuple[int, int]:
dir_vector = np.array([
dir_vector: np.ndarray = np.array([
x1 - x2, y1 - y2
]).astype(np.float64)
# normalize
dir_vector /= np.linalg.norm(dir_vector)
triangle_height = side_len * (3**0.5) / 2
half_base = side_len / 2
triangle_height: float = side_len * (3**0.5) / 2
half_base: float = side_len / 2
perp_vector = np.array([-dir_vector[1], dir_vector[0]])
perp_vector: np.ndarray = np.array([-dir_vector[1], dir_vector[0]])
apex_vertex = (int(x1 + dir_vector[0] * triangle_height * 2/3 * stretch), int(y1 + dir_vector[1] * triangle_height * 2/3 * stretch))
left_vertex = (int(x1 - perp_vector[0] * half_base - dir_vector[0] * triangle_height/3),
@ -112,32 +83,11 @@ def add_directional_triangle(
right_vertex = (int(x1 + perp_vector[0] * half_base - dir_vector[0] * triangle_height/3),
int(y1 + perp_vector[1] * half_base - dir_vector[1] * triangle_height/3))
triangle = np.array([apex_vertex, left_vertex, right_vertex])
triangle: np.ndarray = np.array([apex_vertex, left_vertex, right_vertex])
cv2.drawContours(frame, [triangle], 0, rgb, -1)
return apex_vertex
def get_finger_positions(
frame: np.ndarray,
hands: mp.solutions.hands.Hands,
add_landmarks: bool,
) -> Generator[list[tuple[int, int, int]], None, None]:
height, width = frame.shape[:2]
img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(img_rgb)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
positions = []
for id, lm in enumerate(hand_landmarks.landmark):
x = int(lm.x * width)
y = int(lm.y * height)
positions.append((FingerType(id), x, y))
yield positions
if add_landmarks:
mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
if to_stdout:
sys.stdout.buffer.write(frame.tobytes())
@ -145,19 +95,18 @@ def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
cv2.imshow("Image", frame)
cv2.waitKey(1)
def collect_sfx() -> None:
Popen(['paplay', './assets/sfx/collect.mp3'])
def main() -> NoReturn:
Popen(['paplay', './assets/sfx/start.mp3'])
def main() -> int:
start_sfx()
capture: VideoCapture = cv2.VideoCapture(0)
hands = mp_hands.Hands(max_num_hands=2)
collected_42 = True
img42_x = -img42_side_len - 1
img42_y = -img42_side_len - 1
hands: mp.solutions.hands.Hands = mp_hands.Hands(max_num_hands=2)
collected_42: bool = True
img42_x: int = -img42_side_len - 1
img42_y: int = -img42_side_len - 1
no_fingers: int = 0
score: int = 0
i = 0
i: int = 0
while True:
success: bool
frame: np.ndarray
@ -176,7 +125,15 @@ def main() -> NoReturn:
img42_x : img42_x+img42_side_len,
] = img42
for positions in get_finger_positions(frame, hands, add_landmarks=True):
finger_positions = list(get_finger_positions(frame, hands, add_landmarks=True))
if finger_positions == []:
no_fingers += 1
else:
no_fingers = 0
if no_fingers > 70:
return score
for positions in finger_positions:
index_knuckle_1_pos: tuple[int, int] = (-1, -1)
for finger_id, finger_x, finger_y in positions:
if finger_id == FingerType.INDEX_KNUCKLE_2:
@ -191,12 +148,19 @@ def main() -> NoReturn:
side_len=70,
stretch=2.0,
)
if not collected_42 and touches_42(apex_x, apex_y, img42_x, img42_y):
if not collected_42 and (
touches_42(apex_x, apex_y, img42_x, img42_y)
or touches_42(finger_x, finger_y, img42_x, img42_y)
):
collected_42 = True
i = 0
score += 42
collect_sfx()
show_frame(frame, to_stdout=(not sys.stdout.isatty()))
i += 1
if __name__ == '__main__':
main()
score: int = main()
with open('./.score', 'w') as score_file:
score_file.write(str(score))
sys.exit(0)

20
master.py Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
from time import sleep
from typing import NoReturn
from utils import *
def start_game() -> None:
proc = Popen(['./start_game.sh'])
proc.communicate()
def main() -> NoReturn:
show_matrix()
while True:
if found_hands():
start_game()
sleep(1)
if __name__ == '__main__':
main()

View File

@ -4,18 +4,11 @@ import sys
from typing import NoReturn
def main() -> NoReturn:
x = 0
y = 0
while True:
chunk = sys.stdin.buffer.read(100)
if not chunk:
continue
nls = chunk.count(b'\n')
if nls != 0:
open('/dev/pts/1', 'w').write(
f'{nls}'
)
modified_chunk = chunk
modified_chunk = chunk.replace(b'X', b'.')
sys.stdout.buffer.write(modified_chunk)
sys.stdout.flush()

View File

@ -3,13 +3,14 @@
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray,hflip" -c:v libx265 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=caca --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray,hflip" -c:v libx264 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=tct --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
export TERM_FONT='SauceCodePro Nerd Font Mono'
export TERM_FONT_SIZE='10'
export OUT_TERM='xterm-mono'
TERM_FONT='SauceCodePro Nerd Font Mono'
TERM_FONT_SIZE='10'
OUT_TERM='xterm-mono'
# TERM_FULLSCREEN='-fullscreen'
xterm \
-bg black \
-fg white \
-s -fullscreen \
${TERM_FULLSCREEN} \
-fa "${TERM_FONT}" \
-fs "${TERM_FONT_SIZE}" \
-e '{

75
utils.py Normal file
View File

@ -0,0 +1,75 @@
from enum import Enum
from subprocess import Popen
from typing import Generator
from types import ModuleType
import numpy as np
import mediapipe as mp
import cv2
from cv2 import VideoCapture
mp_hands = mp.solutions.hands
mp_draw: ModuleType = mp.solutions.drawing_utils
class FingerType(Enum):
BASE = 0
BASE_RIGHT = 1
THUMB_BASE = 2
THUMB_KNUCKLE_1 = 3
THUMB_TIP = 4
INDEX_BASE = 5
INDEX_KNUCKLE_1 = 6
INDEX_KNUCKLE_2 = 7
INDEX_TIP = 8
MIDDLE_BASE = 9
MIDDLE_KNUCKLE_1 = 10
MIDDLE_KNUCKLE_2 = 11
MIDDLE_TIP = 12
RING_BASE = 13
RING_KNUCKLE_1 = 14
RING_KNUCKLE_2 = 15
RING_TIP = 16
PINKY_BASE = 17
PINKY_KNUCKLE_1 = 18
PINKY_KNUCKLE_2 = 19
PINKY_TIP = 20
def collect_sfx() -> None:
Popen(['paplay', './assets/sfx/collect.mp3'])
def start_sfx() -> None:
Popen(['paplay', './assets/sfx/start.mp3'])
def show_matrix() -> None:
Popen(['tmatrix'])
def found_hands() -> bool:
capture: VideoCapture = cv2.VideoCapture(0)
hands = mp_hands.Hands(max_num_hands=1)
success, frame = capture.read()
if not success:
return False
return list(get_finger_positions(frame, hands)) != []
def get_finger_positions(
frame: np.ndarray,
hands: mp.solutions.hands.Hands,
add_landmarks: bool=False,
) -> Generator[list[tuple[int, int, int]], None, None]:
height, width = frame.shape[:2]
img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(img_rgb)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
positions = []
for id, lm in enumerate(hand_landmarks.landmark):
x = int(lm.x * width)
y = int(lm.y * height)
positions.append((FingerType(id), x, y))
yield positions
if add_landmarks:
mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)