質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

3回答

1137閲覧

C言語 経路探索アルゴリズム実装についての質問

missile_l700

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

2クリップ

投稿2019/02/25 06:54

編集2019/02/25 07:53

前提・実現したいこと

c++を利用して、迷路探索のアルゴリズムの勉強をしていますが、
参考書などを元に作成したプログラムが動きません。

発生している問題・エラーメッセージ


エラーメッセージ
E0028 式には定数値が必要です。
C3863 配列型を割り当てることは出来ません。
C2228 yの左側はクラス・構造体・共用体でなければなりません。


該当のソースコード

#include <stdlib.h> #include <time.h> #define MAXX 256 #define MAXY 256 /* 迷路自動生成プログラム*/ // 迷路盤面の座標は構造体で管理する。 typedef struct { int x; int y; }coord_t; int meiro[MAXX][MAXY] = { { 0 } }; // 迷路盤 coord_t nodes[MAXX*MAXY]; // 未開発の(壁が伸びていない)柱のリスト int nodend = 0; // nodesリストの長さ coord_t path[MAXX*MAXY]; // 探索した柱のリスト(スタック) int pathend = 0; // pathリストの長さ // 構造体の値を設定 coord_t newcoord (int x , int y) { coord_t newcoord; newcoord,x = x; newcoord,y = y; return newcoord; } // リストに新たな要素を追加(nodes) void insert_node(coord_t c) { nodes[nodend] = c; nodend++; } // リストに新たな要素を追加(path) void insert_path(coord_t c) { path[pathend] = c; pathend++; } // nodesリストの任意の要素を取り出す coord_t remove_node(int k) { coord_t out; if (k > nodend) { printf("error: Not found"); return newcoord(-1, -1); } else { out = nodes[k]; // 取り出す for (int i = k; i < nodend - 1; i++) // 取り出したぶん詰める nodes[i] = nodes[i + 1]; nodend--; } return out; } // pathリストの†末尾†の要素を取り出す coord_t remove_path(void) { coord_t out; out = path[pathend - 1]; // 取り出す pathend--; return out; } // リスト総当たり検索(nodes) int search_node(coord_t c) { for (int i = 0; i <= nodend - 1; i++) { if ((nodes[i].x == c.x) && (nodes[i].y == c.y)) return i; } return -1; } // リスト総当たり検索(path) int search_path(coord_t c) { for (int i = 0; i <= pathend - 1; i++) { if ((path[i].x == c.x) && (path[i].y == c.y)) return i; } return -1; } // 上下左右シャッフル void shuffle(coord_t *direction) { int j; coord_t tmp; for (int i = 0; i < 4; i++) { j = rand() % 4; tmp = direction[i]; direction[i] = direction[j]; direction[j] = tmp; } } // 柱を探索(再帰) int choose_node(coord_t c) { int s, r; coord_t p_1, p_2; coord_t d[4] = { newcoord(0, 2), newcoord(0, -2), newcoord(2, 0), newcoord(-2, 0) }; // 壁を伸ばす方向 // printf("x:%d, y:%d\n", c.x, c.y); if (search_path(c) != -1) { // cが探索済の時 return 1; // 生成失敗 } else { insert_path(c); // pathに追加 s = search_node(c); if (s != -1) { // cが未探索の時 remove_node(s); // nodeから消す // 上下左右のいずれかに壁を伸ばす shuffle(d); for (int i = 0; i < 4; i++) { r = choose_node(newcoord(c.x + d[i].x, c.y + d[i].y)); if (r == 0) break; } if (r == 1) insert_node(remove_path()); return r; } else { // cがすでに壁の時 // pathリストの末尾から一つずつ取り出し壁を作る p_2 = remove_path(); do { p_1 = p_2; p_2 = remove_path(); // printf("wall(%d, %d)\n",(p_1.x + p_2.x) / 2, (p_1.y + p_2.y) / 2); meiro[(p_1.x + p_2.x) / 2][(p_1.y + p_2.y) / 2] = 1; } while (pathend); return 0; } } } // 迷路の自動生成 void make_meiro(int w, int h) { coord_t c; while (nodend) { choose_node(nodes[rand() % nodend]); } // 外壁 for (int j = 0; j < h; j++) { meiro[0][j] = 1; meiro[w - 1][j] = 1; } for (int i = 0; i < w; i++) { meiro[i][0] = 1; meiro[i][h - 1] = 1; } } /*******/ /* 探索 */ /*******/ /** 迷路作成に用いたpathスタックの領域をキューとして再利用 **/ // pathリストの†先頭†の要素を取り出す coord_t remove_path_h(void) { coord_t out = path[0]; // 取り出す for (int i = 0; i < pathend; i++) // 詰める path[i] = path[i + 1]; pathend--; return out; } // 地点pから最も遠い点を検索(幅優先) coord_t search_far(int w, int h, coord_t p) { coord_t n; int sx, sy; coord_t d[4] = { newcoord(0, 1), newcoord(0, -1), newcoord(1, 0), newcoord(-1, 0) }; // 進む方向 // 迷路をコピー int meiro_2[w][h]; for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { meiro_2[i][j] = meiro[i][j]; } } // スタートを追加 pathend = 0; insert_path(p); // 繰り返し探索 while (pathend) { n = remove_path_h(); // printf("search = (%d, %d)\n", n.x, n.y); 可能であれば表示させてみる // printf ("%d\n", pathend);  上同様 meiro_2[n.x][n.y] = 2; // 対応する座標を探索済みにする shuffle(d); // ランダム性を持たせるためシャッフル // printf("%d,%d\n",d[0].x,d[0].y); for (int i = 0; i < 4; i++) { sx = n.x + d[i].x; // 隣接マスのx座標 sy = n.y + d[i].y; // 隣接マスのy座標 if (meiro_2[sx][sy] == 0) { // 隣接マスが未探索の道のとき insert_path(newcoord(sx, sy)); } } } return n; } // 幅優先探索 int search_meiro(int w, int h, coord_t start, coord_t goal) { coord_t n; int sx, sy; coord_t direction[w][h]; // 辿ってきた方向を記憶する配列 coord_t d[4] = { newcoord(0, 1), newcoord(0, -1), newcoord(1, 0), newcoord(-1, 0) }; // 進む方向 // スタートを追加 pathend = 0; insert_path(start); // 繰り返し探索 while (pathend) { n = remove_path_h(); // printf("search = (%d, %d)\n", n.x, n.y); // printf ("%d\n", pathend); meiro[n.x][n.y] = 2; // 対応する座標を探索済みにする if (n.x == goal.x && n.y == goal.y) { // ゴール処理 while (n.x != start.x || n.y != start.y) { // 値を更新 sx = n.x; sy = n.y; // printf("PATH = (%d, %d)\n", n.x, n.y); // マーキング meiro[n.x][n.y] = 3; // 経路回帰 n.x -= direction[sx][sy].x; n.y -= direction[sx][sy].y; } return 0; } else { // 探索処理 for (int i = 0; i < 4; i++) { sx = n.x + d[i].x; // 隣接マスのx座標 sy = n.y + d[i].y; // 隣接マスのy座標 if (meiro[sx][sy] == 0) { // 隣接マスが未探索の道のとき insert_path(newcoord(sx, sy)); direction[sx][sy] = d[i]; } } } } printf("ゴールを見つけられませんでしたorz...\n"); return 1; } // 迷路を表示 void show_meiro(int w, int h, coord_t start, coord_t goal) { for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { if ((i == start.x) && (j == start.y)) { printf("\x1b[41m"); printf("\x1b[37m"); printf("S "); // スタート } else if ((i == goal.x) && (j == goal.y)) { printf("\x1b[41m"); printf("\x1b[37m"); printf("G "); // ゴール } else { switch (meiro[i][j]) { case 0: // 探索されていない道 printf("\x1b[0m"); break; case 1: // 壁 printf("\x1b[42m"); break; case 2: // 探索された道 printf("\x1b[0m");// [47mで薄く表示 break; case 3: // 正解ルート printf("\x1b[45m"); break; default: printf("\x1b[0m"); } printf(" "); } } printf("\x1b[0m"); printf("\n"); } printf("\n\n"); } /***********/ /* メイン */ /***********/ int main(void) { srand((unsigned)time(NULL)); int i, j; int width, height; //壁の厚さを0、道の太さを1とした時の迷路の幅、高さ printf("width> "); scanf("%d", &width); printf("height> "); scanf("%d", &height); // 柱リストの作成 for (j = 1; j < height; j++) { for (i = 1; i < width; i++) { insert_node(newcoord(2 * i, 2 * j)); // printf("%d\n", nodend); meiro[2 * i][2 * j] = 1; } } // 迷路盤の使用領域を設定 int w = 2 * width + 1; // 迷路盤の幅 int h = 2 * height + 1; // 迷路盤の高さ // 迷路の自動生成 make_meiro(w, h); // スタート、ゴールを設定 coord_t start = search_far(w, h, newcoord((rand() % width) * 2 + 1, (rand() % height) * 2 + 1)); coord_t goal = search_far(w, h, start); // 迷路の表示 show_meiro(w, h, start, goal); // 迷路の探索 char yn[2]; printf("Show the answer?"); scanf("%s", yn); if (yn[0] == 'yn') { search_meiro(w, h, start, goal); show_meiro(w, h, start, goal); } printf("[end of 'long_meiro.c']\n"); return 0; } コード

試したこと

構文の変更や、グロ-バル関数について見直しましたがエラーが
出てしまいます。

C言語・プログラムは初心者です。基本的な事かと思われますが、ご教授宜しく御願い致します。

bochan2👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/25 07:00

見出しは### ではなく# ですね・・。(行頭は何も書いてはいけない) なぜそう書かれたか分かりませんが、PCであれば質問投稿画面でリアルタイムプレビューが表示されるので、投稿前にそちら見ながら調整してください。
y_waiwai

2019/02/25 09:52

言語はなにでしょう。C#ではないですね? で、C++でもないようにみえますが。
missile_l700

2019/02/25 15:12

ご指摘ありがとう御座います。 現状、c++にてプログラムしております。 C#を元に作成しておりますので、タグ付けしております。 わかりにくくなってしまい、申し訳御座いません。
guest

回答3

0

別の質問でも指摘されていますが、ここのプログラムを VC でコンパイルしようとしているんですよね。
すでに指摘されるいるように、VC では可変長配列は定義できないので、そこをなんとかしければなりません。ちょっと見、可変長配列である必要はなさそうなので、固定長でもいいと思います。
あと、エスケープシーケンスで色を付けていますが、Windows のコンソールはそれも普通はできないので、それもなんとかしないといけないです。

その辺を修正して、コンパイル・実行できるように変更してみました。

C

1/* 2 * long_meiro.c 3 * by Tsukatomo 4 */ 5 6#include <stdio.h> 7#include <stdlib.h> 8#include <time.h> 9#define MAXX 256 10#define MAXY 256 11 12/***********/ 13/* 自動生成 */ 14/***********/ 15 16// 迷路盤面の座標は構造体で管理 17typedef struct{ 18 int x; 19 int y; 20}coord_t; 21 22int meiro[MAXX][MAXY]={{0}}; // 迷路盤 23coord_t nodes[MAXX*MAXY]; // 未開発の(壁が伸びていない)柱のリスト 24int nodend = 0; // nodesリストの長さ 25coord_t path[MAXX*MAXY]; // 探索した柱のリスト(スタック) 26int pathend = 0; // pathリストの長さ 27 28 29// 構造体の値を設定する 30//coord_t newcoord(x, y){ 31coord_t newcoord(int x, int y) { 32 coord_t new; 33 new.x = x; 34 new.y = y; 35 return new; 36} 37 38// リストに新たな要素を追加(nodes) 39void insert_node(coord_t c){ 40 nodes[nodend] = c; 41 nodend++; 42} 43// リストに新たな要素を追加(path) 44void insert_path(coord_t c){ 45 path[pathend] = c; 46 pathend++; 47} 48 49 50// nodesリストの任意の要素を取り出す 51coord_t remove_node(int k){ 52 coord_t out; 53 if (k > nodend){ 54 printf("error: Not found"); 55 return newcoord(-1, -1); 56 } 57 else{ 58 out = nodes[k]; // 取り出す 59 for(int i=k; i < nodend - 1; i++) // 取り出したぶん詰める 60 nodes[i] = nodes[i + 1]; 61 nodend--; 62 } 63 return out; 64} 65// pathリストの†末尾†の要素を取り出す 66coord_t remove_path(void){ 67 coord_t out; 68 out = path[pathend - 1]; // 取り出す 69 pathend--; 70 return out; 71} 72 73// リスト総当たり検索(nodes) 74int search_node(coord_t c){ 75 for(int i = 0; i <= nodend-1; i++){ 76 if((nodes[i].x == c.x) && (nodes[i].y == c.y)) 77 return i; 78 } 79 return -1; 80} 81// リスト総当たり検索(path) 82int search_path(coord_t c){ 83 for(int i = 0; i <= pathend-1; i++){ 84 if((path[i].x == c.x) && (path[i].y == c.y)) 85 return i; 86 } 87 return -1; 88} 89 90// 上下左右シャッフル 91void shuffle(coord_t *direction){ 92 int j; 93 coord_t tmp; 94 for(int i=0; i < 4; i++){ 95 j = rand()%4; 96 tmp = direction[i]; 97 direction[i] = direction[j]; 98 direction[j] = tmp; 99 } 100} 101 102 103// 柱を探索(再帰) 104int choose_node(coord_t c){ 105 int s, r; 106 coord_t p_1, p_2; 107 coord_t d[4] = {newcoord(0, 2), 108 newcoord(0, -2), 109 newcoord(2, 0), 110 newcoord(-2, 0)}; // 壁を伸ばす方向 111 112 // printf("x:%d, y:%d\n", c.x, c.y); 113 if(search_path(c) != -1){ // cが探索済の時 114 return 1; // 生成失敗 115 } 116 else{ 117 insert_path(c); // pathに追加 118 s = search_node(c); 119 if(s != -1){ // cが未探索の時 120 remove_node(s); // nodeから消す 121 // 上下左右のいずれかに壁を伸ばす 122 shuffle(d); 123 for(int i = 0; i < 4; i++){ 124 r = choose_node(newcoord(c.x + d[i].x, c.y + d[i].y)); 125 if (r == 0) break; 126 } 127 if(r == 1) 128 insert_node(remove_path()); 129 return r; 130 } 131 else{ // cがすでに壁の時 132 // pathリストの末尾から一つずつ取り出し壁を作る 133 p_2 = remove_path(); 134 do{ 135 p_1 = p_2; 136 p_2 = remove_path(); 137 // printf("wall(%d, %d)\n",(p_1.x + p_2.x) / 2, (p_1.y + p_2.y) / 2); 138 meiro[(p_1.x + p_2.x) / 2][(p_1.y + p_2.y) / 2] = 1; 139 }while(pathend); 140 return 0; 141 } 142 } 143} 144 145 146// 迷路の自動生成 147void make_meiro(int w, int h){ 148 //coord_t c; 149 while (nodend) { 150 choose_node(nodes[rand()%nodend]); 151 } 152 // 外壁 153 for(int j=0; j < h; j++){ 154 meiro[0][j] = 1; 155 meiro[w-1][j] = 1; 156 } 157 for(int i=0; i < w; i++){ 158 meiro[i][0] = 1; 159 meiro[i][h-1] = 1; 160 } 161} 162 163 164/********/ 165/* 探索 */ 166/********/ 167 168/** 迷路作成に用いたpathスタックの領域をキューとして再利用 **/ 169// pathリストの†先頭†の要素を取り出す 170coord_t remove_path_h(void){ 171 coord_t out = path[0]; // 取り出す 172 for(int i = 0; i < pathend; i++) // 詰める 173 path[i] = path[i + 1]; 174 pathend--; 175 return out; 176} 177 178// 地点pから最も遠い点を検索(幅優先) 179coord_t search_far(int w, int h, coord_t p){ 180 coord_t n; 181 int sx, sy; 182 coord_t d[4] = {newcoord(0, 1), 183 newcoord(0, -1), 184 newcoord(1, 0), 185 newcoord(-1, 0)}; // 進む方向 186 187 // 迷路をコピー 188 //int meiro_2[w][h]; 189 int meiro_2[MAXX][MAXY]; 190 for(int j = 0; j < h; j++){ 191 for(int i = 0; i < w; i++){ 192 meiro_2[i][j] = meiro[i][j]; 193 } 194 } 195 196 // スタートを追加 197 pathend = 0; 198 insert_path(p); 199 200 // 繰り返し探索 201 while(pathend){ 202 n = remove_path_h(); 203 // printf("search = (%d, %d)\n", n.x, n.y); 204 // printf ("%d\n", pathend); 205 meiro_2[n.x][n.y] = 2; // 対応する座標を探索済みにする 206 shuffle(d); // ランダム性を持たせるためシャッフル 207 // printf("%d,%d\n",d[0].x,d[0].y); 208 for(int i = 0; i < 4; i++){ 209 sx = n.x + d[i].x; // 隣接マスのx座標 210 sy = n.y + d[i].y; // 隣接マスのy座標 211 if(meiro_2[sx][sy] == 0){ // 隣接マスが未探索の道のとき 212 insert_path(newcoord(sx, sy)); 213 } 214 } 215 } 216 return n; 217} 218 219 220// 幅優先探索 221int search_meiro(int w, int h, coord_t start, coord_t goal){ 222 coord_t n; 223 int sx, sy; 224 ///coord_t direction[w][h]; // 辿ってきた方向を記憶する配列(要素はd[4]のどれか) 225 coord_t direction[MAXX][MAXY]; // 辿ってきた方向を記憶する配列(要素はd[4]のどれか) 226 coord_t d[4] = {newcoord(0, 1), 227 newcoord(0, -1), 228 newcoord(1, 0), 229 newcoord(-1, 0)}; // 進む方向 230 231 // スタートを追加 232 pathend = 0; 233 insert_path(start); 234 235 // 繰り返し探索 236 while(pathend){ 237 n = remove_path_h(); 238 // printf("search = (%d, %d)\n", n.x, n.y); 239 // printf ("%d\n", pathend); 240 meiro[n.x][n.y] = 2; // 対応する座標を探索済みにする 241 if(n.x == goal.x && n.y == goal.y){ // ゴール処理 242 while(n.x != start.x || n.y != start.y){ 243 // 値を更新 244 sx = n.x; 245 sy = n.y; 246 // printf("PATH = (%d, %d)\n", n.x, n.y); 247 // マーキング 248 meiro[n.x][n.y] = 3; 249 // 来た道を戻る 250 n.x -= direction[sx][sy].x; 251 n.y -= direction[sx][sy].y; 252 } 253 return 0; 254 } 255 else{ // 探索処理 256 for(int i = 0; i < 4; i++){ 257 sx = n.x + d[i].x; // 隣接マスのx座標 258 sy = n.y + d[i].y; // 隣接マスのy座標 259 if(meiro[sx][sy] == 0){ // 隣接マスが未探索の道のとき 260 insert_path(newcoord(sx, sy)); 261 direction[sx][sy] = d[i]; 262 } 263 } 264 } 265 } 266 printf("I cannot find the goal...\n"); 267 return 1; 268} 269 270// 迷路を表示 271void show_meiro(int w, int h, coord_t start, coord_t goal){ 272 for(int j=0; j < h; j++){ 273 for(int i=0; i < w; i++){ 274 if((i == start.x) && (j == start.y)){ 275 //printf("\x1b[41m"); 276 //printf("\x1b[37m"); 277 printf("S "); // スタート 278 } 279 else if((i == goal.x) && (j == goal.y)){ 280 //printf("\x1b[41m"); 281 //printf("\x1b[37m"); 282 printf("G "); // ゴール 283 } 284 else{ 285 switch(meiro[i][j]){ 286 case 0: // 探索されていない道 287 //printf("\x1b[0m"); 288 printf(" "); 289 break; 290 case 1: // 壁 291 //printf("\x1b[42m"); 292 printf("■"); 293 break; 294 case 2: // 探索された道 295 //printf("\x1b[0m");// [47mでうっすら表示できるよ 296 printf(" "); 297 break; 298 case 3: // 正解ルート 299 //printf("\x1b[45m"); 300 printf("・"); 301 break; 302 default: 303 //printf("\x1b[0m"); 304 break; 305 } 306 //printf(" "); 307 } 308 } 309 //printf("\x1b[0m"); 310 printf("\n"); 311 } 312 printf("\n\n"); 313} 314 315 316/***********/ 317/* メイン */ 318/***********/ 319int main(void){ 320 srand((unsigned)time(NULL)); 321 int i, j; 322 int width, height; //壁の厚さを0、道の太さを1とした時の迷路の幅、高さ 323 printf("width> "); 324 scanf("%d", &width); 325 printf("height> "); 326 scanf("%d", &height); 327 328 if (MAXX / 2 - 1 < width || MAXY / 2 - 1< height) { 329 return 1; 330 } 331 332 // 柱リストの作成 333 for(j=1; j < height; j++){ 334 for(i=1; i < width; i++){ 335 insert_node(newcoord(2 * i, 2 * j)); 336 // printf("%d\n", nodend); 337 meiro[2 * i][2 * j] = 1; 338 } 339 } 340 341 // 迷路盤の使用領域を設定 342 int w = 2 * width + 1; // 迷路盤の幅 343 int h = 2 * height + 1; // 迷路盤の高さ 344 345 // 迷路の自動生成 346 make_meiro(w, h); 347 348 // スタート、ゴールを設定 349 coord_t start = search_far(w, h, newcoord((rand() % width) * 2 + 1, (rand() % height) * 2 + 1)); 350 coord_t goal = search_far(w, h, start); 351 352 // 迷路の表示 353 show_meiro(w, h, start, goal); 354 355 // 迷路の探索 356 char yn[2]; 357 printf("Show the answer? (y/n)> "); 358 scanf("%s", yn); 359 if (yn[0] == 'y'){ 360 search_meiro(w, h, start, goal); 361 show_meiro(w, h, start, goal); 362 } 363 364 printf("[end of 'long_meiro.c']\n"); 365 return 0; 366}

プロポーショナルなフォントを使っていると、表示が崩れます。
C++ ではコンパイルできません。

投稿2019/02/27 06:15

Bull

総合スコア986

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そもそもsearch関数で配列をコピーすること自体が私には不思議なのですが...

ここでも参考にしてみて下さい。

投稿2019/02/25 07:42

stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C++

1int meiro_2[w][h];

このような、「要素数を変数で指定する」形の変数宣言ができるかは、環境に依存します(お使いのコンパイラではできなかったようです)。vectorなどを使ったほうがいいでしょう。

投稿2019/02/25 07:00

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stdio

2019/02/25 07:07

よしダブルポインタの出番だな。
missile_l700

2019/02/25 07:36

御回答ありがとう御座います。 要素数の変更で、vectorを定義しましたが、依然として動作しません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問