당번 뽑기 불만을 원천 없애는 공정 룰렛 — 청소 구역 추첨 & 주간 히스토리 아카이빙
🎡 청소 구역(칠판·복도·창틀·쓰레기통) 배정을 룰렛(roulette)으로 바꿉니다. 이전 주 당번은 자동 제외되고, 뽑힌 횟수가 적은 학생이 유리한 균등 추첨(draw)으로 매주 월요일 아침 자치 시간에 전교생이 보는 앞에서 돌아갑니다.
배정 결과는 아카이빙(archiving, 기록 보관) — '주간 기록 CSV 내보내기'로 당번 히스토리를 로컬 파일에 누적합니다(자동 외부 전송 없음). 교사가 학급 시트에 직접 옮겨 적으면 1년분 공평 보장이 완성됩니다. 실명 칸은 없습니다(번호·닉네임만).
📖 한 줄 정의
심기 모드(데이터 임베딩): API 데이터를 미리 받아 HTML 파일 안 상수로 박아두는 방식(앱 실행 중 외부 통신 0).
학내망 원칙: 학교 배포 웹앱은 개인정보 수집·저장·전송 없음(외부 CDN·API 호출 0, 단일 파일) — 학생은 학내망에서 교사 PC 서버에 접속.
1. 3대 핵심 분석 비교표
| 무엇이 바뀌었나요? / 영역 | 초보자를 위한 쉬운 설명 | 이렇게 한번 써보세요! |
|---|---|---|
| 공정 규칙 3단 | ① 이전 주 당번 자동 제외 ② 뽑힌 횟수가 적은 학생이 유리한 균등 추첨 ③ 전원 제외 시 전체 재등장. 규칙이 코드에 그대로 보입니다. | pickPlayer 함수에서 제외·균등 로직 확인하기. |
| 룰렛 애니메이션 | CSS 회전(transform rotate)과 랜덤 각도로 돌다가 감속하며 멈춥니다. 도착 칸에서 '웅-딩' 사운드(Web Audio 합성)가 울립니다. | 전자칠판에서 큰 회전 버튼(88px)을 눌러 구역별 추첨. |
| 히스토리 아카이빙 | '주간 기록 CSV 내보내기' 버튼이 주차·구역·번호·닉네임을 CSV 파일로 저장합니다. 자동 외부 전송은 없습니다 — 학급 시트로 옮겨 적는 것은 교사의 수동 관리입니다. | 매주 금요일 내보내기 → 교사가 학급 시트에 붙여넣기. |
| 개인정보 설계 | 실명 입력·저장 칸이 없습니다 — 번호·닉네임만. 참가자 목록은 파일 상단 상수로 심기되어 학내망 안에서만 완결됩니다. | EMBED_PLAYERS 상수에 모둠 닉네임 목록 심기. |
2. 핵심 아키텍처 해설
① 구역·참가자 데이터
const ZONES = ["칠판", "복도", "창틀", "쓰레기통"];
const PLAYERS = [
{ no: 1, nick: "코알라" },
{ no: 2, nick: "돌고래" }
];
참가자는 번호와 닉네임만 다룹니다 — 실명은 이 앱의 어디에도 들어가지 않습니다.
② 공정 추첨 로직
function pickPlayer(zoneIndex, history) {
const last = history.filter(function (h) {
return h.zone === ZONES[zoneIndex] && h.week === currentWeek - 1;
});
let pool = PLAYERS.filter(function (p) {
return !last.some(function (h) { return h.no === p.no; });
});
if (pool.length === 0) pool = PLAYERS.slice();
return pool[Math.floor(Math.random() * pool.length)];
}
이전 주 당번을 후보에서 빼고, 전원이 제외될 극단적인 경우에는 전체를 다시 후보로 세웁니다. '뽑힌 횟수 적은 학생 우선'은 히스토리의 누적 횟수로 후보를 정렬해 앞쪽에 비중을 주는 방식으로 확장할 수 있습니다.
③ 룰렛 스핀
let angle = 0;
function spin() {
const target = angle + 1440 + Math.random() * 360;
const timer = setInterval(function () {
angle += 18;
wheel.style.transform = "rotate(" + angle + "deg)";
if (angle >= target) {
clearInterval(timer);
sound("ding");
}
}, 30);
}
④ 주간 기록 아카이빙
function archiveRow(zoneIndex, player) {
return currentWeek + "," + ZONES[zoneIndex] + "," + player.no + "," + player.nick;
}
// CSV 내보내기 버튼으로 주간 기록을 로컬 파일로 저장 — 외부 전송 없음
⑤ 운영 체크리스트
- 결락자(부재로 못 뽑힌 학생)는 다음 주 히스토리에서 자동으로 유리해집니다.
- 학급 시트 관리는 교사 수동 — 앱은 자동 외부 전송을 하지 않습니다(학내망 원칙).
- 새 모둠 닉네임이 생기면 EMBED_PLAYERS 상수를 갱신(심기 루틴)합니다.
3. 따라하기 3단계
- 제미나이 전용 에러 제로 프롬프트를 복사해 Gemini에 붙여넣습니다.
- AI가 던지는 역질문 3가지(구역 수, 당번 인원, CSV 서식)에 답하면 단일 HTML 코드가 완성됩니다.
- 코드를
roulette.html로 저장 후 더블클릭 — 월요일 아침 자치 시간에 전자칠판에서 구역별 추첨을 돌립니다.
제미나이 전용 에러 제로 프롬프트
[🚨 에러 방지 기본 안전장치]
1. 결과물은 외부 라이브러리·폰트·이미지 없이 단일 HTML 파일로 완성한다 — 더블클릭 즉시 실행(서버·설치·회원가입·외부 클라우드 금지).
2. 참가자 목록은 번호·닉네임만 다룬다(실명 입력·저장 금지) — 파일 상단 EMBED_PLAYERS 상수로 심기(학내망 배포용 외부 통신 0).
3. 공정 규칙: 이전 주 당번 자동 제외, 뽑힌 횟수가 적은 학생이 유리한 균등 추첨, 전원 제외 시 전체 재등장.
4. 룰렛 회전은 CSS transform(rotate)과 랜덤 각도 — 도착 사운드는 Web Audio API 합성('웅-딩').
5. 주간 기록(주차,구역,번호,닉네임)은 CSV 내보내기로 로컬 파일 저장 — 자동 외부 전송 없음(학급 시트 옮겨 적기는 교사 수동).
6. 전자칠판 대형 터치 대응: 회전 버튼 88px 이상, 결과 표기 큰 글씨.
7. // TODO, /* 생략 */ 금지 — 끝까지 완성한다.
[❓ 역질문 유도]
코드를 바로 만들지 말고, 아래 3가지를 먼저 질문한 뒤 내 답변으로 설계를 확정한다.
Q1. 청소 구역은 몇 개로 할까? (기본 4: 칠판·복도·창틀·쓰레기통)
Q2. 한 구역 당번은 몇 명? (2인 1조 권장)
Q3. 히스토리 CSV 서식은? (주차,구역,번호,닉네임 기본)🎯 에디터 한줄평
'뽑기 불만'이 '공정 규칙 논의'로 바뀌는 것이 이 앱의 진짜 목표입니다. 규칙이 코드로 눈에 보이는 순간, 학생들은 불만 대신 제안을 하기 시작합니다 — "제외 기준을 2주로 늘리면 어때요?". 이력이 코드 안에서 쌓이는 것은 '공평은 믿음이 아니라 기록'이라는 자치 교육의 정수입니다. 전자칠판 앞에서 울리는 웅-딩 사운드 하나가 월요일 아침을 아이들 절반의 관심사로 만듭니다.
📚 기술·교육 참고 링크
- MDN — CSS transform : 룰렛 회전 애니메이션의 원리
- MDN — Web Audio API : '웅-딩' 도착 사운드 합성
- 교육과정 연계: 창의적 체험활동(학급자치·역할 분담), 모둠 활동과 학급 회의 안건으로 확장