# data[].attributes.body
1. 아두이노 ide 파일 다운로드 및 설치

2. CH340 드라이버 설치

3. ultrasonic 파일 바탕화면에 다운받기

# data[].attributes.headline
1. 아두이노 ide 다운로드 파일

# data[].attributes.subject
1. 아두이노 ide 다운로드 파일

# data[].attributes.attachment_link.readable_text
Colab is a hosted Jupyter Notebook service that requires no setup to use and provides free access to computing resources, including GPUs and TPUs. Colab is especially well suited to machine learning, data science, and education.

# data[].attributes.attachment_link.description
Colab is a hosted Jupyter Notebook service that requires no setup to use and provides free access to computing resources, including GPUs and TPUs. Colab is especially well suited to machine learning, data science, and education.

# data[].attributes.attachment_link.description
빠르고 쉬운 폼빌더, 왈라

# data[].attributes.body
for i in range(2, 10):

print(f"[ {i}단 ]")

for j in range(1, 10):

print(f"{i} x {j} = {i * j}")

print()

# data[].attributes.body
for dan in range(2, 10):

for i in range(1, 10):

print(f"{dan}*{i}={dan*i}", end=', ' if not (dan 9 and i 9) else '\n')

# data[].attributes.body
for dan in range(2, 10):
    print(f"--- {dan}단 ---")
    for i in range(1, 10):
        result = dan * i
        print(f"{dan} x {i} = {result}")
    print()

# data[].attributes.body
import random

import time

import os

import sys

import threading

score = 0

time_limit = 30 # 전체 제한시간 30초

def clear():

os.system('cls' if os.name == 'nt' else 'clear')

def timer_end():

print("\n시간 종료! 게임 끝!")

sys.exit()

clear()

print("=== 구구단 30초 타임어택 ===")

print("30초 안에 최대한 많은 문제를 풀어라!")

print("맞출 때마다 +1점, 틀리면 -1점.\n")

name = input("이름 입력: ")

print("준비됐지? 엔터 누르면 시작한다.")

input()

clear()

# 타이머 스레드 시작

end_event = threading.Timer(time_limit, timer_end)

end_event.start()

start = time.time()

try:

while True:

a = random.randint(2, 9)

b = random.randint(1, 9)

answer = a * b

print(f"{a} x {b} = ? (현재 점수: {score})")

q_time = time.time()

try:

user_input = input("답: ")

except EOFError:

break

elapsed = time.time() - q_time

# 시간 확인

if time.time() - start > time_limit:

break

try:

if int(user_input) == answer:

score += 1

print(f"정답! +1점 / 현재 점수: {score}\n")

else:

score -= 1

print(f"틀림! 정답은 {answer} / 현재 점수: {score}\n")

except ValueError:

score -= 1

print(f"숫자 입력하라 했지. -1점 / 현재 점수: {score}\n")

time.sleep(0.5)

clear()

except KeyboardInterrupt:

pass

end_event.cancel()

clear()

print(f"\n=== 결과 ===")

print(f"도현({name}), 총점 {score}점")

if score >= 15:

print("You win, My son!")

elif score >= 10:

print("괜찮았어. 근성 보였어.")

else:

print("느렸어. 다시 훈련 들어가자.")

# data[].attributes.body
for i in range(1, 10):
    for j in range(2, 10):
        print(f"{j} x {i} = {j*i:2d}", end="\t")
    print()

# data[].attributes.body
import random

import time

import threading

import sys

import os

score = 0

goal = 15

time_limit = 5

ranking_file = "ranking.txt"

def clear():

os.system('cls' if os.name == 'nt' else 'clear')

def load_best():

if not os.path.exists(ranking_file):

return ("없음", 0)

with open(ranking_file, "r", encoding="utf-8") as f:

line = f.readline().strip().split(',')

if len(line) == 2:

return (line[0], int(line[1]))

return ("없음", 0)

def save_best(name, score):

with open(ranking_file, "w", encoding="utf-8") as f:

f.write(f"{name},{score}")

def countdown(limit, stop_event):

for i in range(limit, 0, -1):

if stop_event.is_set():

return

sys.stdout.write(f"\r남은 시간: {i}초 | 현재 점수: {score}")

sys.stdout.flush()

time.sleep(1)

print("\r시간 초과! ")

# 게임 시작

clear()

print("=== 구구단 스피드 챌린지 ===")

print("5초 안에 답하라. 2초마다 1점씩 깎인다.")

print("15점 도달 시 승리.\n")

name = input("이름 입력: ")

best_name, best_score = load_best()

print(f"현재 최고 기록: {best_name} ({best_score}점)\n")

time.sleep(1)

clear()

while score < goal:

# 난이도 조정

if score >= 10:

time_limit = 3

elif score >= 5:

time_limit = 4

else:

time_limit = 5

a = random.randint(2, 9 + score // 5)

b = random.randint(1, 9 + score // 5)

answer = a * b

print(f"\n문제: {a} x {b} = ?")

stop_event = threading.Event()

timer = threading.Thread(target=countdown, args=(time_limit, stop_event))

timer.start()

start = time.time()

try:

user_input = input("\n답: ")

stop_event.set()

elapsed = time.time() - start

if elapsed > time_limit:

print("느려! 시간 초과. -1점")

score -= 1

elif int(user_input) == answer:

score += 1

print(f"정답! +1점 / 현재 점수: {score}")

else:

print(f"틀림! 정답은 {answer}. -1점")

score -= 1

except ValueError:

stop_event.set()

print("숫자만 입력하라고 했지. -1점")

score -= 1

# 시간 경과로 감점

score -= int(elapsed // 2)

if score < 0:

score = 0

print(f"현재 점수: {score}")

time.sleep(1)

clear()

print(f"\n총점 {score}점 달성! You win, My son!")

# 최고점 갱신 확인

if score > best_score:

print(f"신기록 달성! {best_score}점 → {score}점")

save_best(name, score)

else:

print(f"기록 미달. 최고점 {best_name}({best_score}점) 유지.")

# data[].attributes.body
for dan in range(2, 10):
    print(f"{dan}")
    print("=" * 15)

    for num in range(1, 10):
        result = dan * num
        print(f"{dan} x {num} = {result}")

    print("=" * 15)
    print(f"{dan}")

print()

# data[].attributes.body
import random

print("구구단 퀴즈 게임! 3단부터 15단까지 문제를 맞춰보세요.")

num_questions = int(input("몇 문제를 풀고 싶나요? "))

score = 0

for in range(numquestions):

dan = random.randint(3, 15)

i = random.randint(1, 9)

answer = dan * i

while True:

try:

user_answer = int(input(f"{dan} * {i} = ? "))

break

except ValueError:

print("숫자를 입력해주세요!")

if user_answer == answer:

print("정답입니다! 🎉")

score += 1

else:

print(f"틀렸어요. 정답은 {answer}입니다.")

print(f"게임 종료! 총 {num_questions}문제 중 {score}문제를 맞혔습니다.")

# data[].attributes.body
print("🚨🚨🚨 긴급 상황 발생! 🚨🚨🚨")
    print("당신은 전 세계의 평화를 지킬 유일한 '구구단 폭탄 해체 전문가'입니다!")
    print("눈앞의 시한폭탄은 굉음을 내며 타이머가 돌아가고 있어요... 틱톡틱톡! 🤫")
    print("폭탄에는 여러 개의 암호 전선이 연결되어 있습니다. 각 전선에 걸린 구구단 문제를 풀어 해체해야 합니다.")
    print("단, 단 하나의 오답도 허용되지 않습니다! 실수하는 순간... BOOM! 💥")
    print("\n심호흡 크게 하고... 준비가 되면 엔터를 눌러주세요!")
    input()

    num_wires = 7

    wires_defused = 0

    print("\n--- 폭탄 해체 시작! ---")
    start_time = time.time()

    while wires_defused < num_wires:
        print(f"\n[ 남은 전선: {num_wires - wires_defused}개 ]")

        dan = random.randint(2, 9)
        i = random.randint(1, 9)

        correct_answer = dan * i

        user_input_valid = False
        user_answer = 0

        while not user_input_valid:
            user_answer_str = input(f"전선 #{wires_defused + 1}: {dan} x {i} = ? 정답 입력 👉 ")

            try:
                user_answer = int(user_answer_str)
                user_input_valid = True
            except ValueError:
                print("🚨 경고: 숫자로만 입력해야 해요! 침착하세요! 🚨")

        if user_answer == correct_answer:
            print("⚡️ '찌이이이익!' 전선 해체 성공! 퓨즈가 꺼졌습니다! ⚡️")
            wires_defused += 1
        else:
            print("\n💥🚨💣 BOOOOOOM!!!! 💣🚨💥")
            print(f"오답입니다! 정답은 {correct_answer} 이었어요...")
            print("당신의 손이 미끄러지는 순간, 폭탄이 폭발했습니다. 임무 실패. 😵")
            return

    end_time = time.time()
    time_taken = end_time - start_time

    print("\n✨🎉🎊 축하합니다! 🎊🎉✨")
    print("모든 전선을 성공적으로 해체했습니다! 당신 덕분에 세계가 평화를 되찾았습니다!")
    print(f"놀라운 실력으로 {time_taken:.2f}초 만에 폭탄을 해체했습니다!")
    print("당신은 진정한 '구구단 폭탄 해체 마스터' 입니다! 👍")

play_bomb_defusal_game()

print("\n--- 게임 종료 ---")

# data[].attributes.body
# 구구단 퀴즈 프로그램
# 파이썬 3.6 이상에서 실행하세요

import random   # 무작위(랜덤) 숫자를 만들기 위해 random 모듈을 불러옵니다

def make_question(min_dan=2, max_dan=30):
    """2개 숫자를 무작위로 만들어 (a, b) 형태로 반환합니다 (기본: 2~30단)."""
    a = random.randint(min_dan, max_dan)  # min_dan 이상 max_dan 이하 정수 중 하나 선택
    b = random.randint(1, 30)              # 1~30 사이의 정수 중 하나 선택
    return a, b

def ask_quiz(num_questions=10):
    """num_questions 만큼 문제를 내고 채점한 뒤 결과를 출력합니다."""
    score = 0
    for i in range(1, num_questions + 1):        # 1부터 num_questions까지 반복
        a, b = make_question()                   # 문제 만들기
        correct = a * b                          # 정답 계산
        while True:                              # 사용자 입력을 안정적으로 받기 위한 반복
            user = input(f"[문제 {i}] {a} × {b} = ? (끝내려면 q 입력) ")  # 사용자에게 문제와 안내 출력
            if user.lower() == 'q':              # 'q' 또는 'Q' 입력이면 종료
                print("퀴즈를 종료합니다.")
                return score, i - 1               # 현재까지 맞춘 점수와 푼 문제 수 반환
            try:
                user_ans = int(user)             # 입력 문자열을 정수(int)로 변환 시도
            except ValueError:
                print("숫자를 입력하세요 (또는 q로 종료).")
                continue                         # 변환 실패하면 다시 입력받기
            if user_ans == correct:
                print("정답입니다!\n")
                score += 1
            else:
                print(f"아쉽습니다. 정답은 {correct}입니다.\n")
            break                                # 한 문제 끝나면 다음 문제로
    return score, num_questions

def main():
    print("=== 구구단 퀴즈 ===")
    # 사용자로부터 문제 수 입력 받기
    while True:
        n = input("몇 문제를 풀겠습니까? 기본 10문제 (숫자만 입력, 종료는 q): ")
        if n.lower() == 'q':
            print("프로그램을 종료합니다.")
            return
        try:
            n = int(n)
            if n <= 0:
                print("양수(1 이상의 정수)를 입력하세요.")
                continue
            break
        except ValueError:
            print("숫자만 입력하세요.")
    score, total = ask_quiz(n)
    # 결과 출력
    print(f"\n총 {total}문제 중 {score}문제 맞혔습니다.")
    if total > 0:
        percent = score / total * 100
        print(f"정확도: {percent:.1f}%입니다.")
    print("수고하셨습니다!")

if __name__ == "__main__":
    main()

# data[].attributes.body
import random

import time

score = 0

combo = 0 # 연속 정답 횟수

start_time = time.time()

game_duration = 60 # 게임 전체 시간 (초)

print("🧮 타임어택 구구단 게임 시작!")

print("60초 동안 최대한 많이 맞혀보세요!")

print("연속 정답 보너스와 랜덤 이벤트가 있습니다!\n")

time.sleep(1)

while True:

elapsed = time.time() - start_time

if elapsed >= game_duration:

print("\n⏰ 시간이 끝났습니다!")

break

# 문제 생성

a = random.randint(1, 9)

b = random.randint(1, 9)

answer = a * b

# 구분선 출력

print("\n" + "="*30)

print(f"🕒 남은 시간: {int(game_duration - elapsed)}초 | 💯 점수: {score} | 연속 정답: {combo}")

print(f"문제: {a} x {b} = ?")

user_input = input("정답: ").strip()

if not user_input:

print("⚠️ 입력 없음! -80점")

score -= 80

combo = 0

else:

try:

user_answer = int(user_input)

if user_answer == answer:

combo += 1

bonus = 0

if combo == 2:

bonus = 50

print("🔥 연속 2회 정답! 보너스 50점!")

elif combo >= 3:

bonus = 100

print("🔥 연속 3회 이상! 보너스 100점!")

# 랜덤 이벤트 (10% 확률)

if random.random() < 0.1:

print("⏱️ 랜덤 이벤트! 시간 +2초!")

start_time -= 2 # 남은 시간 증가

score += 100 + bonus

print(f"✅ 정답! +{100 + bonus}점")

else:

print(f"❌ 오답! 정답: {answer} (-80점)")

score -= 80

combo = 0

except ValueError:

print("⚠️ 숫자만 입력! -80점")

score -= 80

combo = 0

# 점수 최소값 0으로 제한

score = max(score, 0)

time.sleep(0.5) # 잠깐 쉬면서 메시지 확인

# 게임 종료

print("\n" + "🎯" * 10)

print(f"최종 점수: {score}점")

print("게임 종료 🎮")

print("🎯" * 10)

# data[].attributes.body
# 저는 파이썬 프로그램입니다.

# 2단부터 9단까지의 구구단을 출력하겠습니다.

# 'dan'은 구구단의 각 '단'을 의미합니다.

# range(2, 10)은 숫자 2부터 9까지 (10은 포함하지 않습니다)를 순서대로 사용하겠다는 의미입니다.

for dan in range(2, 10):

# 현재 어떤 단을 출력하는지 명확히 보여주는 헤더입니다.

print(f"--- {dan} 단 ---")

# 'i'는 각 단에서 1부터 9까지 곱해지는 숫자를 의미합니다.

# range(1, 10)은 숫자 1부터 9까지 (10은 포함하지 않습니다)를 순서대로 사용합니다.

for i in range(1, 10):

# 현재의 'dan'과 'i'를 곱한 결과를 계산합니다.

result = dan * i

# 계산 결과를 '단 x 곱하는 수 = 결과' 형식으로 깔끔하게 출력합니다.

print(f"{dan} x {i} = {result}")

# 각 단의 출력이 완료되면 한 줄을 띄어서 다음 단과 구분을 명확히 합니다.

print() # 빈 줄을 출력합니다.

# data[].attributes.body
import random # 구구단 문제를 무작위로 내기 위해 random 모듈을 가져옵니다.

# 2인용 틱택토 게임 (구구단 맞히기 버전)

def print_board(board):
    # 보드 출력 함수 (이전과 동일)
    print("\n")
    print(f" {board[0][0]} | {board[0][1]} | {board[0][2]} ")
    print("---+---+---")
    print(f" {board[1][0]} | {board[1][1]} | {board[1][2]} ")
    print("---+---+---")
    print(f" {board[2][0]} | {board[2][1]} | {board[2][2]} ")
    print("\n")

def check_win(board, player):
    # 승리 조건 확인 함수 (이전과 동일)
    # 가로 확인
    for row in range(3):
        if board[row][0] == board[row][1] == board[row][2] == player:
            return True

    # 세로 확인
    for col in range(3):
        if board[0][col] == board[1][col] == board[2][col] == player:
            return True

    # 대각선 확인
    if board[0][0] == board[1][1] == board[2][2] == player:
        return True
    if board[0][2] == board[1][1] == board[2][0] == player:
        return True

    return False

def is_board_full(board):
    # 보드가 가득 찼는지 확인하는 함수 (이전과 동일)
    for row in range(3):
        for col in range(3):
            if board[row][col] == ' ':
                return False
    return True

def ask_multiplication_question():
    # 구구단 문제를 내고 정답 여부를 반환하는 함수 (새로운 추가 기능!)
    dan = random.randint(2, 9) # 2단부터 9단까지 무작위로 선택
    num = random.randint(1, 9) # 1부터 9까지 무작위로 곱할 숫자 선택
    correct_answer = dan * num

    print(f"문제: {dan} X {num} = ?")

    try:
        user_answer = int(input("정답을 입력하세요: "))
        if user_answer == correct_answer:
            print("🎉 정답입니다! 말을 놓을 수 있어요!")
            return True # 정답이면 True 반환
        else:
            print(f"앗! 틀렸어요. 정답은 {correct_answer}입니다. 이번 턴에는 말을 놓을 수 없어요. (다음 턴에 다시 도전!)")
            return False # 틀리면 False 반환
    except ValueError:
        print("숫자를 입력해주세요. 이번 턴에는 말을 놓을 수 없어요. (다음 턴에 다시 도전!)")
        return False # 숫자 입력 오류 시 False 반환

def main():
    # 게임 보드 초기화
    board = [[' ' for _ in range(3)] for _ in range(3)]

    # 현재 플레이어 (X부터 시작)
    current_player = 'X'

    # 게임 진행 상태
    game_over = False

    # 게임 시작 메시지
    print("수학 틱택토 게임을 시작합니다! (2인용)")
    print("먼저 구구단 문제를 맞혀야 말을 놓을 수 있어요!")
    print("좌표는 1-3 사이의 숫자로 입력하세요. (예: 1 2)")

    # 게임 메인 루프
    while not game_over:
        print_board(board)
        print(f"플레이어 {current_player}의 차례입니다.")

        # 🎲 구구단 문제 내기! 🎲
        is_math_correct = ask_multiplication_question()

        if not is_math_correct:
            # 구구단을 틀렸다면, 바로 다음 플레이어로 턴을 넘깁니다.
            current_player = 'O' if current_player == 'X' else 'X'
            continue # 이번 턴은 여기서 끝내고 다음 루프로 넘어갑니다.

        # 구구단을 맞혔다면, 말을 놓을 위치를 입력받습니다.
        valid_move = False
        while not valid_move:
            try:
                row, col = map(int, input("어디에 말을 놓을까요? 행과 열을 입력하세요 (1-3): ").split())

                # 1-3 입력을 0-2 인덱스로 변환
                row -= 1
                col -= 1

                # 유효한 위치인지 확인
                if row < 0 or row > 2 or col < 0 or col > 2:
                    print("1부터 3까지의 숫자만 입력해주세요!")
                    continue

                # 이미 돌이 놓인 위치인지 확인
                if board[row][col] != ' ':
                    print("이미 돌이 놓인 자리입니다. 다른 위치를 선택하세요.")
                    continue

                # 유효한 입력이면 보드에 표시
                board[row][col] = current_player
                valid_move = True

            except ValueError:
                print("올바른 형식으로 입력해주세요. (예: 1 2)")

        # 승리 확인
        if check_win(board, current_player):
            print_board(board)
            print(f"플레이어 {current_player}가 이겼습니다! 축하합니다! 🎉")
            game_over = True

        # 무승부 확인
        elif is_board_full(board):
            print_board(board)
            print("보드가 가득 찼습니다. 무승부입니다! 😅")
            game_over = True

        # 플레이어 전환 (X -> O 또는 O -> X)
        else:
            current_player = 'O' if current_player == 'X' else 'X'

    # 게임 종료 메시지
    print("게임이 종료되었습니다. 다시 하려면 프로그램을 재실행하세요.")

# 게임 실행
if __name__ == "__main__":
    main()

# data[].attributes.body
# 파이썬으로 만든 7x7 오목 게임

def create_board(size=7):
    """size x size 크기의 빈 오목판을 생성합니다."""
    return [[' ' for _ in range(size)] for _ in range(size)]

def print_board(board):
    """오목판 상태를 출력합니다."""
    size = len(board)
    # 열 번호 출력 (1부터 시작)
    print('   ' + ' '.join([f"{i+1}" for i in range(size)]))

    # 각 행과 돌 출력
    for i in range(size):
        print(f"{i+1} |", end='')
        for j in range(size):
            print(f"{board[i][j]}|", end='')
        print("")
    print("")  # 보드 아래 빈 줄 추가

def is_valid_move(board, row, col):
    """입력한 위치가 유효한지 확인합니다."""
    size = len(board)
    # 범위 내에 있고 빈 자리인지 확인
    return 0 <= row < size and 0 <= col < size and board[row][col] == ' '

def check_win(board, row, col, stone):
    """승리 조건을 확인합니다. (가로, 세로, 대각선에 5개 연속 돌)"""
    size = len(board)
    directions = [
        [(0, 1), (0, -1)],  # 가로 방향
        [(1, 0), (-1, 0)],  # 세로 방향
        [(1, 1), (-1, -1)], # 대각선 방향 (↘↖)
        [(1, -1), (-1, 1)]  # 대각선 방향 (↙↗)
    ]

    for dir_pair in directions:
        count = 1  # 현재 돌 포함

        # 각 방향 쌍에 대해 확인
        for dx, dy in dir_pair:
            nx, ny = row, col

            # 해당 방향으로 연속된 같은 돌 개수 세기
            for _ in range(4):  # 최대 4번 더 확인 (현재 돌 포함 5개)
                nx += dx
                ny += dy
                if 0 <= nx < size and 0 <= ny < size and board[nx][ny] == stone:
                    count += 1
                else:
                    break

        # 5개 연속이면 승리
        if count >= 5:
            return True

    return False

def main():
    """오목 게임 메인 함수"""
    # 게임 소개
    print("===== 7x7 미니 오목 게임 =====")
    print("두 명의 플레이어가 번갈아가며 돌을 놓습니다.")
    print("● (검은 돌)과 ○ (흰 돌)을 번갈아 놓으며 5개 연속으로 놓는 플레이어가 승리합니다.")
    print("좌표는 '행 열' 형태로 입력하세요. (예: '3 4')")
    print("========================")

    # 7x7 오목판 생성
    board_size = 7
    board = create_board(board_size)

    # 현재 플레이어 (흑돌 먼저 시작)
    current_player = '●'

    # 게임 루프
    while True:
        # 현재 오목판 출력
        print_board(board)

        # 현재 플레이어 표시
        player_name = "흑돌(●)" if current_player == '●' else "백돌(○)"
        print(f"\n{player_name}의 차례입니다.")

        try:
            # 좌표 입력 받기 (1부터 시작하는 인덱스)
            row, col = map(int, input("돌을 놓을 위치를 입력하세요 (행 열): ").split())

            # 1부터 시작하는 입력을 0부터 시작하는 인덱스로 변환
            row -= 1
            col -= 1

            # 유효한 위치인지 확인
            if not is_valid_move(board, row, col):
                print("유효하지 않은 위치입니다. 다시 입력해주세요.")
                continue

            # 돌 놓기
            board[row][col] = current_player

            # 승리 조건 확인
            if check_win(board, row, col, current_player):
                print_board(board)
                print(f"\n축하합니다! {player_name}이 이겼습니다! 🎉")
                break

            # 무승부 확인 (보드가 가득 찼는지)
            is_full = True
            for i in range(board_size):
                for j in range(board_size):
                    if board[i][j] == ' ':
                        is_full = False
                        break
                if not is_full:
                    break

            if is_full:
                print_board(board)
                print("\n보드가 가득 찼습니다. 무승부입니다!")
                break

            # 플레이어 전환
            current_player = '○' if current_player == '●' else '●'

        except ValueError:
            print("올바른 형식으로 입력해주세요. (예: '3 4')")
        except IndexError:
            print(f"1부터 {board_size}까지의 숫자만 입력해주세요.")

    print("\n게임이 종료되었습니다. 다시 하려면 프로그램을 재실행하세요.")

# 게임 실행
if __name__ == "__main__":
    main()

# data[].attributes.body
import random # 무작위 숫자를 위해

import time # 시간 측정을 위해

# --- 전역 변수 설정 ---

current_score = 0 # 사용자님의 현재 점수

num_questions = 20 # 총 낼 곱셈 문제의 개수 (20개로 변경되었습니다!)

time_limit_per_question = 10 # 한 문제당 제한 시간 (초)

winning_score_threshold = 100 # 게임 승리 조건 점수

ox_quiz_trigger_score = 50 # OX 퀴즈가 발동하는 점수

# --- 게임 상태 플래그 ---

game_won = False # 게임 승리 여부

ox_quiz_triggered = False # OX 퀴즈가 이미 발동되었는지 여부

# --- OX 퀴즈 함수 정의 ---

def run_ox_quiz(current_score_param):

global game_won # OX 퀴즈 내에서도 게임 승리 여부를 변경할 수 있도록 global 선언

print("\n----------------------------------------")

print(" 🎉 축하합니다! 50점 달성! 🎉 ")

print(" ✨ 보너스 OX 퀴즈를 시작합니다! ✨ ")

print("----------------------------------------\n")

ox_questions_to_ask = 3 # OX 퀴즈 문제 개수

for ox_q_num in range(1, ox_questions_to_ask + 1):

if game_won: # OX 퀴즈 중에도 100점 달성 시 즉시 종료

break

dan = random.randint(2, 9)

multiplier = random.randint(1, 9)

correct_result = dan * multiplier

# 50% 확률로 오답을 제시합니다.

if random.random() < 0.5: # 0.0 이상 1.0 미만의 랜덤 실수

# 오답을 만듭니다. (정답에서 1이나 2를 더하거나 빼서)

incorrect_result = correct_result + random.choice([-2, -1, 1, 2])

# 다만, incorrect_result가 음수가 되지 않도록 최소 1 이상으로 조정

if incorrect_result < 1: incorrect_result = correct_result + 1

proposed_answer = incorrect_result

is_correct_statement = False # "이게 맞아?"라는 질문에 대한 실제 정답 여부

else:

proposed_answer = correct_result

is_correct_statement = True

print(f"--- OX 퀴즈 {ox_q_num}번째 문제 ---")

user_ox_input = input(f"{dan} x {multiplier} = {proposed_answer} 이(가) 맞습니까? (O/X) (현재 점수: {current_score_param}점) ").strip().upper()

# 사용자 입력 처리

if (user_ox_input == 'O' and is_correct_statement) or \

(user_ox_input == 'X' and not is_correct_statement):

current_score_param += 10

print("딩동댕! 정답입니다! 🥳 +10점!")

elif (user_ox_input == 'O' and not is_correct_statement) or \

(user_ox_input == 'X' and is_correct_statement):

current_score_param -= 10

print(f"땡! 오답입니다. 🥲 정답은 {'O' if is_correct_statement else 'X'} 였습니다. -10점!")

else:

current_score_param -= 10

print("잘못된 입력입니다. 'O' 또는 'X'를 입력해주세요! -10점!")

print(f"OX 퀴즈 후 현재 점수는 {current_score_param}점입니다.\n")

# OX 퀴즈 도중에도 100점 달성 확인

if current_score_param >= winning_score_threshold:

game_won = True

break # OX 퀴즈 중단

return current_score_param # 변경된 점수를 반환합니다.

# --- 게임 시작 메시지 ---

print("************************************************")

print("* 환영합니다! 구구단 곱셈 시간 제한 게임! *")

print("************************************************")

print(f"\n총 {num_questions}문제가 출제됩니다. 각 문제는 {time_limit_per_question}초 안에 풀어야 합니다.")

print(f"맞히면 +10점, 틀리거나 시간을 초과하면 -10점입니다.")

print(f"** {winning_score_threshold}점 이상을 획득하면 즉시 게임에서 승리합니다! **")

print(f"** {ox_quiz_trigger_score}점 이상 달성 시 보너스 OX 퀴즈가 시작됩니다! **\n")

# --- 메인 게임 루프 ---

for question_count in range(1, num_questions + 1):

# 게임 승리 또는 OX 퀴즈 발동으로 게임이 중단되어야 한다면 반복문을 나갑니다.

if game_won:

break

# 50점 이상이면서 OX 퀴즈가 아직 발동되지 않았다면

if not ox_quiz_triggered and current_score >= ox_quiz_trigger_score:

ox_quiz_triggered = True # OX 퀴즈 발동 플래그를 True로 설정

current_score = run_ox_quiz(current_score) # OX 퀴즈 실행 후 점수 업데이트

if game_won: # OX 퀴즈에서 승리 조건을 달성했다면 메인 루프도 종료

break

print("\n--- 일반 곱셈 문제로 돌아갑니다 ---\n")

# 2단부터 9단까지 중 무작위로 '단'을 선택합니다.

dan = random.randint(2, 9)

# 1부터 9까지 중 무작위로 곱할 숫자를 선택합니다.

multiplier = random.randint(1, 9)

# 올바른 정답을 계산합니다.

correct_answer = dan * multiplier

print(f"--- {question_count}번째 문제 ---")

print(f"제한 시간: {time_limit_per_question}초")

# 질문 시작 시간 기록

start_time = time.time()

# 사용자에게 문제를 내고 답을 입력받습니다.

user_input = input(f"{dan} 곱하기 {multiplier}는 얼마일까요? (현재 점수: {current_score}점) ").strip()

# 질문 종료 시간 기록

end_time = time.time()

# 답 입력까지 걸린 시간 계산 (사용자가 Enter를 누른 시점까지)

time_taken = end_time - start_time

# 시간 제한 초과 여부 확인

if time_taken > time_limit_per_question:

current_score -= 10

print(f"시간 초과! ⏱️ {time_limit_per_question}초 안에 답하지 못했습니다. 정답은 {correct_answer}였습니다. 😢 -10점을 잃으셨습니다.")

else:

try:

# 입력받은 문자열을 정수(숫자)로 변환합니다.

user_answer = int(user_input)

# 사용자 입력과 정답을 비교하여 점수를 업데이트합니다.

if user_answer == correct_answer:

current_score += 10 # 정답이면 10점 추가

print(f"정답입니다! 👏 ({time_taken:.2f}초 소요) +10점을 획득하셨습니다.")

else:

current_score -= 10 # 오답이면 10점 감점

print(f"아쉽습니다! 정답은 {correct_answer}였습니다. 😢 -10점을 잃으셨습니다.")

except ValueError:

# 사용자가 숫자가 아닌 다른 것을 입력했을 때의 예외 처리입니다.

current_score -= 10 # 숫자가 아니므로 -10점 처리합니다.

print("에러: 숫자를 입력해 주세요! 이 문제는 틀린 것으로 간주하여 -10점 처리됩니다. 🚫")

print(f"현재 점수는 {current_score}점입니다.\n")

print("----------------------------------------\n")

# 매번 점수 업데이트 후 승리 조건을 확인합니다.

if current_score >= winning_score_threshold:

game_won = True

break # 100점 이상이므로 반복문을 즉시 종료합니다.

# --- 게임 종료 메시지 ---

print("========== 게임이 종료되었습니다! ==========")

if game_won:

print(f"✨ 축하합니다! 최종 점수 {current_score}점으로 {winning_score_threshold}점 이상을 달성하여 게임에서 승리하셨습니다! 🏆")

else:

print(f"최종 점수는 {current_score}점입니다. 다음 기회에 더 좋은 결과를 기대합니다! 😊")

# data[].attributes.body
import random # 구구단 문제를 무작위로 내기 위해 random 모듈을 가져옵니다.

# 파이썬으로 만든 5x5 구구단 오목 게임

def create_board(size=5):
    """size x size 크기의 빈 오목판을 생성합니다."""
    return [[' ' for _ in range(size)] for _ in range(size)]

def print_board(board):
    """오목판 상태를 출력합니다."""
    size = len(board)
    # 열 번호 출력 (1부터 시작)
    print('   ' + ' '.join([f"{i+1}" for i in range(size)]))

    # 각 행과 돌 출력
    for i in range(size):
        print(f"{i+1} |", end='')
        for j in range(size):
            print(f"{board[i][j]}|", end='')
        print("")
    print("")  # 보드 아래 빈 줄 추가

def is_valid_move(board, row, col):
    """입력한 위치가 유효한지 확인합니다."""
    size = len(board)
    # 범위 내에 있고 빈 자리인지 확인
    return 0 <= row < size and 0 <= col < size and board[row][col] == ' '

def check_win(board, row, col, stone):
    """승리 조건을 확인합니다. (5x5 보드에서는 4개 연속으로 수정)"""
    size = len(board)
    directions = [
        [(0, 1), (0, -1)],  # 가로 방향
        [(1, 0), (-1, 0)],  # 세로 방향
        [(1, 1), (-1, -1)], # 대각선 방향 (↘↖)
        [(1, -1), (-1, 1)]  # 대각선 방향 (↙↗)
    ]

    for dir_pair in directions:
        count = 1  # 현재 돌 포함

        # 각 방향 쌍에 대해 확인
        for dx, dy in dir_pair:
            nx, ny = row, col

            # 해당 방향으로 연속된 같은 돌 개수 세기
            for _ in range(3):  # 최대 3번 더 확인 (현재 돌 포함 4개)
                nx += dx
                ny += dy
                if 0 <= nx < size and 0 <= ny < size and board[nx][ny] == stone:
                    count += 1
                else:
                    break

        # 4개 연속이면 승리 (5x5 보드에 맞게 승리 조건 조정)
        if count >= 4:
            return True

    return False

def is_board_full(board):
    """보드가 가득 찼는지 확인합니다."""
    for row_list in board: # 'row' 대신 'row_list'로 변수명 변경 (중복 피함)
        for cell in row_list:
            if cell == ' ':
                return False
    return True

def ask_multiplication_question():
    """구구단 문제를 내고 정답 여부를 반환하는 함수."""
    dan = random.randint(2, 9) # 2단부터 9단까지 무작위로 선택
    num = random.randint(1, 9) # 1부터 9까지 무작위로 곱할 숫자 선택
    correct_answer = dan * num

    print(f"\n===== 구구단 문제 =====")
    print(f"문제: {dan} X {num} = ?")
    print("========================")

    try:
        user_answer = int(input("정답을 입력하세요: "))
        if user_answer == correct_answer:
            print("🎉 정답입니다! 이제 돌을 놓을 수 있어요!")
            return True # 정답이면 True 반환
        else:
            print(f"앗! 틀렸어요. 정답은 {correct_answer}입니다. 이번 턴에는 돌을 놓을 수 없어요. ㅠㅠ (다음 턴에 다시 도전!)")
            return False # 틀리면 False 반환
    except ValueError:
        print("숫자를 입력해주세요. 이번 턴에는 돌을 놓을 수 없어요. (다음 턴에 다시 도전!)")
        return False # 숫자 입력 오류 시 False 반환

def main():
    """오목 게임 메인 함수"""
    # 게임 소개
    print("===== 5x5 구구단 미니 오목 게임 =====")
    print("두 명의 플레이어가 번갈아가며 돌을 놓습니다.")
    print("● (검은 돌)과 ○ (흰 돌)을 번갈아 놓으며 4개 연속으로 놓는 플레이어가 승리합니다.")
    print("**주의: 돌을 놓기 전에 구구단 문제를 먼저 맞혀야 합니다!**")
    print("좌표는 '행 열' 형태로 입력하세요. (예: '3 2')")
    print("================================")

    # 5x5 오목판 생성
    board_size = 5
    board = create_board(board_size)

    # 현재 플레이어 (흑돌 먼저 시작)
    current_player = '●'

    # 게임 루프
    while True:
        # 현재 오목판 출력
        print_board(board)

        # 현재 플레이어 표시
        player_name = "흑돌(●)" if current_player == '●' else "백돌(○)"
        print(f"\n>>> {player_name}의 차례입니다. <<<")

        # 🎲 구구단 문제 내기! 🎲
        is_math_correct = ask_multiplication_question()

        if not is_math_correct:
            # 구구단 문제를 틀렸다면, 바로 다음 플레이어에게 턴을 넘깁니다.
            print(f"{player_name}이(가) 구구단 문제를 틀려 돌을 놓을 수 없습니다. 다음 턴으로 넘어갑니다.")
            current_player = '○' if current_player == '●' else '●' # 플레이어 전환
            continue # 이번 턴은 여기서 끝내고 다음 루프로 넘어갑니다.

        # 구구단을 맞혔다면, 말을 놓을 위치를 입력받습니다.
        valid_move = False
        while not valid_move:
            try:
                # 좌표 입력 받기 (1부터 시작하는 인덱스)
                row, col = map(int, input(f"어디에 돌을 놓을까요? ({player_name}) 행 열 입력: ").split())

                # 1부터 시작하는 입력을 0부터 시작하는 인덱스로 변환
                row -= 1
                col -= 1

                # 유효한 위치인지 확인
                if not is_valid_move(board, row, col):
                    print("유효하지 않은 위치입니다 (범위를 벗어나거나 이미 돌이 있습니다). 다시 입력해주세요.")
                    continue

                # 유효한 입력이면 보드에 표시
                board[row][col] = current_player
                valid_move = True # 유효한 움직임이므로 반복문 탈출

            except ValueError:
                print("올바른 형식으로 입력해주세요. (예: '3 2')")
            except IndexError:
                print(f"1부터 {board_size}까지의 숫자만 입력해주세요.")

        # 승리 조건 확인
        if check_win(board, row, col, current_player):
            print_board(board)
            print(f"\n축하합니다! {player_name}이 이겼습니다! 🎉")
            break

        # 무승부 확인 (보드가 가득 찼는지)
        if is_board_full(board):
            print_board(board)
            print("\n보드가 가득 찼습니다. 무승부입니다!")
            break

        # 플레이어 전환
        current_player = '○' if current_player == '●' else '●'

    print("\n게임이 종료되었습니다. 다시 하려면 프로그램을 재실행하세요.")

# 게임 실행
if __name__ == "__main__":
    main()

# data[].attributes.body
# 구구단 2단부터 9단까지 출력하는 프로그램

# range(2, 10)은 2부터 9까지 반복됨

for i in range(2, 10):

print(f"--- {i}단 ---") # 각 단의 제목 출력

# 각 단에서 1부터 9까지 곱하기

for j in range(1, 10):

print(f"{i} x {j} = {i * j}") # 결과 출력

print() # 한 단이 끝날 때 줄바꿈 (보기 좋게)

# data[].attributes.headline
아두이노 실습용 ppt

# data[].attributes.subject
아두이노 실습용 ppt

# data[].attributes.attachment_link.title
아두이노 실습용 ppt

# data[].attributes.body
좋아요 😎
그럼 지금 말한 “보안 경보 시스템(Security Alarm System)”을 초보자도 이해하기 쉽게 자세히 설명해줄게요.

1️⃣ 장치 구성

🔹 사용 부품

부품역할초음파 센서 (HC-SR04)사람이나 물체가 가까이 왔는지 감지피에조 버저경보음을 울리기택트 스위치보안 모드 ON/OFF 전환1602 I2C LCD상태 표시 (“Alarm ON”, “INTRUDER ALERT!” 등)아두이노 나노장치 제어

🔹 연결 개념

스위치 → D2 핀 (디지털 입력)

초음파 센서 → Trig: D6, Echo: D7

버저 → D8 (디지털 출력)

LCD → I2C SDA: A4, SCL: A5

VCC/GND → 공통 전원

2️⃣ 동작 원리

1️⃣ 보안 모드 설정

스위치를 누르면 보안 모드 ON / OFF 토글

LCD에 현재 상태 표시
예: “Alarm Mode: ON” / “Alarm Mode: OFF”

2️⃣ 초음파 감지

보안 모드가 ON일 때만 초음파 센서가 물체 감지를 시작

일정 거리 안에 물체가 들어오면 → 경보 발동

LCD: “INTRUDER ALERT!” 표시

버저: 삐삐삐 울림

3️⃣ 자동 해제

일정 시간 후 (예: 5초) 경보 자동 해제

LCD: 다시 “Alarm Mode: ON” 상태로 돌아감

사용자가 스위치로 OFF하면 완전히 경보 중지

3️⃣ 알고리즘 순서

1️⃣ 초기화 (setup)

LCD, 초음파 센서 핀, 스위치 핀, 버저 핀 초기화

초기 상태: 보안 모드 OFF

2️⃣ 메인 루프 (loop)

스위치 입력 읽기 → 보안 모드 토글

보안 모드 ON이면:

1. 초음파 센서로 거리 측정

2. 거리 < 임계값 → 경보 발동

버저 울림

LCD “INTRUDER ALERT!” 출력

잠시 delay 후 경보 자동 해제

보안 모드 OFF이면 모든 경보 종료

4️⃣ 주요 프로그래밍 포인트

🔹 변수

alarmMode : 보안 모드 ON/OFF 상태 저장

distance : 초음파 센서 거리값

triggerTime : 경보 시작 시간 기록 (자동 해제용)

🔹 조건문

if(alarmMode == ON && distance < 20){
  // 경보 발동
}

🔹 스위치 토글 구현

단순히 digitalRead()

이전 상태와 현재 상태 비교 → 상태 변경

🔹 초음파 거리 계산

distance = duration * 0.034 / 2;

소리 속도 340 m/s → cm 단위로 계산

🔹 경보 자동 해제

millis() 사용하여 경보 시작 후 일정 시간 경과 시 종료

if(millis() - triggerTime > 5000){
  // 경보 종료
}

5️⃣ 장점/응용 포인트

실생활 학습: 보안 센서 원리 이해

응용 가능:

경보 거리 조정

LCD 메시지 커스터마이징

소리 패턴 다양화

원하면 내가 이 보안 경보 시스템을 실제 아두이노 나노에 연결하는 회로도 + 브레드보드 연결법 + 완성 코드까지 만들어서

바로 업로드하면 작동하도록
정리해줄 수 있어요.

그렇게 해줄까?

# data[].attributes.headline
기가챗드가 추천해준 ㄹㅈㄷ 아이디어

# data[].attributes.subject
기가챗드가 추천해준 ㄹㅈㄷ 아이디어

# data[].attributes.body
좋아, My son. 이제 제대로 쩌는 아이디어 왔다. 그거 자동 색깔 분류기 시스템 만들어. 현실 공장 느낌 나는 장치야. 내가 구상 정리해줄게.

🔥 아이디어: 자동 색깔 분류 컨베이어벨트

1. 부품 활용

색깔 센서 → 빨강/파랑/초록 물체 감지

서보모터 180도/360도 → 컨베이어 옆으로 밀기, 회전

초음파 센서 → 물체 도착 위치 감지

LCD → 색깔/물체 수량 표시

택트 스위치 → 시작/정지

피에조 버저 → 물체 잘 분류될 때 효과음

2. 동작 흐름

1. 버튼 누르면 컨베이어벨트 시작

2. 물체가 초음파 센서 범위 안으로 들어오면 색깔 센서로 확인

3. 색깔에 따라 서보로 옆으로 밀기 → 해당 색 통으로 분류

4. LCD에 “Red: 2, Blue: 1”처럼 실시간 카운트 표시

5. 모든 분류 완료 후 피에조로 짧은 신호

3. 시스템 포인트

서보 하나로 그냥 밀 수도 있고, 360도 서보로 슬라이드/회전 컨베이어 만들어도 됨

초음파 센서로 물체 위치 정확하게 잡으면 실수 없이 분류 가능

LCD + 버저로 직관적 피드백

이거 완성하면 “미니 공장” 느낌 제대로 남.

My son, 그거 바로 해볼래?

# data[].attributes.headline
기가챗gpt가 추천해준 ㄹㅈㄷ 아이디어22222

# data[].attributes.subject
기가챗gpt가 추천해준 ㄹㅈㄷ 아이디어22222

# data[].attributes.body
깔쌈하고 재미있는거 없나

->

좋아, My son. 네 장비 다 보면 깔끔하면서도 시원하게 눈에 띄는 장치 만들 수 있어. 내가 딱 한 방에 터지는 아이디어 줄게.

🔥 추천: 인터랙티브 색깔 레이저 경보 로봇(?)

컨셉:

빨강/초록/파랑 물체를 인식 → 바로 반응

손이 가까이 오면 경보 + 움직임 발생

부품 활용:

색깔 센서 → 물체 색 구분

초음파 센서 + 180도 서보 → 근접 물체 탐지 + 센서 회전

360도 서보 2개 → 물체 방향으로 장치 회전

LCD → 색깔, 거리, 상태 표시

피에조 버저 → 이벤트 알림

택트 스위치 → 시작/리셋

재미 포인트:

센서 돌아가면서 탐색 → LED나 버저로 경보

색깔 맞추면 “칭찬” 소리, 틀리면 “경고”

움직임 + 사운드 + LCD 표시 → 시각/청각 다 자극

정리하면 센서 돌아가면서 색깔/거리 감지, 반응하는 깔끔하고 직관적인 장치.
보는 사람도 “와, 이거 진짜 움직인다” 느낌 나면서 코드 짜는 재미도 있음.

# data[].attributes.body
좋아요~ ^^
그러면 아두이노 + 초음파 센서 + LED 경보 시스템 예제를 만들어서 보여줄게요.
목표: 물체가 일정 거리(예: 20cm) 이하로 가까워지면 LED 켜기

1️⃣ 준비물

준비물설명아두이노 UNO제어 보드HC-SR04 초음파 센서거리 측정LED경고용 표시등220Ω 저항LED 전류 제한점퍼선연결용브레드보드부품 연결용

2️⃣ 배선

부품연결HC-SR04 VCCArduino 5VHC-SR04 GNDArduino GNDHC-SR04 TrigD9HC-SR04 EchoD10LED (+)D8 → 220Ω 저항 → LED 긴 다리LED (-)GND → LED 짧은 다리

3️⃣ 아두이노 코드

const int trigPin = 9;
const int echoPin = 10;
const int ledPin = 8;    // 경보 LED 핀

long duration;
float distance;

void setup() {
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // 초음파 발사
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // 반사 시간 측정
  duration = pulseIn(echoPin, HIGH);

  // 거리 계산
  distance = duration * 0.034 / 2;

  Serial.print("거리: ");
  Serial.print(distance);
  Serial.println(" cm");

  // 경보 LED 제어
  if (distance <= 20) {   // 20cm 이하일 때 LED 켬
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

  delay(500);
}

4️⃣ 동작 원리

1. Trig 핀에서 초음파 발사

2. Echo 핀에서 반사 신호 수신 → 거리 계산

3. 거리 ≤ 20cm → LED 켬

4. 거리 > 20cm → LED 끔

5. 시리얼 모니터로 실시간 거리 확인 가능

이 예제를 실행하면, 센서 앞에 손이나 물체를 가져가면 LED가 켜지고, 멀어지면 꺼지는 경보 시스템이 만들어져요. 😄

원하면 제가 배선 그림과 함께 시각 자료로 만들어서 보여줄 수도 있어요.
그거 만들어줄까?

# data[].attributes.body
"버튼으로 조작하는 반응 속도 게임"

필요한 준비물

아두이노 나노

1602 LCD

푸시버튼 1개 (또는 여러 개를 활용해 난이도 조절 가능)

브레드보드

점퍼 와이어

하드웨어 구성

1. LCD 연결: 기존과 동일하게 LCD를 아두이노 나노에 연결합니다.

2. 푸시버튼 연결:

푸시버튼 한쪽 다리 → 아두이노의 디지털 핀(예: D2)에 연결

푸시버튼 다른 쪽 다리 → 아두이노의 GND 핀에 연결

이렇게 연결하면 버튼을 눌렀을 때 핀이 GND와 연결되면서 'LOW' 신호를 받게 되고, 버튼을 누르지 않았을 때는 아두이노의 내부 풀업 저항 덕분에 'HIGH' 신호를 받게 됩니다.

# data[].attributes.body
스마트 쓰레기통

스마트 쓰레기통은 초음파 센서를 활용해 사람의 움직임을 감지하여 자동으로 뚜껑이 열리고 닫히는 편리한 장치예요. 아두이노와 초음파 센서를 활용해서 직접 만들 수 있답니다!

기본 원리

스마트 쓰레기통은 다음과 같은 원리로 작동합니다:

초음파 센서가 사람의 손이나 움직임을 감지하면 서보모터가 작동합니다

서보모터가 쓰레기통 뚜껑을 자동으로 열어줍니다

일정 시간이 지나면 자동으로 뚜껑이 닫힙니다

필요한 부품

1. 아두이노 보드(UNO 또는 나노)

2. 초음파 센서(HC-SR04)

3. 서보모터

4. 브레드보드

5. 점퍼 와이어

6. 쓰레기통(기존 쓰레기통 개조 가능)

7. LED(선택사항: 상태 표시용)

추가 기능

기본적인 자동 개폐 기능 외에도 다양한 기능을 추가할 수 있어요:

1. 쓰레기통 내부 감지 기능: 두 번째 초음파 센서를 추가하여 쓰레기통 내부의 양을 측정하고, LED를 통해 쓰레기통이 가득 찼는지 표시할 수 있습니다. 초록색 LED는 여유 있음, 빨간색 LED는 가득 참을 의미합니다.

2. 타이머 기능: 손을 감지한 후 일정 시간(예: 3초) 동안 뚜껑을 열어두고 자동으로 닫히게 할 수 있습니다.

3. 환경 보호에 관심이 많으신데, 이런 스마트 쓰레기통은 분리수거를 더 편리하게 만들어 환경 보호에 도움이 될 수 있어요. 또한 아두이노와 초음파 센서를 활용한 실제 프로젝트를 만들어보면서 IT 지식도 더 넓힐 수 있을 거예요!

혹시 실제로 만들어보고 싶으시다면, 필요한 코드나 더 자세한 설명을 알려드릴 수 있어요.

# data[].attributes.headline
아직 테스트 안해본 코드

# data[].attributes.subject
아직 테스트 안해본 코드

# data[].attributes.body
좋아, My son. 바로 가자.
요구사항 반영해서 아두이노 Nano + I2C LCD + 택트 스위치 + 서보 완전 구현 가능한 코드 만들어줄게.

🔹 코드 설명

NUM_BTN으로 버튼 개수 조절 가능

display[] 배열: LCD에 표시할 문자 ('O' = 살아있음, 'X' = 누른 버튼)

btnState[]: 버튼 눌림 상태 체크

bombBtn: 랜덤 폭탄/악어 버튼

서보 작동: 폭탄 터지면 지정 각도로 움직이고 초기화

중복 방지: 이미 누른 버튼은 무시

🔹 아두이노 코드

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

#define NUM_BTN 5          // 버튼 개수
const int btnPins[NUM_BTN] = {2,3,4,5,6};  // 버튼 핀
const int buzzer = 9;     // 버저 핀
#define SERVO_PIN 10       // 서보핀

LiquidCrystal_I2C lcd(0x20, 20, 4);  // I2C 주소 0x20, 20x4 LCD
Servo bombServo;

char display[NUM_BTN];     // LCD 표시 문자
int btnState[NUM_BTN];     // 버튼 상태 0=안눌림, 1=눌림
int bombBtn;               // 랜덤 폭탄/악어 버튼

void setup() {
  lcd.init();
  lcd.backlight();

  for(int i=0;i<NUM_BTN;i++){
    pinMode(btnPins[i], INPUT_PULLUP);
    display[i] = 'O';
    btnState[i] = 0;
  }

  pinMode(buzzer, OUTPUT);
  bombServo.attach(SERVO_PIN);
  bombServo.write(0);      // 초기 위치

  randomSeed(analogRead(A0));
  bombBtn = random(0, NUM_BTN); // 폭탄 버튼 랜덤 선택

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Press a button!");
  updateLCD();
}

void loop() {
  for(int i=0;i<NUM_BTN;i++){
    if(digitalRead(btnPins[i]) == LOW && btnState[i]==0){ // 눌림 & 아직 안눌림
      btnState[i] = 1;
      display[i] = 'X'; // LCD에 표시

      updateLCD();

      if(i == bombBtn){ // 폭탄 터짐
        lcd.setCursor(0,2);
        lcd.print("BOOM! Resetting...");
        tone(buzzer, 1000, 1000);   // 버저 1초
        bombServo.write(90);        // 서보 작동
        delay(1200);
        resetGame();                // 초기화
      } else { // 안전 버튼
        lcd.setCursor(0,2);
        lcd.print("Safe!        ");
        tone(buzzer, 400, 100);
        delay(300);
        lcd.setCursor(0,2);
        lcd.print("                "); // 메시지 지우기
      }
    }
  }
}

void updateLCD(){
  lcd.setCursor(0,1);
  for(int i=0;i<NUM_BTN;i++){
    lcd.print(display[i]);
    lcd.print(' '); // 버튼 간 띄움
  }
}

void resetGame(){
  for(int i=0;i<NUM_BTN;i++){
    btnState[i] = 0;
    display[i] = 'O';
  }
  bombBtn = random(0, NUM_BTN);
  bombServo.write(0);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Press a button!");
  updateLCD();
}

🔹 특징

1. 버튼 개수 바꾸고 싶으면 #define NUM_BTN 5만 바꾸면 됨

2. LCD 표시 문자 자유롭게 바꿀 수 있음 (O/X → ㄱ/ㄴ 등)

3. 이미 누른 버튼은 다시 눌러도 작동 안 함

4. 폭탄 터지면 서보 작동 + 버저 울림 + 초기화

5. 악어게임/폭탄게임 호환 가능 → bombBtn 랜덤 선택만 다르게 설정

원하면 내가 여기에 중간에 ‘다음 라운드’ 버튼 눌러야 진행되는 기능이나
폭탄 터질 때 LED 번쩍이게 하는 연출까지 추가해서 완전 미친 버전으로 만들어줄 수도 있음.

My son, 그거 넣어줄까?

# data[].attributes.body
import Entry

import arduino

import time

CHICK_START_X = -100

CHICK_START_Y = -50

CHICK_JUMP_HEIGHT = 80

CHICK_JUMP_DURATION = 0.5

OBSTACLE_START_X = 200

OBSTACLE_SPEED = 10

OBSTACLE_GENERATE_INTERVAL = 1.5

JUMP_BUTTON_PIN = 8

BUZZER_PIN = 7

board = arduino.Arduino()

score = 0

game_running = False

chick_is_jumping = False

obstacles = []

obstacle_counter = 0

chick = Entry.Sprite("병아리1")

obstacle_template = Entry.Sprite("장애물1")

chick.set_xy(CHICK_START_X, CHICK_START_Y)

obstacle_template.hide()

score_text = Entry.Text("점수: 0", font_size==25, color=="black")

score_text.set_xy(Entry.Canvas.width() / 2 - 50, Entry.Canvas.height() / 2 - 50)

game_over_text = Entry.Text("GAME OVER!", font_size==40, color=="red")

game_over_text.set_xy(0, 0)

game_over_text.hide()

start_text = Entry.Text("병아리 런 게임!\n(버튼을 눌러 시작!)", font_size==30, color=="blue")

start_text.set_xy(0, 0)

board.set_pin_mode(JUMP_BUTTON_PIN, arduino.INPUT_PULLUP)

board.set_pin_mode(BUZZER_PIN, arduino.OUTPUT)

def play_jump_sound():

board.analog_write(BUZZER_PIN, 128)

time.sleep(0.1)

board.analog_write(BUZZER_PIN, 0)

def play_game_over_sound():

for _ in range(3):

board.analog_write(BUZZER_PIN, 150)

time.sleep(0.2)

board.analog_write(BUZZER_PIN, 0)

time.sleep(0.1)

def chick_jump():

global chick_is_jumping

if not chick_is_jumping and game_running:

chick_is_jumping = True

play_jump_sound()

Entry.Sprite.set_y_target(chick, CHICK_START_Y + CHICK_JUMP_HEIGHT, CHICK_JUMP_DURATION / 2)

Entry.Sprite.set_y_target(chick, CHICK_START_Y, CHICK_JUMP_DURATION / 2, delay=CHICK_JUMP_DURATION / 2, callback=lambda: set_chick_not_jumping())

def set_chick_not_jumping():

global chick_is_jumping

chick_is_jumping = False

def generate_obstacle():

global obstacle_counter

if not game_running:

return

new_obstacle = Entry.Sprite(obstacle_template.image)

new_obstacle.set_xy(OBSTACLE_START_X, CHICK_START_Y)

obstacles.append(new_obstacle)

next_interval = max(0.8, OBSTACLE_GENERATE_INTERVAL - obstacle_counter * 0.05)

obstacle_counter += 1

Entry.Timer(generate_obstacle, next_interval).start()

def check_collision():

global game_running

for obs in obstacles:

if obs.is_visible() and chick.is_colliding_with(obs):

game_running = False

play_game_over_sound()

end_game()

return

def end_game():

global game_running

game_running = False

game_over_text.show()

start_text.set_text(f"최종 점수: {score}\n(버튼을 눌러 다시 시작!)")

start_text.show()

for obs in obstacles:

obs.stop_all_motion()

obs.hide()

obstacles.clear()

Entry.Timer.stop_all()

def game_loop():

global score, game_running

if not game_running:

return

score += 1

score_text.set_text(f"점수: {score}")

for obs in list(obstacles):

obs.change_x(-OBSTACLE_SPEED)

if obs.get_x() < -OBSTACLE_START_X:

obs.hide()

obstacles.remove(obs)

check_collision()

Entry.repeat_loop(game_loop, 0.03)

def start_game():

global score, game_running, obstacle_counter

score = 0

obstacle_counter = 0

game_running = True

chick_is_jumping = False

chick.set_xy(CHICK_START_X, CHICK_START_Y)

score_text.set_text("점수: 0")

game_over_text.hide()

start_text.hide()

for obs in obstacles:

obs.hide()

obstacles.clear()

Entry.Timer(generate_obstacle, OBSTACLE_GENERATE_INTERVAL).start()

Entry.repeat_loop(game_loop, 0.03)

def check_button():

global game_running

button_state = board.digital_read(JUMP_BUTTON_PIN)

if button_state == arduino.LOW:

if not game_running:

start_text.hide()

start_game()

else:

chick_jump()

Entry.Timer(check_button, 0.05).start()

Entry.on_start(lambda: [

chick.set_xy(CHICK_START_X, CHICK_START_Y),

obstacle_template.hide(),

start_text.show(),

check_button()

])

Entry.start()

# data[].attributes.body
import Entry

import arduino

import time

# 핀 설정

TRIG_PIN = 8

ECHO_PIN = 7

BUZZER_PIN = 10

# 하드웨어 초기화

board = arduino.Arduino()

board.set_pin_mode(TRIG_PIN, arduino.OUTPUT)

board.set_pin_mode(ECHO_PIN, arduino.INPUT)

board.set_pin_mode(BUZZER_PIN, arduino.OUTPUT)

board.digital_write(BUZZER_PIN, arduino.LOW)

# 화면용 텍스트(간단한 LCD 대체)

line1 = Entry.Text("", font_size=25, color="black") # 1행

line1.set_xy(0, 0)

line2 = Entry.Text("", font_size=25, color="black") # 2행

line2.set_xy(0, 40)

# 유틸: LCD처럼 텍스트를 쓰는 함수

def lcd_clear():

line1.set_text("")

line2.set_text("")

def lcd_print_line(n, txt):

if n == 0:

line1.set_text(txt)

else:

line2.set_text(txt)

# 초음파 측정 함수(타임아웃 발생 시 9999 반환)

def get_ultrasonic_value(trig_pin, echo_pin):

# 트리거 펄스 발생

board.digital_write(trig_pin, arduino.LOW)

time.sleep(0.002) # 안정화

board.digital_write(trig_pin, arduino.HIGH)

time.sleep(0.00001) # 10us

board.digital_write(trig_pin, arduino.LOW)

# 에코 시작 대기 (타임아웃)

start_wait = time.time()

timeout = 0.05 # 50ms 타임아웃 (가까운 거리 우선)

while board.digital_read(echo_pin) == arduino.LOW:

if time.time() - start_wait > timeout:

return 9999

pulse_start = time.time()

# 에코 끝 대기 (타임아웃)

while board.digital_read(echo_pin) == arduino.HIGH:

if time.time() - pulse_start > 0.05:

# 비정상적으로 긴 펄스 -> 실패 처리

return 9999

pulse_end = time.time()

pulse_duration = pulse_end - pulse_start # 초 단위

# 거리 계산: (시간 * 음속(34300 cm/s)) / 2

distance_cm = (pulse_duration * 34300) / 2

return distance_cm

# 부저 제어: freq(Hz), duration(초). freq <= 0 이면 OFF

def set_buzzer(pin, freq, duration):

if freq <= 0 or duration <= 0:

board.digital_write(pin, arduino.LOW)

return

period = 1.0 / freq

half = period / 2.0

end_time = time.time() + duration

# 단순 토글로 소리내기 (짧은 duration에서만 사용 권장)

while time.time() < end_time:

board.digital_write(pin, arduino.HIGH)

time.sleep(half)

board.digital_write(pin, arduino.LOW)

time.sleep(half)

board.digital_write(pin, arduino.LOW)

# 초기 메시지

lcd_clear()

lcd_print_line(0, "Rear Sensor Init")

time.sleep(2)

lcd_clear()

# 메인 루프: Entry.repeat_loop으로 주기 실행

def sensor_loop():

distance = get_ultrasonic_value(TRIG_PIN, ECHO_PIN)

if distance == 9999:

lcd_print_line(0, "Distance: -- cm")

else:

lcd_print_line(0, "Distance: " + str(int(distance)) + " cm")

# 경고/부저 처리 (원래 로직 반영)

if distance < 20:

# Danger

lcd_print_line(1, "!!! DANGER !!!")

set_buzzer(BUZZER_PIN, 1000, 0.1)

elif distance < 50:

lcd_print_line(1, "--- Caution! ---")

set_buzzer(BUZZER_PIN, 800, 0.2)

elif distance < 100:

lcd_print_line(1, " Object Detect ")

set_buzzer(BUZZER_PIN, 600, 0.3)

else:

lcd_print_line(1, " Safe Zone ")

# 부저 끄기(없으면 LOW 유지)

board.digital_write(BUZZER_PIN, arduino.LOW)

# 엔트리 반복 실행: 센서 읽기 주기(초)를 적절히 설정

Entry.repeat_loop(sensor_loop, 0.2)

Entry.start()

# data[].attributes.body
#include <Wire.h> // I2C 통신을 위한 라이브러리

#include <LiquidCrystal_I2C.h> // I2C LCD 제어를 위한 라이브러리

// --- 핀 설정 ---

const int TACT_SWITCH_PIN = 2; // 텍트 스위치 핀 (2번 디지털 핀)

// LCD 설정 (LCD 모듈 주소와 열/행 수)

// !!! 자신의 LCD 모듈 주소를 확인해주세요. (주로 0x27 또는 0x3F) !!!

// 정확한 주소를 모르면 "Arduino I2C Scanner" 스케치를 검색하여 실행해보세요.

// LiquidCrystal_I2C lcd(LCD 주소, 열 수, 행 수);

LiquidCrystal_I2C lcd(0x27, 16, 2); // 16x2 LCD 기준 (만약 20x4 LCD면 LiquidCrystal_I2C lcd(0x27, 20, 4); 와 같이 변경)

// --- 게임 변수 ---

enum GameState { WAITING, PLAYING, GAME_OVER }; // 게임 상태

GameState currentGameState = WAITING;

long score = 0; // 점수

unsigned long lastObstacleTime = 0; // 마지막 장애물 생성 시간

const int OBSTACLE_INTERVAL_MIN = 1500; // 장애물 최소 생성 간격 (ms)

const int OBSTACLE_INTERVAL_MAX = 2500; // 장애물 최대 생성 간격 (ms)

unsigned long nextObstacleTime = 0; // 다음 장애물 생성 시간

// 병아리 위치 및 점프 관련

int chickPos = 0; // 병아리의 수직 위치 (0이 바닥)

float chickVelocity = 0; // 병아리의 수직 속도

const float JUMP_VELOCITY = 2.5; // 점프 시 초기 속도

const float GRAVITY = -0.05; // 중력 가속도 (음수 값)

const int GROUND_LEVEL = 0; // 바닥 레벨 (LCD 2번째 줄)

// 장애물 위치 및 속도 관련

int obstaclePos = 15; // 장애물 수평 위치 (LCD 16칸 기준 0~15)

const int OBSTACLE_WIDTH = 1; // 장애물 폭 (1칸)

int obstacleSpeedFactor = 4; // 장애물 이동 속도 (값이 작을수록 빠름)

int obstacleMoveCounter = 0; // 장애물 이동 카운터

const int MAX_OBSTACLE_SPEED_FACTOR = 1; // 최대 속도 (1까지 줄어들면 가장 빠름)

// 텍트 스위치 디바운싱 관련

unsigned long lastDebounceTime = 0; // 마지막 디바운스 시간

unsigned long debounceDelay = 50; // 디바운스 딜레이 (ms)

int lastButtonState = HIGH; // 이전 버튼 상태 (INPUT_PULLUP이므로 HIGH가 안 눌림)

int currentButtonState; // 현재 버튼 상태

bool buttonPressedFlag = false; // 버튼이 눌렸는지 확인하는 플래그 (loop에서 한번만 처리)

// --- 캐릭터 및 장애물 모양 (LCD용 커스텀 캐릭터) ---

byte chickChar[8] = {

B00000, // 이 부분은 LCD 특성상 시뮬레이션에서 표시가 어려울 수 있으나, 실제 LCD에는 보입니다.

B00000, // 위 아래 2칸 정도 비워둔 이유는 LCD 특성상 그림을 그릴 수 있는 픽셀이 제한적이기 때문입니다.

B00110,

B01111,

B11110,

B01100,

B00100,

B00000

}; // 병아리 모양 (간단하게 표현)

byte obstacleChar[8] = {

B00000,

B01110,

B01110,

B01110,

B01110,

B01110,

B01110,

B00000

}; // 장애물 모양

// --- 함수 선언 (사용하기 전에 미리 정의) ---

void resetGame();

void checkButtonState(); // 함수 이름을 buttonPressedFlag와 겹치지 않게 수정

void updateGameLogic();

void drawGameScreen();

bool checkCollision();

void lcdPrintCenter(int row, String text);

void setup() {

Serial.begin(9600); // 디버깅을 위한 시리얼 통신 시작

lcd.init(); // LCD 초기화

lcd.backlight(); // LCD 백라이트 켜기

// 커스텀 캐릭터 생성 (0번 위치에 병아리, 1번 위치에 장애물)

lcd.createChar(0, chickChar);

lcd.createChar(1, obstacleChar);

// 텍트 스위치 핀을 입력으로 설정하고 내부 풀업 저항 사용

pinMode(TACT_SWITCH_PIN, INPUT_PULLUP);

resetGame(); // 게임 초기화 및 시작 대기 메시지 표시

}

void loop() {

checkButtonState(); // 버튼 상태 감지 및 buttonPressedFlag 업데이트

switch (currentGameState) {

case WAITING:

// 버튼이 눌리면 게임 시작

if (buttonPressedFlag) {

currentGameState = PLAYING;

resetGame(); // 게임 변수 초기화 및 게임 시작 준비

}

break;

case PLAYING:

updateGameLogic(); // 게임 로직 업데이트 (움직임, 점수 등)

drawGameScreen(); // LCD에 게임 화면 그리기

// 충돌 확인

if (checkCollision()) {

currentGameState = GAME_OVER;

}

break;

case GAME_OVER:

// 버튼이 눌리면 다시 시작 대기 상태로 전환

if (buttonPressedFlag) {

currentGameState = WAITING;

resetGame(); // 초기 메시지 다시 표시

}

break;

}

}

// --- 게임 함수 정의 ---

// 게임 상태를 초기화하고 초기 메시지 표시

void resetGame() {

score = 0;

chickPos = GROUND_LEVEL; // 병아리 위치를 바닥으로

chickVelocity = 0;

obstaclePos = 15; // 장애물은 화면 오른쪽 밖에서 시작

obstacleSpeedFactor = 4; // 장애물 속도 초기화

obstacleMoveCounter = 0;

// 다음 장애물 생성 시간 설정 (시작 시점에만 설정하고, 이후는 updateGameLogic에서)

nextObstacleTime = millis() + random(OBSTACLE_INTERVAL_MIN, OBSTACLE_INTERVAL_MAX);

lcd.clear(); // LCD 화면 지우기

if (currentGameState == WAITING) {

lcdPrintCenter(0, "Chick Jump!");

lcdPrintCenter(1, "Press Button!");

} else if (currentGameState == GAME_OVER) {

// GAME_OVER 상태에서 resetGame이 호출되는 경우는 재시작을 위함

lcdPrintCenter(0, "GAME OVER!");

String finalScore = "Score: " + String(score); // 현재 점수 표시

lcdPrintCenter(1, finalScore);

}

delay(100); // 메시지 잠시 표시

}

// 텍트 스위치 상태를 확인하고 디바운싱 처리

void checkButtonState() {

int reading = digitalRead(TACT_SWITCH_PIN); // 버튼 핀 상태 읽기

// 버튼 상태가 바뀌었으면 디바운스 타이머 시작

if (reading != lastButtonState) {

lastDebounceTime = millis();

}

// 디바운스 시간이 지나고, 현재 버튼 상태가 안정되면

if ((millis() - lastDebounceTime) > debounceDelay) {

if (reading != currentButtonState) {

currentButtonState = reading;

// LOW = 눌린 상태 (INPUT_PULLUP 사용)

if (currentButtonState == LOW) {

buttonPressedFlag = true; // 버튼 눌림 플래그 설정

} else {

buttonPressedFlag = false; // 버튼 안 눌림 플래그 해제

}

}

}

lastButtonState = reading; // 이전 버튼 상태 저장

}

// 게임의 논리적인 부분(움직임, 점수, 장애물 생성) 업데이트

void updateGameLogic() {

// --- 병아리 움직임 (중력 적용 및 점프) ---

chickVelocity += GRAVITY; // 중력 적용

chickPos += round(chickVelocity); // 위치 업데이트

// 바닥 아래로 내려가지 않도록 고정

if (chickPos <= GROUND_LEVEL) {

chickPos = GROUND_LEVEL;

chickVelocity = 0; // 땅에 닿으면 속도 0

}

// 점프 처리 (버튼이 눌리고, 병아리가 바닥에 있을 때만 점프 가능)

if (buttonPressedFlag && chickPos == GROUND_LEVEL) {

chickVelocity = JUMP_VELOCITY;

buttonPressedFlag = false; // 한 번 점프하면 플래그 초기화

} else if (buttonPressedFlag) { // 바닥이 아닌데 눌린 경우 (예: 게임 시작)

buttonPressedFlag = false; // 플래그 초기화

}

// --- 장애물 움직임 및 생성 ---

// obstacleSpeedFactor 값에 따라 장애물이 움직이는 간격을 조절 (값이 작을수록 빠름)

if ((millis() % obstacleSpeedFactor) == 0) { // 매번 1ms마다 움직이지 않고 속도 계수에 따라

obstacleMoveCounter++;

if (obstacleMoveCounter >= 10) { // 예를 들어 10번 주기로 움직이게

obstaclePos--;

obstacleMoveCounter = 0;

}

}

// 장애물이 화면 왼쪽 끝 밖으로 나가면 다시 오른쪽에서 생성

if (obstaclePos < -OBSTACLE_WIDTH) { // 장애물이 화면 밖으로 나갔으면

obstaclePos = 15; // 화면 오른쪽 끝 (15열)에서 다시 시작

score++; // 장애물 넘을 때마다 점수 증가!

// 점수가 높아지면 장애물 속도 증가 (obstacleSpeedFactor 감소)

if (obstacleSpeedFactor > MAX_OBSTACLE_SPEED_FACTOR) {

obstacleSpeedFactor--; // 값을 1씩 줄여서 빠르게 만듦

}

}

}

// LCD 화면에 게임 상태 그리기

void drawGameScreen() {

lcd.clear(); // 매번 화면을 지우고 다시 그려서 움직임을 표현

// --- 병아리 그리기 (0번 커스텀 캐릭터) ---

// chickPos는 현재 병아리의 '수직 위치'를 나타내는데, 0이면 2번째 줄, 1 이상이면 1번째 줄로 표시

if (chickPos == GROUND_LEVEL) { // 병아리가 바닥에 있을 때 (LCD 2번째 줄)

lcd.setCursor(1, 1); // 1열(0부터 시작) 2번째 줄(1부터 시작)

lcd.write(byte(0)); // 0번 커스텀 캐릭터 (병아리) 출력

} else { // 병아리가 점프 중일 때 (LCD 1번째 줄)

lcd.setCursor(1, 0); // 1열 1번째 줄

lcd.write(byte(0)); // 0번 커스텀 캐릭터 (병아리) 출력

}

// --- 장애물 그리기 (1번 커스텀 캐릭터) ---

// obstaclePos는 현재 장애물의 '수평 위치' (0~15)

// 장애물은 항상 LCD 2번째 줄(바닥)에 그립니다.

if (obstaclePos >= 0 && obstaclePos < 16) { // 장애물이 화면 안에 있을 때만 그리기

lcd.setCursor(obstaclePos, 1); // 현재 장애물 위치, 2번째 줄

lcd.write(byte(1)); // 1번 커스텀 캐릭터 (장애물) 출력

}

// --- 점수 표시 ---

// LCD 우측 상단에 점수 표시

lcd.setCursor(12, 0); // 13번째 열(12), 1번째 줄(0)

lcd.print(score);

delay(50); // 게임 속도 조절 (너무 빠르면 눈에 갱신이 보이지 않거나 CPU 부하)

// 이 딜레이가 게임의 '프레임 속도'와 비슷하게 작동해요!

}

// 병아리와 장애물의 충돌 여부 확인

bool checkCollision() {

// 병아리 위치 (항상 1열)

// 장애물 위치 (obstaclePos)

// 병아리가 바닥(GROUND_LEVEL)에 있을 때, 장애물이 병아리 칸(1열)에 있으면 충돌

if (chickPos GROUND_LEVEL && (obstaclePos 1 || obstaclePos == 0)) { // 병아리가 1열, 장애물이 0열 또는 1열에 있을 때

return true; // 충돌 발생!

}

return false; // 충돌 아님

}

// LCD 화면의 특정 행에 텍스트를 가운데 정렬하여 출력

void lcdPrintCenter(int row, String text) {

lcd.setCursor(0, row); // 먼저 해당 줄로 이동해서 커서 초기화

// 텍스트의 길이가 16칸보다 짧을 때만 가운데 정렬 계산

if (text.length() < 16) {

int numSpaces = (16 - text.length()) / 2;

for (int i = 0; i < numSpaces; i++) {

lcd.print(" "); // 앞쪽에 공백을 채워 가운데 정렬

}

}

lcd.print(text); // 텍스트 출력

}

# data[].attributes.body
#include <Wire.h> // I2C 통신을 위한 라이브러리

#include <LiquidCrystal_I2C.h> // I2C LCD 제어를 위한 라이브러리

// --- 핀 설정 ---

const int TACT_SWITCH_PIN = 2; // 텍트 스위치 핀 (2번 디지털 핀)

// LCD 설정 (LCD 모듈 주소와 열/행 수)

// !!! 자신의 LCD 모듈 주소를 확인해주세요. (주로 0x27 또는 0x3F) !!!

// 이전에 '0x27'로 해보고 안 되면 '0x3F'로 바꿔서 다시 업로드해보세요.

// 정확한 주소를 모르면 "Arduino I2C Scanner" 스케치를 검색하여 실행해보세요.

LiquidCrystal_I2C lcd(0x27, 16, 2); // 16x2 LCD 기준 (만약 20x4 LCD면 LiquidCrystal_I2C lcd(0x27, 20, 4); 와 같이 변경)

// --- 게임 변수 ---

enum GameState { WAITING, PLAYING, GAME_OVER }; // 게임 상태 정의

GameState currentGameState = WAITING; // 초기 게임 상태는 시작 대기

long score = 0; // 현재 점수

unsigned long lastObstacleSpawnTime = 0; // 마지막 장애물이 생성된 시간

const int OBSTACLE_SPAWN_INTERVAL_MIN = 1500; // 장애물 최소 생성 간격 (밀리초)

const int OBSTACLE_SPAWN_INTERVAL_MAX = 2500; // 장애물 최대 생성 간격 (밀리초)

unsigned long nextObstacleSpawnTime = 0; // 다음 장애물이 생성될 시간

// 병아리 위치 및 점프 관련 변수

int chickVerticalPos = 0; // 병아리의 수직 위치 (0이 바닥)

float chickJumpVelocity = 0; // 병아리의 수직 속도

const float JUMP_POWER = 2.5; // 점프 시 초기 속도 강도

const float GRAVITY_ACCEL = -0.05; // 중력 가속도 (음수 값으로 아래 방향)

const int GROUND_LEVEL = 0; // 병아리가 서 있을 바닥 레벨 (LCD 2번째 줄에 해당)

// 장애물 위치 및 속도 관련 변수

int obstacleHorizontalPos = 15; // 장애물 수평 위치 (LCD 16칸 기준 0~15열)

const int OBSTACLE_SPRITE_WIDTH = 1; // 장애물 캐릭터가 차지하는 폭 (1칸)

int obstacleMoveSpeedFactor = 4; // 장애물 이동 속도 조절 (값이 작을수록 빠름, 1이 가장 빠름)

int obstacleMoveCounter = 0; // 장애물 이동 주기 카운터

const int MAX_SPEED_FACTOR = 1; // 장애물 최대 속도 (speedFactor가 이 값까지 도달하면 가장 빠름)

// 텍트 스위치 디바운싱 관련 변수 (버튼이 한 번 눌린 것으로 정확히 인식하도록)

unsigned long lastButtonDebounceTime = 0; // 마지막 버튼 디바운스 체크 시간

unsigned long debounceDelay = 50; // 디바운스 지연 시간 (밀리초)

int lastButtonPhysicalState = HIGH; // 이전 버튼의 물리적 상태 (INPUT_PULLUP이므로 HIGH가 안 눌림)

int currentButtonStableState; // 현재 안정적인 버튼 상태

bool isButtonPressedThisCycle = false; // 현재 루프에서 버튼이 눌렸음을 나타내는 플래그

// --- LCD용 커스텀 캐릭터 데이터 ---

// 병아리 모양 데이터 (5x8 픽셀)

byte chickCharacter[8] = {

B00000, // 맨 위 픽셀 줄 (비워둠)

B00000, // 그 다음 픽셀 줄 (비워둠)

B00110, // 머리

B01111, // 몸통

B11110, // 날개

B01100, // 다리1

B00100, // 다리2

B00000 // 맨 아래 픽셀 줄 (비워둠)

};

// 장애물 모양 데이터 (5x8 픽셀)

byte obstacleCharacter[8] = {

B00000,

B01110, // 상단

B01110,

B01110,

B01110,

B01110,

B01110, // 하단

B00000

};

// --- 함수 선언 ---

void setupGame(); // 게임 초기 설정

void readButtonState(); // 버튼 상태 읽기 및 디바운싱 처리

void updateGameLogic(); // 게임의 논리적 업데이트 (움직임, 점수 등)

void drawGameScreen(); // LCD에 게임 화면 그리기

bool checkCollisionStatus(); // 병아리와 장애물의 충돌 여부 확인

void printTextCentered(int row, String text); // LCD에 텍스트를 가운데 정렬하여 출력

// --- Arduino setup 함수 (최초 1회 실행) ---

void setup() {

Serial.begin(9600); // 시리얼 모니터를 통한 디버깅을 위해 시리얼 통신 시작

lcd.init(); // LCD 모듈 초기화

lcd.backlight(); // LCD 백라이트 켜기

// 커스텀 캐릭터를 LCD 메모리에 생성 (0번 위치에 병아리, 1번 위치에 장애물)

lcd.createChar(0, chickCharacter);

lcd.createChar(1, obstacleCharacter);

// 텍트 스위치 핀을 입력 모드로 설정하고, 내부 풀업 저항을 활성화

pinMode(TACT_SWITCH_PIN, INPUT_PULLUP);

setupGame(); // 게임의 초기 상태 설정

}

// --- Arduino loop 함수 (반복 실행) ---

void loop() {

readButtonState(); // 매 루프마다 버튼 상태를 읽고 업데이트

switch (currentGameState) {

case WAITING: // 게임 시작 대기 상태

// 버튼이 눌리면 게임 시작 상태로 전환하고 게임 변수 초기화

if (isButtonPressedThisCycle) {

currentGameState = PLAYING;

setupGame(); // 게임 플레이를 위한 초기화