TOPぺージ

プロジェクト概要

IT1-CODE-POCKETは、共通テスト「情報Ⅰ」第3問で扱われるプログラミング・アルゴリズム分野の学習を補助するために開発したWebアプリです。スマートフォンで短時間でも取り組めるよう、PythonモードとDNCLモードのクイズ、難易度別の出題、問題数選択、解説表示、間違えた問題の復習機能を実装しました。 単なるクイズ画面だけでなく、共通テスト用プログラム表記の解説ページ、重要アルゴリズムの解説ページ、プライバシーポリシーやお問い合わせページも用意し、公開サイトとして運用できる構成にしています。

開発目的

  • 共通テスト「情報Ⅰ」第3問の学習をスマートフォンで手軽に行えるようにするため
  • PythonとDNCLの両方に対応した演習環境を作るため
  • クイズ、解説、復習を組み合わせて学習しやすい流れを作るため
  • 静的サイトでも実用的な学習アプリを実装するため
  • 独自ドメイン、SEO、OGP、AdSense対応まで含めた公開運用を経験するため

使用技術

プログラミング言語

JavaScript

フロントエンド

HTML5 CSS3 Vanilla JavaScript Tailwind CSS CDN

バックエンド / 外部サービス

GitHub Pages Cloudflare Google Search Console Google AdSense Google Forms localStorage

主な機能

  • Python / DNCL の言語モード選択
  • 基礎 / 標準 / 発展の難易度選択
  • 5問 / 10問 / 20問 / 40問の問題数選択
  • ランダム出題と同一セッション内の重複防止
  • 回答後の正誤判定と解説表示
  • 中断したクイズの保存と再開
  • 間違えた問題だけを復習する機能
  • 復習で正解した問題を復習リストから自動削除
  • テーマ切り替え(シンプル、クールブラック、ポップ)
  • 共通テスト用プログラム表記の解説ページ
  • 重要アルゴリズムの解説ページ
  • SNS共有ボタン
  • OGP / favicon / app icon 対応
  • サイトマップ、robots.txt、ads.txt対応

システム構成

バックエンドを持たない静的Webアプリとして構成しています。問題データと画面制御はJavaScriptで管理し、クイズの中断データや復習リスト、テーマ設定はブラウザのlocalStorageに保存します。GitHub Pagesで公開し、独自ドメインとHTTPSはCloudflareおよびGitHub Pagesの設定で運用しています。

データフロー

ユーザーが言語モード、難易度、問題数を選択
↓ スタート
条件に合う問題を抽出し、ランダムに並び替え
↓ 出題
ユーザーが選択肢を回答
↓ 判定
正解ならスコア加算、不正解なら復習リストへ保存
↓ 解説表示
次の問題へ進む、または結果画面を表示
↓ 必要に応じて
中断データを保存、または復習リストから再演習

工夫した点

  • スマートフォンで片手操作しやすい画面構成にした
  • クイズ中のヘッダー操作を「中断」「戻る」に整理した
  • 中断データと復習リストを独立して管理し、片方の操作でもう片方が消えないようにした
  • 復習・再開ボタンをヘッダー内に表示し、必要な時だけアクセスできるようにした
  • PythonとDNCLで問題数や難易度のバランスを取るようにした
  • DNCL表記がPython風になりすぎないよう、記号や用語を調整した
  • 選択肢のインデントやラベル幅を調整し、コード選択肢を読みやすくした
  • テーマ切り替え時の一瞬の表示ズレを防ぐため、初期テーマ反映用スクリプトを用意した
  • OGP、favicon、SNS共有、sitemap、robots.txt、ads.txtまで整備し、公開サイトとして扱えるようにした

技術的ハイライト

1. ランダム出題と問題数制御

function shuffleQuestions(questions) {
  const shuffled = [...questions];
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  }
  return shuffled;
}

function startQuiz() {
  const targetQuestions = QUESTIONS.filter(q =>
    q.langMode === state.langMode && q.difficulty === state.difficulty
  );

  if (targetQuestions.length === 0) {
    alert('該当する問題がありません。言語モードまたは難易度を変更してください。');
    return;
  }

  state.questions = shuffleQuestions(targetQuestions).slice(0, Math.min(state.questionCount, targetQuestions.length));
  state.quizMode = 'normal';
  state.currentIndex = 0;
  state.score = 0;
  state.answered = false;
  state.selectedIndex = null;
  closeLearningStatusModal();
  showScreen('screen-quiz');
  renderQuestion();
  saveSession();
  updateHeaderStats();
}

2. localStorageを使った中断・復習データ管理

const SESSION_KEY = 'quiz-saved-session-v1';
const REVIEW_KEY = 'quiz-review-question-ids-v1';

function saveSession() {
  if (!state.questions.length) return;
  if (state.quizMode === 'review') return;

  const session = {
    langMode: state.langMode,
    difficulty: state.difficulty,
    questionCount: state.questionCount,
    quizMode: state.quizMode,
    questionIds: state.questions.map(q => q.id),
    currentIndex: state.currentIndex,
    score: state.score,
    answered: state.answered,
    selectedIndex: state.selectedIndex,
    savedAt: new Date().toISOString()
  };
  localStorage.setItem(SESSION_KEY, JSON.stringify(session));
  updateResumeCard();
  updateHeaderStats();
}

function addReviewQuestion(questionId) {
  saveReviewQuestionIds([...getReviewQuestionIds(), questionId]);
}

function removeReviewQuestion(questionId) {
  saveReviewQuestionIds(getReviewQuestionIds().filter(id => id !== questionId));
}

3. テーマのちらつきを防ぐ初期化処理

(function initThemeBeforePaint() {
  try {
    const theme = localStorage.getItem('quiz-theme');
    if (['simple', 'cool', 'pop'].includes(theme)) {
      document.documentElement.setAttribute('data-theme', theme);
    }
  } catch {
    // localStorage が使えない環境では初期テーマのまま表示する。
  }
})();

開発情報

開発形態

個人開発

役割

企画、設計、UI作成、問題作成、フロントエンド実装、公開設定、SEO対応、AdSense準備

制作期間

約1〜2週間

開発時の注意事項

本プロジェクトは、学習支援およびポートフォリオ掲載を目的として開発しました。公開サイトとして運用するため、学習内容の扱い、個人情報、外部サービス、広告審査に関する点に配慮しています。

学習コンテンツとしての配慮

  • 共通テスト本番での出題を保証する表現は避けた
  • 「問われやすい」ではなく「学んでおくと理解に役立つ」という表現に調整した
  • PythonとDNCLの表記が混ざらないように見直した
  • 解説文や選択肢の見やすさを優先して調整した

個人情報・データ保存への配慮

  • クイズの中断データや復習リストはlocalStorageに保存し、サーバーへ送信しない設計にした
  • お問い合わせはGoogleフォームを利用し、プライバシーポリシーで取り扱いを明記した
  • ログイン機能や個人識別を前提としない構成にした

公開・広告運用への配慮

  • 独自ドメインとHTTPSで公開できるようにした
  • sitemap.xmlとrobots.txtを用意した
  • OGP、favicon、app iconを設定した
  • AdSenseコードとads.txtを設置した
  • プライバシーポリシー、お問い合わせ、利用規約・免責事項、このサイトについてのページを用意した

謝辞

  • MDN Web Docs: HTML、CSS、JavaScriptの仕様確認
  • Google Search Console: サイト公開後のインデックス確認
  • Google AdSense: 広告審査およびads.txt設定
  • Cloudflare: DNS管理と独自ドメイン運用
  • GitHub Pages: 静的サイトのホスティング