diff --git a/app/page.tsx b/app/page.tsx
index c69f396..5166a77 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,5 +1,79 @@
+import Link from "next/link";
+import { pagesList } from "./pagesList";
+
export default function Home() {
- return
- This is root page
-
;
+ return (
+
+
my.code(); へようこそ
+
+ my.code();
+ はプログラミング言語のチュートリアルを提供するウェブサイトです。
+
+
+ {pagesList.map((group) => {
+ return (
+
+
+
{group.lang}
+
{group.description}
+
+
+ はじめる
+
+
+
+
+ );
+ })}
+
+
主な特徴
+ {/* TODO: デザインがダサい */}
+
+ -
+ 豊富なチュートリアル
+
+ my.code();
+ ではさまざまなプログラミング言語やフレームワークのチュートリアルを提供しています。
+ 初心者向けの基礎から上級者向けの応用まで、幅広いレベルに対応したチュートリアルが揃っています。
+ {/* ほんまか? */}
+
+
+ -
+ すぐに動かせる実行環境
+
+ my.code();
+ ではブラウザ上でコードを実行できる環境を整備しており、環境構築の手間なくすぐにコードを実行することができます。
+ チュートリアル内のサンプルコードはそのまま実行するだけでなく、自由に編集して試すことも可能です。
+
+
+ -
+ AIアシスタントによるサポート
+
+ my.code(); ではAIアシスタントが学習をサポートします。
+ チュートリアルを読んでいてわからないことがあれば、AIアシスタントに質問してみてください。
+ さらに、実行したサンプルコードの解説やエラーの原因調査、改善提案まで、AIアシスタントがあなたの学習を強力に支援します。
+
+
+ -
+ 実践的な練習問題
+
+ 各チュートリアルには練習問題が含まれており、学んだ内容を実際に試すことができます。
+ 練習問題は段階的に難易度が上がるように設計されており、理解度を深めるのに役立ちます。
+ 書いたコードはその場ですぐにAIアシスタントがレビューし、フィードバックを提供します。
+
+
+
+
+ );
}
diff --git a/app/pagesList.ts b/app/pagesList.ts
new file mode 100644
index 0000000..2a8a150
--- /dev/null
+++ b/app/pagesList.ts
@@ -0,0 +1,32 @@
+// docs_id = `${group.id}-${page.id}`
+export const pagesList = [
+ {
+ id: "python",
+ lang: "Python",
+ // TODO: これをいい感じの文章に変える↓
+ description: "Pythonの基礎から応用までを学べるチュートリアル",
+ pages: [
+ { id: 1, title: "環境構築と基本思想" },
+ { id: 2, title: "基本構文とデータ型" },
+ { id: 3, title: "リスト、タプル、辞書、セット" },
+ { id: 4, title: "制御構文と関数" },
+ { id: 5, title: "モジュールとパッケージ" },
+ { id: 6, title: "オブジェクト指向プログラミング" },
+ {
+ id: 7,
+ title: "ファイルの入出力とコンテキストマネージャ",
+ },
+ { id: 8, title: "例外処理" },
+ { id: 9, title: "ジェネレータとデコレータ" },
+ ],
+ },
+ {
+ id: "cpp",
+ lang: "C++",
+ description: "C++の基本から高度な機能までを学べるチュートリアル",
+ pages: [
+ { id: 2, title: "型システムとメモリ" },
+ { id: 3, title: "関数と参照" },
+ ],
+ },
+] as const;
diff --git a/app/sidebar.tsx b/app/sidebar.tsx
index 21b7730..3d2d81d 100644
--- a/app/sidebar.tsx
+++ b/app/sidebar.tsx
@@ -1,65 +1,60 @@
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
-import useSWR, { Fetcher } from 'swr'
+import useSWR, { Fetcher } from "swr";
import { splitMarkdown } from "./[docs_id]/splitMarkdown";
+import { pagesList } from "./pagesList";
-const fetcher: Fetcher
= (url) => fetch(url).then((r) => r.text())
+const fetcher: Fetcher = (url) =>
+ fetch(url).then((r) => r.text());
export function Sidebar() {
const pathname = usePathname();
const docs_id = pathname.replace(/^\//, "");
- const { data, error, isLoading } = useSWR(
- `/docs/${docs_id}.md`,
- fetcher
- )
+ const { data, error, isLoading } = useSWR(`/docs/${docs_id}.md`, fetcher);
- const pages = [
- { id: "python-1", title: "1. 環境構築と基本思想" },
- { id: "python-2", title: "2. 基本構文とデータ型" },
- { id: "python-3", title: "3. リスト、タプル、辞書、セット" },
- { id: "python-4", title: "4. 制御構文と関数" },
- { id: "python-5", title: "5. モジュールとパッケージ" },
- { id: "python-6", title: "6. オブジェクト指向プログラミング" },
- { id: "python-7", title: "7. ファイルの入出力とコンテキストマネージャ" },
- { id: "python-8", title: "8. 例外処理" },
- { id: "python-9", title: "9. ジェネレータとデコレータ" },
- ];
+ if (error) console.error("Sidebar fetch error:", error);
- if (error) console.error("Sidebar fetch error:", error)
-
-
-
-
- const splitmdcontent = splitMarkdown(data ?? "")
+ const splitmdcontent = splitMarkdown(data ?? "");
return (
-
+
{/* todo: 背景色ほんとにこれでいい? */}
-
+
{/* サイドバーが常時表示されている場合のみ */}
Navbar Title
-
-
- {pages.map((page) => (
- -
- {page.title}
- {page.id === docs_id && !isLoading &&(
-
- {splitmdcontent
- .slice(1)
- .map((section, idx) => (
- -
- {section.title}
-
- ))}
-
- )}
+
+ {pagesList.map((group) => (
+ -
+
+ {group.lang}
+
+ {group.pages.map((page) => (
+ -
+
+ {page.id}.
+ {page.title}
+
+ {`${group.id}-${page.id}` === docs_id && !isLoading && (
+
+ {splitmdcontent.slice(1).map((section, idx) => (
+ -
+ {section.title}
+
+ ))}
+
+ )}
+
+ ))}
+
+
))}
-
+
);
}
-
diff --git a/app/terminal/editor.tsx b/app/terminal/editor.tsx
index fdbe9bb..57d8c38 100644
--- a/app/terminal/editor.tsx
+++ b/app/terminal/editor.tsx
@@ -9,6 +9,7 @@ import "ace-builds/src-min-noconflict/theme-twilight";
import "ace-builds/src-min-noconflict/ext-language_tools";
import "ace-builds/src-min-noconflict/ext-searchbox";
import "ace-builds/src-min-noconflict/mode-python";
+import "ace-builds/src-min-noconflict/mode-c_cpp";
import "ace-builds/src-min-noconflict/mode-json";
import "ace-builds/src-min-noconflict/mode-csv";
import "ace-builds/src-min-noconflict/mode-text";
@@ -17,8 +18,11 @@ import { useSectionCode } from "../[docs_id]/section";
import clsx from "clsx";
// snippetを有効化するにはsnippetもimportする必要がある: import "ace-builds/src-min-noconflict/snippets/python";
+// mode-xxxx.js のファイル名と、AceEditorの mode プロパティの値が対応する
+export type AceLang = "python" | "c_cpp" | "json" | "csv" | "text";
+
interface EditorProps {
- language?: string;
+ language?: AceLang;
tabSize: number;
filename: string;
initContent: string;
diff --git a/app/terminal/exec.tsx b/app/terminal/exec.tsx
index 82ba51b..c6b3ee7 100644
--- a/app/terminal/exec.tsx
+++ b/app/terminal/exec.tsx
@@ -1,21 +1,34 @@
"use client";
-import chalk from "chalk";
import { usePyodide } from "./python/pyodide";
-import { clearTerminal, getRows, useTerminal } from "./terminal";
+import {
+ clearTerminal,
+ getRows,
+ hideCursor,
+ systemMessageColor,
+ useTerminal,
+} from "./terminal";
import { useSectionCode } from "../[docs_id]/section";
+import { useWandbox } from "./wandbox/wandbox";
+import { ReplOutput, writeOutput } from "./repl";
+import { useState } from "react";
+
+export type ExecLang = "python" | "cpp";
interface ExecProps {
- filename: string;
- language: string;
+ /*
+ * Pythonの場合はメインファイル1つのみを指定する。
+ * C++の場合はソースコード(.cpp)とヘッダー(.h)を全部指定し、ExecFile内で拡張子を元にソースコードと追加コードを分ける。
+ */
+ filenames: string[];
+ language: ExecLang;
content: string;
}
export function ExecFile(props: ExecProps) {
const { terminalRef, terminalInstanceRef, termReady } = useTerminal({
getRows: (cols: number) => getRows(props.content, cols) + 1,
onReady: () => {
- // カーソル非表示
- terminalInstanceRef.current!.write("\x1b[?25l");
+ hideCursor(terminalInstanceRef.current!);
for (const line of props.content.split("\n")) {
terminalInstanceRef.current!.writeln(line);
}
@@ -24,51 +37,77 @@ export function ExecFile(props: ExecProps) {
const sectionContext = useSectionCode();
const pyodide = usePyodide();
+ const wandbox = useWandbox();
+ // 表示するコマンドライン文字列
let commandline: string;
- let exec: () => Promise
| void;
+ // trueの間 (初期化しています...) と表示される
let runtimeInitializing: boolean;
+ // 初期化処理が必要な場合の関数
+ let beforeExec: (() => Promise) | null = null;
+ // 実行中です... と表示される
+ const [isExecuting, setIsExecuting] = useState(false);
+ // 実際に実行する関数
+ let exec: (() => Promise) | null = null;
switch (props.language) {
case "python":
- commandline = `python ${props.filename}`;
+ if (props.filenames.length !== 1) {
+ throw new Error("Pythonの実行にはファイル名が1つ必要です");
+ }
+ commandline = `python ${props.filenames[0]}`;
runtimeInitializing = pyodide.initializing;
- exec = async () => {
- if (!pyodide.ready) {
- clearTerminal(terminalInstanceRef.current!);
- terminalInstanceRef.current!.write(
- chalk.dim.bold.italic("(初期化しています...しばらくお待ちください)")
- );
- await pyodide.init();
- }
- clearTerminal(terminalInstanceRef.current!);
- const outputs = await pyodide.runFile(props.filename);
- for (const output of outputs) {
- // 出力内容に応じて色を変える
- const message = String(output.message).replace(/\n/g, "\r\n");
- switch (output.type) {
- case "error":
- terminalInstanceRef.current!.writeln(chalk.red(message));
- break;
- default:
- terminalInstanceRef.current!.writeln(message);
- break;
- }
- }
- sectionContext?.setExecResult(props.filename, outputs);
- };
+ beforeExec = pyodide.ready ? null : pyodide.init;
+ exec = () => pyodide.runFile(props.filenames[0]);
+ break;
+ case "cpp":
+ if (!props.filenames || props.filenames.length === 0) {
+ throw new Error("C++の実行には filenames プロパティが必要です");
+ }
+ commandline = wandbox.cppOptions
+ ? `${wandbox.cppOptions.commandline} ${props.filenames.join(" ")} && ./a.out`
+ : "";
+ runtimeInitializing = false;
+ const namesSource = props.filenames!.filter((name) =>
+ name.endsWith(".cpp")
+ );
+ const namesAdditional = props.filenames!.filter(
+ (name) => !name.endsWith(".cpp")
+ );
+ exec = () => wandbox.runFiles("C++", namesSource, namesAdditional);
break;
default:
+ props.language satisfies never;
commandline = `エラー: 非対応の言語 ${props.language}`;
runtimeInitializing = false;
- exec = () => undefined;
break;
}
+
+ const onClick = async () => {
+ if (exec) {
+ if (beforeExec) {
+ clearTerminal(terminalInstanceRef.current!);
+ terminalInstanceRef.current!.write(
+ systemMessageColor("(初期化しています...しばらくお待ちください)")
+ );
+ await beforeExec();
+ }
+ clearTerminal(terminalInstanceRef.current!);
+ terminalInstanceRef.current!.write(systemMessageColor("実行中です..."));
+ setIsExecuting(true);
+ const outputs = await exec();
+ setIsExecuting(false);
+ clearTerminal(terminalInstanceRef.current!);
+ writeOutput(terminalInstanceRef.current!, outputs, false);
+ // TODO: 1つのファイル名しか受け付けないところに無理やりコンマ区切りで全部のファイル名を突っ込んでいる
+ sectionContext?.setExecResult(props.filenames.join(","), outputs);
+ }
+ };
return (
diff --git a/app/terminal/python/page.tsx b/app/terminal/python/page.tsx
index e4f8c8b..0e7f6c1 100644
--- a/app/terminal/python/page.tsx
+++ b/app/terminal/python/page.tsx
@@ -29,7 +29,7 @@ export default function PythonPage() {
filename="main.py"
initContent="print('hello, world!')"
/>
-
+
);
}
diff --git a/app/terminal/repl.tsx b/app/terminal/repl.tsx
index ef4ae6c..7ac11f8 100644
--- a/app/terminal/repl.tsx
+++ b/app/terminal/repl.tsx
@@ -4,11 +4,19 @@ import { useCallback, useEffect, useRef } from "react";
import { highlightCodeToAnsi } from "./highlight";
import chalk from "chalk";
import { MutexInterface } from "async-mutex";
-import { clearTerminal, getRows, hideCursor, showCursor, useTerminal } from "./terminal";
+import {
+ clearTerminal,
+ getRows,
+ hideCursor,
+ showCursor,
+ systemMessageColor,
+ useTerminal,
+} from "./terminal";
import { useSectionCode } from "../[docs_id]/section";
+import { Terminal } from "@xterm/xterm";
export interface ReplOutput {
- type: "stdout" | "stderr" | "error" | "return"; // 出力の種類
+ type: "stdout" | "stderr" | "error" | "return" | "system"; // 出力の種類
message: string; // 出力メッセージ
}
export interface ReplCommand {
@@ -17,6 +25,35 @@ export interface ReplCommand {
}
export type SyntaxStatus = "complete" | "incomplete" | "invalid"; // 構文チェックの結果
+export function writeOutput(
+ term: Terminal,
+ outputs: ReplOutput[],
+ endNewLine: boolean
+) {
+ for (let i = 0; i < outputs.length; i++) {
+ const output = outputs[i];
+ if (i > 0) {
+ term.writeln("");
+ }
+ // 出力内容に応じて色を変える
+ const message = String(output.message).replace(/\n/g, "\r\n");
+ switch (output.type) {
+ case "error":
+ term.write(chalk.red(message));
+ break;
+ case "system":
+ term.write(systemMessageColor(message));
+ break;
+ default:
+ term.write(message);
+ break;
+ }
+ }
+ if (endNewLine && outputs.length > 0) {
+ term.writeln("");
+ }
+}
+
interface ReplComponentProps {
initRuntime: () => void;
runtimeInitializing: boolean;
@@ -125,18 +162,7 @@ export function ReplTerminal(props: ReplComponentProps) {
const onOutput = useCallback(
(outputs: ReplOutput[]) => {
if (terminalInstanceRef.current) {
- for (const output of outputs) {
- // 出力内容に応じて色を変える
- const message = String(output.message).replace(/\n/g, "\r\n");
- switch (output.type) {
- case "error":
- terminalInstanceRef.current.writeln(chalk.red(message));
- break;
- default:
- terminalInstanceRef.current.writeln(message);
- break;
- }
- }
+ writeOutput(terminalInstanceRef.current, outputs, true);
// 出力が終わったらプロンプトを表示
updateBuffer(() => [""]);
}
@@ -296,7 +322,7 @@ export function ReplTerminal(props: ReplComponentProps) {
initRuntime();
hideCursor(terminalInstanceRef.current);
terminalInstanceRef.current.write(
- chalk.dim.bold.italic(
+ systemMessageColor(
"(初期化しています...しばらくお待ちください)"
)
);
diff --git a/app/terminal/terminal.tsx b/app/terminal/terminal.tsx
index fc533c5..0c019de 100644
--- a/app/terminal/terminal.tsx
+++ b/app/terminal/terminal.tsx
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react";
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import "@xterm/xterm/css/xterm.css";
+import chalk from "chalk";
/**
* 文字列の幅を計算する。
@@ -49,6 +50,8 @@ export function showCursor(term: Terminal) {
term.write("\x1b[?25h");
}
+export const systemMessageColor = chalk.blue.bold.italic;
+
interface TerminalProps {
getRows?: (cols: number) => number;
onReady?: () => void;
diff --git a/app/terminal/wandbox/page.tsx b/app/terminal/wandbox/page.tsx
new file mode 100644
index 0000000..d3a201e
--- /dev/null
+++ b/app/terminal/wandbox/page.tsx
@@ -0,0 +1,34 @@
+"use client";
+
+import { EditorComponent } from "../editor";
+import { ExecFile } from "../exec";
+
+export default function WandboxPage() {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/app/terminal/wandbox/wandbox.tsx b/app/terminal/wandbox/wandbox.tsx
new file mode 100644
index 0000000..70fbe76
--- /dev/null
+++ b/app/terminal/wandbox/wandbox.tsx
@@ -0,0 +1,306 @@
+"use client";
+
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useMemo,
+} from "react";
+import { ReplOutput } from "../repl";
+import { useFile } from "../file";
+import useSWR, { Fetcher } from "swr";
+
+type WandboxLang = "C++";
+
+interface IWandboxContext {
+ // filesの中から、namesSourceで指定されたファイルをソースコードとして、namesAdditionalで指定されたファイルを追加コードとして渡して実行する
+ runFiles: (
+ lang: WandboxLang,
+ namesSource: string[],
+ namesAdditional: string[]
+ ) => Promise;
+ cppOptions: WandboxOptions | null;
+}
+interface WandboxOptions {
+ compilerName: string;
+ compilerOptions: string[];
+ commandline: string;
+}
+
+const WandboxContext = createContext(null!);
+export function useWandbox() {
+ const context = useContext(WandboxContext);
+ if (!context) {
+ throw new Error("useWandbox must be used within a WandboxProvider");
+ }
+ return context;
+}
+
+const WANDBOX = "https://wandbox.org";
+// https://github.com/melpon/wandbox/blob/ajax/kennel2/API.rst <- 古いけど、説明と例がある
+// https://github.com/melpon/wandbox/blob/master/feline/src/types.rs
+/* RustのVecはバイト配列ですが、serialize_with = "serialize_utf8"という指定があるため、
+JSONにシリアライズされる際にはUTF-8文字列に変換されると解釈し、TypeScriptの型はstringとします。
+by gemini
+*/
+export interface SwitchOption {
+ name: string;
+ "display-flags": string;
+ "display-name": string;
+}
+export interface SwitchSingle {
+ type: "single";
+ name: string;
+ "display-name": string;
+ "display-flags": string;
+ default: boolean;
+}
+export interface SwitchSelect {
+ type: "select";
+ name: string;
+ options: SwitchOption[];
+ default: string;
+}
+/**
+ * Rustの 'Switch' enum に対応するディスクリミネேテッドユニオン型です。
+ * 'type' プロパティの値によって `SwitchSingle` か `SwitchSelect` かを判別できます。
+ */
+export type Switch = SwitchSingle | SwitchSelect;
+export interface CompilerInfo {
+ name: string;
+ version: string;
+ language: string;
+ "display-name": string;
+ templates: string[];
+ "compiler-option-raw": boolean;
+ "runtime-option-raw": boolean;
+ "display-compile-command": string;
+ switches: Switch[];
+}
+interface Code {
+ file: string;
+ code: string;
+}
+interface CompileParameter {
+ compiler: string;
+ code: string;
+ codes?: Code[];
+ options?: string;
+ stdin?: string;
+ "compiler-option-raw"?: string;
+ "runtime-option-raw"?: string;
+ github_user?: string;
+ title?: string;
+ description?: string;
+ save?: boolean;
+ created_at?: number;
+ is_private?: boolean;
+ "compiler-info"?: CompilerInfo;
+}
+interface CompileResult {
+ status: string;
+ signal: string;
+ compiler_output: string;
+ compiler_error: string;
+ compiler_message: string;
+ program_output: string;
+ program_error: string;
+ program_message: string;
+ permlink: string;
+ url: string;
+}
+
+const compilerInfoFetcher: Fetcher = () =>
+ fetch(new URL("/api/list.json", WANDBOX)).then(
+ (res) => res.json() as Promise
+ );
+
+export function WandboxProvider({ children }: { children: ReactNode }) {
+ const { files } = useFile();
+ const { data: compilerList, error } = useSWR("list", compilerInfoFetcher);
+ if (error) {
+ console.error("Failed to fetch compiler list from Wandbox:", error);
+ }
+ const cppOptions = useMemo(() => {
+ if (!compilerList) {
+ return null;
+ }
+ const compilerListForLang = compilerList?.filter(
+ (c) => c.language === "C++"
+ );
+ const compilerOptions: string[] = [];
+ const commandlineArgs: string[] = [];
+
+ // headでない最初のgccを使う
+ const selectedCompiler = compilerListForLang.find(
+ (c) => c.name.includes("gcc") && !c.name.includes("head")
+ );
+ if (!selectedCompiler) {
+ throw new Error("compiler not found");
+ }
+ const compilerName = selectedCompiler.name;
+ // commandlineArgs.push(selectedCompiler["display-compile-command"]);
+ commandlineArgs.push("g++");
+
+ // singleオプション:
+ const warningSwitch = selectedCompiler.switches.find(
+ (s) => s.name === "warning"
+ );
+ if (warningSwitch && warningSwitch.type === "single") {
+ compilerOptions.push("warning");
+ commandlineArgs.push(warningSwitch["display-flags"]);
+ } else {
+ console.warn("warning switch not found");
+ }
+
+ // selectオプション:
+ for (const switchSelect of selectedCompiler.switches.filter(
+ (s) => s.type === "select"
+ )) {
+ // boostはnothing、stdは最新を選ぶ ほかはデフォルト
+ if (switchSelect.name.includes("boost")) {
+ const boostNothingOption = switchSelect.options.find((o) =>
+ o.name.includes("nothing")
+ );
+ if (boostNothingOption) {
+ compilerOptions.push(boostNothingOption.name);
+ commandlineArgs.push(boostNothingOption["display-flags"]);
+ } else {
+ console.warn("boost nothing option not found");
+ }
+ } else if (switchSelect.name.includes("std")) {
+ const stdLatestOption = switchSelect.options
+ .filter((o) => o.name.startsWith("c++"))
+ .sort()
+ .reverse()[0];
+ if (stdLatestOption) {
+ compilerOptions.push(stdLatestOption.name);
+ commandlineArgs.push(stdLatestOption["display-flags"]);
+ } else {
+ console.warn("std option not found");
+ }
+ } else {
+ const defaultOption = switchSelect.options.find(
+ (o) => o.name === switchSelect.default
+ );
+ compilerOptions.push(switchSelect.default);
+ commandlineArgs.push(defaultOption!["display-flags"]);
+ }
+ }
+
+ return {
+ compilerName,
+ compilerOptions,
+ commandline: commandlineArgs.join(" "),
+ } satisfies WandboxOptions;
+ }, [compilerList]);
+
+ const runFiles = useCallback(
+ async (
+ lang: WandboxLang,
+ namesSource: string[],
+ namesAdditional: string[]
+ ) => {
+ let options: WandboxOptions | null;
+ switch (lang) {
+ case "C++":
+ options = cppOptions;
+ break;
+ default:
+ return [
+ {
+ type: "error" as const,
+ message: `Unsupported language: ${lang}`,
+ },
+ ];
+ }
+ if (!options) {
+ return [
+ { type: "error" as const, message: "Wandbox is not ready yet." },
+ ];
+ }
+ const result: CompileResult = await fetch(
+ new URL("/api/compile.json", WANDBOX),
+ {
+ method: "post",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ compiler: options.compilerName,
+ code: "",
+ codes: namesSource
+ .map((name) => ({
+ file: name,
+ code: files[name] || "",
+ }))
+ .concat(
+ namesAdditional.map((name) => ({
+ file: name,
+ code: files[name] || "",
+ }))
+ ),
+ options: options.compilerOptions.join(","),
+ stdin: "",
+ "compiler-option-raw": namesSource.join("\n"),
+ "runtime-option-raw": "",
+ save: false,
+ is_private: true,
+ } satisfies CompileParameter),
+ }
+ ).then((res) => res.json());
+
+ let outputs: ReplOutput[] = [];
+ if (result.compiler_output) {
+ outputs = outputs.concat(
+ result.compiler_output
+ .trim()
+ .split("\n")
+ .map((line) => ({ type: "stdout" as const, message: line }))
+ );
+ }
+ if (result.compiler_error) {
+ outputs = outputs.concat(
+ result.compiler_error
+ .trim()
+ .split("\n")
+ .map((line) => ({ type: "error" as const, message: line }))
+ );
+ }
+ if (result.program_output) {
+ outputs = outputs.concat(
+ result.program_output
+ .trim()
+ .split("\n")
+ .map((line) => ({ type: "stdout" as const, message: line }))
+ );
+ }
+ if (result.program_error) {
+ outputs = outputs.concat(
+ result.program_error
+ .trim()
+ .split("\n")
+ .map((line) => ({ type: "error" as const, message: line }))
+ );
+ }
+ if (result.status !== "0") {
+ outputs.push({
+ type: "system" as const,
+ message: `ステータス ${result.status} で異常終了しました`,
+ });
+ }
+ // TODO: result.signal はいつ使われるのか?
+
+ console.log(outputs);
+ return outputs;
+ },
+ [files, cppOptions]
+ );
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/public/docs/cpp-2.md b/public/docs/cpp-2.md
new file mode 100644
index 0000000..74001ed
--- /dev/null
+++ b/public/docs/cpp-2.md
@@ -0,0 +1,283 @@
+# 第2章: C++の型システムとメモリ
+
+C++は**静的型付け言語**です。これは、コンパイル時にすべての変数の型が決定され、一度決まった型は変更できないことを意味します。この厳密な型システムは、一見すると面倒に感じるかもしれませんが、大規模なプログラムでもバグを未然に防ぎ、高いパフォーマンスを引き出すための重要な仕組みです。
+
+この章では、C++の基本的な型と、他の高級言語ではあまり意識することのない「メモリ」との関係について学んでいきましょう。
+
+## 基本データ型
+
+他の多くの言語と同様に、C++にも数値を扱うための基本的なデータ型が用意されています。すでにご存知のものが多いと思いますが、C++における特徴と合わせて再確認しましょう。
+
+| 型 (Type) | 説明 (Description) | サイズの例 (Typical Size) | 値の範囲の例 (Example Range) |
+| :---------------- | :----------------------------------------------- | :---------------------- | :------------------------------------------------------- |
+| `int` | 整数を格納します (Integer) | 4 bytes | `-2,147,483,648` ~ `2,147,483,647` |
+| `double` | 倍精度浮動小数点数を格納します (Double-precision float) | 8 bytes | 約 `±1.7E308` (有効数字15桁程度) |
+| `char` | 1文字を格納します (Character) | 1 byte | `-128` ~ `127` または `0` ~ `255` |
+| `bool` | 真偽値を格納します (Boolean) | 1 byte | `true` または `false` |
+
+**ポイント**: C++の規格では、`int`が何バイトであるかといったサイズを厳密には定めていません。環境(OSやCPUアーキテクチャ)によって変わる可能性があります。しかし、多くのモダンな環境では上記のサイズが一般的です。
+
+### 変数の宣言・代入・初期化
+
+変数は、値を入れておくための「名前付きの箱」のようなものです。C++で変数を使うには、まず「どのような種類の箱(**型**)を、どんな名前で用意するか」をコンピュータに伝える必要があります。これを**宣言 (Declaration)** と呼びます。
+
+```cpp
+// 整数を入れるための'age'という名前の箱を宣言
+int age;
+```
+
+宣言した変数に値を入れることを**代入 (Assignment)** と言います。代入には `=` 記号を使います。
+
+```cpp
+// 宣言済みの変数 'age' に 30 を代入
+age = 30;
+```
+
+多くの場合、宣言と代入は同時に行います。これを**初期化 (Initialization)** と呼び、こちらの書き方が一般的で安全です。
+
+```cpp:data_types.cpp
+#include
+
+int main() {
+ // 宣言と同時に初期化
+ int age = 30;
+ double pi = 3.14159;
+ char initial = 'A';
+ bool is_student = true;
+
+ std::cout << "Age: " << age << std::endl;
+ std::cout << "Pi: " << pi << std::endl;
+ std::cout << "Initial: " << initial << std::endl;
+ std::cout << "Is student? " << is_student << std::endl; // boolは通常 1 (true) または 0 (false) として出力される
+
+ return 0;
+}
+```
+
+```cpp-exec:data_types.cpp
+Age: 30
+Pi: 3.14159
+Initial: A
+Is student? 1
+```
+
+## 基本的な演算
+
+C++では、数値型の変数を使って基本的な算術計算ができます。
+
+| 演算子 | 意味 | 例 | 結果 |
+|:---:|:---|:---|:---:|
+| `+` | 加算 | `5 + 2` | `7` |
+| `-` | 減算 | `5 - 2` | `3` |
+| `*` | 乗算 | `5 * 2` | `10` |
+| `/` | 除算 | `5 / 2` | `2` |
+| `%` | 剰余 | `5 % 2` | `1` |
+
+### ⚠️ 整数除算の注意点
+
+ここで特に注意が必要なのが `/` (除算) です。**整数 (`int`) 同士の割り算の結果は、小数点以下が切り捨てられ、整数 (`int`) になります。**
+
+```cpp:integer_division.cpp
+#include
+
+int main() {
+ int a = 7;
+ int b = 2;
+
+ std::cout << "7 / 2 = " << a / b << std::endl;
+
+ // 正しい計算結果(浮動小数点数)を得るには?
+ // 演算する値の少なくとも一方が浮動小数点数型である必要があります。
+ double c = 7.0;
+ std::cout << "7.0 / 2 = " << c / b << std::endl;
+
+ return 0;
+}
+```
+
+```cpp-exec:integer_division.cpp
+7 / 2 = 3
+7.0 / 2 = 3.5
+```
+
+`7 / 2` が `3` になってしまうのは、`int` 型の `a` と `int` 型の `b` で演算した結果もまた `int` 型になる、というC++のルールのためです。小数点以下の値を得たい場合は、`7.0` のように、どちらかの値を `double` などの浮動小数点数型にする必要があります。
+
+## 型を厳密に扱う
+
+静的型付けの恩恵を最大限に受けるために、C++には型をより安全かつ便利に扱うための仕組みがあります。
+
+### `const`による不変性の保証
+
+`const` (constantの略) は、変数を**読み取り専用**にするためのキーワードです。一度`const`で初期化された変数の値は、後から変更しようとするとコンパイルエラーになります。
+
+なぜ`const`が重要なのでしょうか?
+
+ * **安全性の向上**: 変更されるべきでない値を誤って変更してしまうバグを防ぎます。
+ * **意図の明確化**: プログラムを読む人に対して、「この値は変わらない」という意図を明確に伝えられます。
+
+円周率のように、プログラム中で決して変わることのない値に`const`を使うのが典型的な例です。
+
+```cpp:const_example.cpp
+#include
+
+int main() {
+ const double PI = 3.14159;
+ int radius = 5;
+
+ double area = PI * radius * radius;
+ std::cout << "Area: " << area << std::endl;
+
+ // PI = 3.14; // この行はコンパイルエラーになる!
+
+ return 0;
+}
+```
+```cpp-exec:const_example.cpp
+Area: 78.5397
+```
+
+### `auto`による型推論
+
+C++11から導入された`auto`キーワードを使うと、コンパイラが初期化式から変数の型を自動で推論してくれます。これにより、特に型名が長い場合にコードを簡潔に書くことができます。
+
+```cpp
+// autoを使わない場合
+std::vector::iterator it = my_vector.begin();
+
+// autoを使う場合
+auto it = my_vector.begin(); // コンパイラが it の型を std::vector::iterator と推論してくれる
+```
+
+ただし、`auto`はあくまで「型を書く手間を省く」ものであり、変数が型を持たないわけではありません(動的型付け言語とは異なります)。初期化と同時に使う必要があり、型が明確な場面で適切に使うことが推奨されます。
+
+```cpp
+auto x = 10; // x は int型になる
+auto y = 3.14; // y は double型になる
+auto z = "hello"; // z は const char* (C言語スタイルの文字列) になるので注意
+```
+
+## C++の文字列: `std::string`
+
+C言語では文字列を`char`の配列(`char*`)として扱いましたが、これは扱いにくく、バグの温床でした。モダンC++では、**`std::string`** クラスを使うのが標準的です。`std::string`は、文字列の連結、長さの取得、部分文字列の取り出しといった操作を安全かつ簡単に行うための豊富な機能を提供します。
+
+`std::string`を使うには、``ヘッダをインクルードする必要があります。
+
+```cpp:string_example.cpp
+#include
+#include // std::string を使うために必要
+
+int main() {
+ // 文字列の宣言と初期化
+ std::string greeting = "Hello";
+
+ // 文字列の連結
+ std::string name = "C++";
+ std::string message = greeting + ", " + name + "!";
+
+ std::cout << message << std::endl;
+
+ // 文字列の長さを取得
+ std::cout << "Length: " << message.length() << std::endl;
+
+ return 0;
+}
+```
+
+```cpp-exec:string_example.cpp
+Hello, C++!
+Length: 11
+```
+
+## 変数とメモリ
+
+さて、C++を深く理解する上で避けて通れないのが**メモリ**の概念です。変数を宣言すると、コンピュータのメモリ上にその型に応じたサイズの領域が確保されます。
+
+例えば、`int x = 10;` と書くと、
+
+1. コンパイラは`int`型に必要なメモリサイズ(例: 4バイト)を判断します。
+2. プログラム実行時、メモリ上のどこかに4バイトの領域が確保されます。
+3. その領域に`x`という名前が割り当てられ、値として`10`が格納(バイナリ形式で書き込み)されます。
+
+この「メモリ上のどこか」を示すのが**メモリアドレス**(単にアドレスとも)です。アドレスは、メモリ上の各バイトに割り振られた通し番号のようなもので、通常は16進数で表現されます。
+
+変数名の前に`&`(アドレス演算子)を付けることで、その変数が格納されているメモリアドレスを知ることができます。
+
+```cpp:memory_address.cpp
+#include
+#include
+
+int main() {
+ int age = 30;
+ double pi = 3.14;
+ std::string name = "Alice";
+
+ std::cout << "変数 'age' の値: " << age << std::endl;
+ std::cout << "変数 'age' のメモリアドレス: " << &age << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "変数 'pi' の値: " << pi << std::endl;
+ std::cout << "変数 'pi' のメモリアドレス: " << &pi << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "変数 'name' の値: " << name << std::endl;
+ std::cout << "変数 'name' のメモリアドレス: " << &name << std::endl;
+
+ return 0;
+}
+```
+```cpp-exec:memory_address.cpp
+変数 'age' の値: 30
+変数 'age' のメモリアドレス: 0x7ffee3b8c9ac
+
+変数 'pi' の値: 3.14
+変数 'pi' のメモリアドレス: 0x7ffee3b8c9a0
+
+変数 'name' の値: Alice
+変数 'name' のメモリアドレス: 0x7ffee3b8c990
+```
+
+このコードを実行すると、`0x7ffee...` のようなアドレスが表示されるはずです(値は実行のたびに変わります)。今は「変数はメモリ上の特定の場所に、特定のサイズで存在している」というイメージを持つことが重要です。この概念は、第4章で学ぶポインタを理解するための基礎となります。
+
+## この章のまとめ
+
+ * C++は**静的型付け言語**であり、コンパイル時にすべての変数の型が決まる。
+ * `int`, `double`, `char`, `bool` といった基本的なデータ型が存在する。
+ * 変数は**宣言**してから使い、宣言と同時に値を代入する**初期化**が一般的。
+ * 基本的な**四則演算**ができるが、**整数同士の除算**は結果が整数に切り捨てられる点に注意。
+ * **`const`** を使うことで、変数を不変にし、プログラムの安全性を高めることができる。
+ * **`auto`** を使うことで、コンパイラに型を推論させ、コードを簡潔に書くことができる。
+ * モダンC++では、文字列は\*\*`std::string`\*\* クラスを使って安全かつ便利に扱う。
+ * 宣言された変数は、メモリ上の特定の**アドレス**に、その型に応じた**サイズ**の領域を確保して格納される。
+
+### 練習問題1
+
+あなたの名前(`std::string`)、年齢(`int`)、視力(`double`)をそれぞれ変数として宣言し、コンソールに出力するプログラムを書いてください。ただし、名前は一度決めたら変わらないものとして、`const`を使って宣言してください。
+
+```cpp:practice2_1.cpp
+#include
+#include
+
+int main() {
+
+}
+```
+
+```cpp-exec:practice2_1.cpp
+```
+
+
+### 練習問題2
+
+2つの`std::string`変数 `firstName` と `lastName` を宣言し、あなたの姓名で初期化してください。その後、これら2つの変数を連結してフルネームを`fullName`という新しい変数に格納し、そのフルネームと文字数(長さ)をコンソールに出力するプログラムを書いてください。
+
+```cpp:practice2_2.cpp
+#include
+#include
+
+int main() {
+
+}
+```
+
+```cpp-exec:practice2_2.cpp
+```
diff --git a/public/docs/cpp-3.md b/public/docs/cpp-3.md
new file mode 100644
index 0000000..637f33c
--- /dev/null
+++ b/public/docs/cpp-3.md
@@ -0,0 +1,334 @@
+# 第3章: 関数と参照
+
+プログラムを構成する基本的な部品である「関数」について、C++ならではの引数の渡し方や便利な機能を学びます。他の言語で関数に慣れている方も、C++特有の概念である「参照」は特に重要なので、しっかり理解していきましょう。
+
+## 関数の基本: 宣言と定義の分離
+
+プログラム内の特定のタスクを実行するコードのまとまりを「**関数**」と呼びます。C++では、この関数を利用する前に、コンパイラがその関数の存在と使い方を知っている必要があります。そのため、「**宣言 (declaration)**」と「**定義 (definition)**」という2つの概念が重要になります。
+
+ * **宣言 (Declaration)**: 関数の使い方(名前、引数、戻り値)をコンパイラに教える。本体の処理はない。
+ * **定義 (Definition)**: 関数の具体的な処理内容を記述する。
+
+### 関数の宣言
+
+宣言の基本的な文法は以下の通りです。
+
+```
+戻り値の型 関数名(引数の型1 引数名1, 引数の型2 引数名2, ...);
+```
+
+ * **戻り値の型 (Return Type)**: 関数が処理を終えた後に返す値の型です。例えば、`int`型なら整数値を返します。
+ * **関数名 (Function Name)**: 関数を呼び出すときに使う名前です。
+ * **引数リスト (Parameter List)**: 関数が処理のために受け取る値です。`()`の中に、`型名 変数名`のペアをコンマで区切って記述します。引数が必要ない場合は `()` の中を空にします。
+ * **セミコロン (`;`)**: 宣言の最後には必ずセミコロンを付けます。
+
+### 戻り値がない場合: `void`型
+
+関数が何も値を返す必要がない場合もあります。例えば、「画面にメッセージを表示するだけ」といった関数です。その場合、戻り値の型として `void` という特別なキーワードを使います。
+
+```cpp
+void printMessage(std::string message);
+```
+
+第2章で学んだように、`int`や`double`などの型は変数を定義するために使えましたが、`void`は「型がない」ことを示す特殊な型なので、`void my_variable;` のように変数を定義することはできません。あくまで関数の戻り値の型としてのみ使います。
+
+### コンパイラは上から順に読む
+
+C++のコンパイラはソースコードを上から下へと順番に読み込んでいきます。そのため、`main`関数のような場所で別の関数を呼び出すコードに出会ったとき、コンパイラはその時点ですでに関数の「宣言」または「定義」を読み込んでいる必要があります。
+
+つまり、**`main`関数よりも上(前)に、呼び出す関数の定義か宣言のどちらかが書かれていなければコンパイルエラー**になります。
+
+コードを整理するため、一般的には`main`関数の前に関数の「宣言」だけを記述し、`main`関数の後(または別のファイル)に具体的な処理内容である「定義」を記述するスタイルがよく使われます。
+
+以下の例で確認してみましょう。
+
+```cpp:declaration_definition.cpp
+#include
+#include
+
+// 1. 関数の「宣言」(プロトタイプ宣言)
+// これにより、main関数の中で greet や add を使ってもコンパイラはエラーを出さない。
+void greet(std::string name); // 戻り値がない関数の宣言
+int add(int a, int b); // int型の値を返す関数の宣言
+
+// main関数: プログラムの開始点
+int main() {
+ // 宣言があるので、これらの関数を呼び出すことができる
+ greet("Taro");
+
+ int result = add(5, 3);
+ std::cout << "5 + 3 = " << result << std::endl;
+
+ return 0;
+}
+
+// 2. 関数の「定義」(本体の実装)
+// 実際の処理はここに書く。
+void greet(std::string name) {
+ std::cout << "Hello, " << name << "!" << std::endl;
+}
+
+int add(int a, int b) {
+ return a + b;
+}
+```
+
+```cpp-exec:declaration_definition.cpp
+Hello, Taro!
+5 + 3 = 8
+```
+
+この例では、`main`関数が始まる前に`greet`関数と`add`関数の宣言をしています。これにより、`main`関数内でこれらの関数を自由な順序で呼び出すことができ、コードの可読性が向上します。関数の具体的な実装は`main`関数の後にまとめて記述することで、「プログラムの全体的な流れ(`main`)」と「各部分の具体的な処理(関数の定義)」を分離して考えることができます。
+
+## 引数の渡し方
+
+C++の関数の引数の渡し方には、主に **「値渡し」「ポインタ渡し」「参照渡し」** の3つがあります。ここでは特にC++特有の「参照渡し」に注目します。
+
+### 値渡し (Pass by Value)
+
+引数に渡された値が**コピー**されて、関数内のローカル変数として扱われます。関数内でその値を変更しても、呼び出し元の変数は影響を受けません。これは多くの言語で標準的な引数の渡し方です。
+
+```cpp:pass_by_value.cpp
+#include
+
+void tryToChange(int x) {
+ x = 100; // 関数内のコピーが変更されるだけ
+ std::cout << "Inside function: x = " << x << std::endl;
+}
+
+int main() {
+ int my_number = 10;
+ std::cout << "Before function call: my_number = " << my_number << std::endl;
+ tryToChange(my_number);
+ std::cout << "After function call: my_number = " << my_number << std::endl; // 10のまま変わらない
+ return 0;
+}
+```
+
+```cpp-exec:pass_by_value.cpp
+Before function call: my_number = 10
+Inside function: x = 100
+After function call: my_number = 10
+```
+
+ * **長所**: 呼び出し元の変数が不用意に書き換えられることがなく、安全です。
+ * **短所**: 大きなオブジェクト(例えば、たくさんの要素を持つ `std::vector` など)を渡すと、コピーのコストが無視できなくなり、パフォーマンスが低下する可能性があります。
+
+### ポインタ渡し (Pass by Pointer)
+
+これはC言語から引き継がれた伝統的な方法で、変数のメモリアドレスを渡します。ポインタ(アドレスを指し示す変数)を介して、呼び出し元の変数を直接変更できます。詳細は第4章で詳しく学びますが、ここでは簡単に紹介します。
+
+```cpp:pass_by_pointer.cpp
+#include
+
+// ポインタを受け取るには、型名の後にアスタリスク * を付ける
+void changeWithPointer(int* ptr) {
+ *ptr = 100; // アスタリスク * でポインタが指す先の値にアクセス
+}
+
+int main() {
+ int my_number = 10;
+ // 変数のアドレスを渡すには、アンパサンド & を付ける
+ changeWithPointer(&my_number);
+ std::cout << "After function call: my_number = " << my_number << std::endl; // 100に変わる
+ return 0;
+}
+```
+
+```cpp-exec:pass_by_pointer.cpp
+After function call: my_number = 100
+```
+
+ポインタは強力ですが、`nullptr`(どこも指していないポインタ)の可能性を考慮する必要があるなど、扱いが少し複雑です。
+
+### 参照渡し (Pass by Reference)
+
+C++の大きな特徴の一つが**参照 (Reference)** です。参照は、既存の変数に**別名**を付ける機能と考えることができます。。
+
+関数に参照を渡すと、値のコピーは発生せず、関数内の引数は呼び出し元の変数の「別名」として振る舞います。そのため、関数内での操作が呼び出し元の変数に直接反映されます。構文もポインタよりずっとシンプルです。
+
+```cpp:pass_by_reference.cpp
+#include
+
+// 参照を受け取るには、型名の後にアンパサンド & を付ける
+void changeWithReference(int& ref) {
+ ref = 100; // 通常の変数と同じように扱うだけ
+}
+
+int main() {
+ int my_number = 10;
+ changeWithReference(my_number); // 呼び出し側は特別な記号は不要
+ std::cout << "After function call: my_number = " << my_number << std::endl; // 100に変わる
+ return 0;
+}
+```
+
+```cpp-exec:pass_by_reference.cpp
+After function call: my_number = 100
+```
+
+
+ * **長所**: コピーが発生しないため効率的です。また、構文がシンプルで、呼び出し元の変数を変更する意図が明確になります。
+ * **注意点**: 関数内で値を変更できるため、意図しない書き換えに注意が必要です。
+
+#### `const`参照: 効率と安全性の両立
+
+「大きなオブジェクトを渡したいけど、コピーは避けたい。でも関数内で値を変更されたくはない」という場合に最適なのが **`const`参照** です。
+
+```cpp:const_reference.cpp
+#include
+#include
+
+// const参照で受け取ることで、コピーを防ぎつつ、
+// messageが関数内で変更されないことを保証する
+void printMessage(const std::string& message) {
+ // message = "changed!"; // この行はコンパイルエラーになる!
+ std::cout << message << std::endl;
+}
+
+int main() {
+ std::string greeting = "Hello, C++ world! This is a long string.";
+ printMessage(greeting);
+ return 0;
+}
+```
+
+```cpp-exec:const_reference.cpp
+Hello, C++ world! This is a long string.
+```
+
+**C++のベストプラクティス**:
+
+ * `int`や`double`などの小さな基本型は**値渡し**。
+ * 関数内で引数を**変更する必要がある**場合は**参照渡し (`&`)**。
+ * 大きなオブジェクトを渡すが**変更はしない**場合は **`const`参照 (`const &`)** を使う。
+
+## 関数のオーバーロード
+
+C++では、**同じ名前で引数の型や個数が異なる関数を複数定義**できます。これを**オーバーロード (Overload)** と呼びます。コンパイラは、関数呼び出し時の引数の型や個数を見て、どの関数を呼び出すべきかを自動的に判断してくれます。
+
+```cpp:overloading.cpp
+#include
+#include
+
+// int型の引数を1つ取るprint関数
+void print(int value) {
+ std::cout << "Integer: " << value << std::endl;
+}
+
+// string型の引数を1つ取るprint関数
+void print(const std::string& value) {
+ std::cout << "String: " << value << std::endl;
+}
+
+// double型とint型の引数を取るprint関数
+void print(double d_val, int i_val) {
+ std::cout << "Double: " << d_val << ", Integer: " << i_val << std::endl;
+}
+
+int main() {
+ print(123);
+ print("hello");
+ print(3.14, 42);
+ return 0;
+}
+```
+
+```cpp-exec:overloading.cpp
+Integer: 123
+String: hello
+Double: 3.14, Integer: 42
+```
+
+これにより、`printInt`, `printDouble` のように別々の名前を付ける必要がなくなり、コードが直感的で読みやすくなります。
+
+注意点として、戻り値の型が違うだけではオーバーロードはできません。あくまで引数のリストが異なる必要があります。
+
+## デフォルト引数
+
+関数の引数に、あらかじめ**デフォルト値**を設定しておくことができます。これにより、関数を呼び出す際に該当する引数を省略できるようになります。
+
+デフォルト引数は、引数リストの**右側**から設定する必要があります。一度デフォルト引数を設定したら、それより右側にある引数もすべてデフォルト引数を持たなければなりません。
+
+```cpp:default_arguments.cpp
+#include
+#include
+
+// 第2引数 greeting にデフォルト値を設定
+void greet(const std::string& name, const std::string& greeting = "Hello") {
+ std::cout << greeting << ", " << name << "!" << std::endl;
+}
+
+int main() {
+ // 第2引数を省略。デフォルト値 "Hello" が使われる
+ greet("Alice");
+
+ // 第2引数を指定。指定した値 "Hi" が使われる
+ greet("Bob", "Hi");
+
+ return 0;
+}
+```
+
+```cpp-exec:default_arguments.cpp
+Hello, Alice!
+Hi, Bob!
+```
+
+## この章のまとめ
+
+この章では、C++の関数に関する基本的ながらも重要な機能を学びました。
+
+ * **関数の宣言と定義の分離**: プログラムの構造を整理し、分割コンパイルを可能にするための基本です。
+ * **引数の渡し方**:
+ * **値渡し**: 引数のコピーを作成し、元の変数を保護します。
+ * **参照渡し (`&`)**: 変数の「別名」を渡し、コピーのコストをなくします。呼び出し元の変数を変更するため、または効率化のために使います。
+ * **`const`参照渡し (`const&`)**: 効率的でありながら、意図しない変更を防ぐためのC++の定石です。
+ * **関数のオーバーロード**: 同じ名前で引数リストの異なる関数を定義でき、文脈に応じた適切な関数が自動で選ばれます。
+ * **デフォルト引数**: 関数の引数を省略可能にし、柔軟な関数呼び出しを実現します。
+
+特に「参照」は、この先のC++プログラミングで頻繁に登場する極めて重要な概念です。値渡しとの違い、そして`const`参照との使い分けをしっかりマスターしましょう。
+
+### 練習問題1: 値の交換
+
+2つの`int`型変数の値を交換する関数 `swap` を作成してください。この関数は、呼び出し元の変数の値を直接変更できるように、**参照渡し**を使って実装してください。
+
+```cpp:practice3_1.cpp
+#include
+
+// ここにswap関数を実装してください
+
+
+// main関数
+int main() {
+ int a = 10;
+ int b = 20;
+ std::cout << "Before: a = " << a << ", b = " << b << std::endl;
+ swap(a, b);
+ std::cout << "After: a = " << a << ", b = " << b << std::endl;
+ return 0;
+}
+```
+
+```cpp-exec:practice3_1.cpp
+(期待される実行結果)
+Before: a = 10, b = 20
+After: a = 20, b = 10
+```
+
+### 問題2: 図形の面積
+
+**関数のオーバーロード**を使い、正方形と長方形の面積を計算する `calculate_area` という名前の関数を実装してください。
+
+1. 引数が1つ (`int side`) の場合は、正方形の面積 (side✕side) を計算して返す。
+2. 引数が2つ (`int width`, `int height`) の場合は、長方形の面積 (width✕height) を計算して返す。
+
+作成した関数を`main`関数から呼び出し、結果が正しく表示されることを確認してください。
+
+```cpp:practice3_2.cpp
+#include
+
+```
+
+```cpp-exec:practice3_2.cpp
+```