配列でマップ
0 = 床、1 = 壁 の int[,] を用意し、char のマップへ変換する。
配列と番兵だけで
2次元配列でマップを作り、外側を1マス「番兵」で囲む。それだけで、範囲チェックを一切書かずに @ が壁に当たって止まる。コンソールで動く、小さな C# プログラムです。
dotnet run
0 = 床、1 = 壁 の int[,] を用意し、char のマップへ変換する。
マップの外側を1マス壁で囲む。境界チェックの書き忘れが構造的に消える。
Console.ReadKey で矢印キー(4方向)とテンキー(8方向)を読む。
// ============================================================
// Program.cs — C# 学習用お手本
// 「@マークを歩き回らせるだけ」の小さなプログラム
//
// 学べること
// 1. 2次元配列でマップを作る
// 2. 番兵(sentinel)で端の判定を消す
// → 添字が範囲外になる心配がなくなる
// 3. while ループ + キー入力(矢印キー / テンキー)
// 4. メソッドに分ける(描画 / 入力 / 移動)
//
// 実行方法は同じフォルダの README.md を見てください。
// ============================================================
using System;
class Program
{
// 番兵=マップの外側を1マス囲む「壁」。
// 外へ出ようとしたら必ずこの壁に当たるので、
// 「x が 0 より小さいか?」のような範囲チェックを書かなくて済む。
const char Wall = '#'; // 壁(番兵もこれで描く)
const char Floor = '.'; // 床
const char Player = '@'; // プレイヤー
static void Main()
{
// --- (1) マップ本体(内側だけ) ---
// 0 = 床, 1 = 壁。あとで番兵つきの char マップへ変換する。
int[,] inner =
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 1, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 1, 1, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
// --- (2) 番兵つきマップに変換 ---
char[,] map = WithSentinel(inner);
// プレイヤーの座標(内側だけの座標。描くときに番兵の分 +1 する)
int px = 2;
int py = 2;
Console.CursorVisible = false;
// --- (3) メインループ:描く → キーを待つ → 動かす ---
while (true)
{
Draw(map, px, py);
ConsoleKeyInfo key = Console.ReadKey(true); // true = 押したキーを画面に出さない
if (key.Key == ConsoleKey.Escape || key.Key == ConsoleKey.Q)
break; // Esc か Q で終了
int dx, dy;
if (!TryGetDirection(key.Key, out dx, out dy))
continue; // 関係ないキーは無視して最初に戻る
TryMove(map, ref px, ref py, dx, dy);
}
}
// 周囲を1マスぶん壁(番兵)で囲んだ char マップを作る。
static char[,] WithSentinel(int[,] inner)
{
int rows = inner.GetLength(0);
int cols = inner.GetLength(1);
char[,] map = new char[rows + 2, cols + 2]; // 上下左右に +1
for (int y = 0; y < map.GetLength(0); y++)
{
for (int x = 0; x < map.GetLength(1); x++)
{
bool edge =
y == 0 || x == 0 ||
y == map.GetLength(0) - 1 ||
x == map.GetLength(1) - 1;
if (edge)
map[y, x] = Wall; // 番兵
else
map[y, x] = inner[y - 1, x - 1] == 1 ? Wall : Floor;
}
}
return map;
}
// 画面を全部描き直す(簡単のため毎回全描画)。
static void Draw(char[,] map, int px, int py)
{
Console.SetCursorPosition(0, 0); // 毎回左上から書き直す
for (int y = 0; y < map.GetLength(0); y++)
{
for (int x = 0; x < map.GetLength(1); x++)
{
// プレイヤーの座標は番兵の分 +1 ずらす
if (x == px + 1 && y == py + 1)
Console.Write(Player);
else
Console.Write(map[y, x]);
}
Console.WriteLine();
}
Console.WriteLine("矢印キー / テンキー で移動(5 はその場)");
Console.WriteLine("Esc か Q で終了");
}
// 押されたキーを方向 (dx, dy) に変換する。
// 対応していないキーなら false を返す。
// テンキーは斜めもあるので 8 方向。
static bool TryGetDirection(ConsoleKey key, out int dx, out int dy)
{
dx = 0;
dy = 0;
switch (key)
{
// 矢印キー(4方向)
case ConsoleKey.UpArrow: dy = -1; return true;
case ConsoleKey.DownArrow: dy = 1; return true;
case ConsoleKey.LeftArrow: dx = -1; return true;
case ConsoleKey.RightArrow: dx = 1; return true;
// テンキー(8方向)
case ConsoleKey.NumPad8: dy = -1; return true; // ↑
case ConsoleKey.NumPad2: dy = 1; return true; // ↓
case ConsoleKey.NumPad4: dx = -1; return true; // ←
case ConsoleKey.NumPad6: dx = 1; return true; // →
case ConsoleKey.NumPad7: dx = -1; dy = -1; return true; // ↖
case ConsoleKey.NumPad9: dx = 1; dy = -1; return true; // ↗
case ConsoleKey.NumPad1: dx = -1; dy = 1; return true; // ↙
case ConsoleKey.NumPad3: dx = 1; dy = 1; return true; // ↘
}
return false;
}
// 進もうとした先が壁(番兵を含む)でなければ座標を更新する。
static void TryMove(char[,] map, ref int px, ref int py, int dx, int dy)
{
int nx = px + dx;
int ny = py + dy;
// 番兵の分だけずらして地形を見る。
// 番兵があるので、ここで範囲外になることは絶対にない。
if (map[ny + 1, nx + 1] != Wall)
{
px = nx;
py = ny;
}
}
}
マップの外側をぐるっと壁で囲んでおくテクニック。外へ出ようとすると必ずその壁に当たるので、添字が範囲外にならず、境界チェックの書き忘れによるクラッシュが起こらない。
普通なら、進む前に4方向の範囲を確認する必要がある。
if (0 <= nx && nx < cols && 0 <= ny && ny < rows) // これが要らない
初回だけ必要。入れ方は下の付録(Windows / Mac)。
dotnet --version
8.x.x のように表示されればOK。
このリポジトリにある場合はそのまま。
cd projects/csharp-walk
dotnet run
手元に新しく作る場合は、雛形を作って Program.cs をこのページのコードに置き換える。
dotnet new console -o walk
cd walk
# 生成された Program.cs を置き換える
dotnet run
| キー | 動き |
|---|---|
↑ ↓ ← → | 4方向に1マス |
テンキー 8 2 4 6 | 上下左右 |
テンキー 7 9 1 3 | 斜め |
Esc / Q | 終了 |
テンキーで斜めを動かすには NumLock をオンにする(オフだと矢印キー扱いになる。矢印キーはそのまま使える)。
ビルドと実行に .NET 8 SDK が要る。どちらも公式の配布物を入れる。バージョンは 8 系で揃えている。
winget install dotnet-sdk-8.0
PowerShell またはコマンドプロンプトで実行する。winget が無い場合は公式インストーラ(.NET 8 SDK / x64)を落として実行する。
brew install --cask dotnet-sdk@8
Homebrew で入れる。Homebrew が無い場合は公式インストーラ(.NET 8 SDK / Arm64 または x64)を落として実行する。
入れたら dotnet --version で確認する。dotnet は初回起動時に「Welcome to .NET」の案内を出すことがある。