C言語で画面のFという文字を一回転させていますが、ほぼ同じ For文が4つあり、違うのはprintfの中の変数だけなので、これを、関数化したいのですが、どうもうまくいきませんので教えてください。よろしくお願いします。
#include<stdio.h>
int main(void)
{
int dt[5][5]={
{88,■,■,■,88},
{88,■,88,88,88},
{88,■,■,■,88},
{88,■,88,88,88},
{88,■,88,88,88}
};
;
int x;
int y;
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%d", dt[x][y]);
}
}
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%d", dt[4-y][x]);
}
}
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%d", dt[4-x][4-y]);
}
}
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%d", dt[y][4-x]);
}
}
return 0;
}
A 回答 (9件)
- 最新から表示
- 回答順に表示
No.9
- 回答日時:
#7です。
パラメータを右回転数を与えるようにしました。
右回転数=0 そのまま
右回転数=1 右へ90度
右回転数=2 右へ180度
右回転数=3 右へ270度
---------------------------------------------
#include<stdio.h>
int GetConst(int X,int Y)
{
if (X == -1 || Y== -1) return 4;
return 0;
}
int GetIndex(int base,int rot)
{
if (rot < 0) rot = 3;
if ((base+rot%2)%2 == 0){
return 0;
}else{
if ((base+rot/2)%2 == 0){
return -1;
}else{
return 1;
}
}
}
void FunctionROT(int rot)
{
int x = 0;
int y = 0;
int X1,X2,C1,Y1,Y2,C2;
int dt[5][5]={
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,88,88,88}
};
X1 = GetIndex(1,rot);
Y1 = GetIndex(0,rot);
C1 = GetConst(X1,Y1);
X2 = GetIndex(1,rot-1);
Y2 = GetIndex(0,rot-1);
C2 = GetConst(X2,Y2);
//printf("\nX1=%d Y1=%d C1=%d X2=%d Y2=%d C2=%d\n",X1,Y1,C1,X2,Y2,C2);
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%-d", dt[X1*x+Y1*y+C1][X2*x+Y2*y+C2]);
}
}
}
int main(void)
{
FunctionROT( 0 );
FunctionROT( 1 );
FunctionROT( 2 );
FunctionROT( 3 );
return 0;
}
---------------------------------------------
以下、実行結果です。
8811111188
8811888888
8811111188
8811888888
8811888888
8888888888
1111111111
8888118811
8888118811
8888888888
8888881188
8888881188
8811111188
8888881188
8811111188
8888888888
1188118888
1188118888
1111111111
8888888888
ーーーーーーーーーーーーーー
No.8
- 回答日時:
回転処理をアフィン変換で計算すれば、分岐のない計算式だけで処理できます。
アフィン変換による回転処理
計算後ベクトル座標 = ベクトル座標 * 平行移動(-2,-2) * 回転(deg) * 平行移動(+2,+2)
アフィン変換は行列の記述が面倒なので、計算途中は省略しますが、
最終的には以下の計算式が求まります。
c = cos(deg)
s = sin(deg)
xx = x*c + y*s + (1-c-s)*2
yy = y*c - x*s + (1-c+s)*2
コンソール画面の座標 (x,y) と、回転角度 deg から、変数 dt の座標 (xx,yy) の計算式が決まりましたので、
以下のサンプルのような、条件分岐のない関数を作ることができます。
void displaySquareImage(int dt[5][5], int deg) {
_ int x, y, s, c, xx, yy;
_ s = (deg==90)? 1: (deg==270)? -1: 0;
_ c = (deg==0)? 1: (deg==180)? -1: 0;
_ printf("-- rotate %d deg\n", deg);
_ for (y=0; y<5; y++) {
_ _ for (x=0; x<5; x++) {
_ _ _ xx = x*c + y*s + (1-c-s)*2;
_ _ _ yy = y*c - x*s + (1-c+s)*2;
_ _ _ printf("%02d", dt[yy][xx]);
_ _ }
_ _ puts("");
_ }
}
使い方
displaySquareImage(dt, 0);
displaySquareImage(dt, 90);
さらに汎用化を求めるなら、
* 画像 5x5 以外にも対応
* 90度以外の回転 (計算を double 型にしたり、範囲外判定も増える)
などもご検討ください。
No.7
- 回答日時:
#6です。
関数が望みでしたら、以下ではどうでしょうか。力ずくです。--------------------------------------------------------------------
#include<stdio.h>
void FunctionXY(int lx,int ly,int lc, int rx,int ry,int rc)
{
int x = 0;
int y = 0;
int dt[5][5]={
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,88,88,88}
};
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%-d", dt[lx*x+ly*y+lc][rx*x+ry*y+rc]);
}
}
}
int main(void)
{
FunctionXY( 1,0,0,0,1,0 );
FunctionXY( 0,-1,4,1,0,0);
FunctionXY( -1,0,4,0,-1,4);
return 0;
}
------------------------------------------------------
以下、実行結果です。
8811111188
8811888888
8811111188
8811888888
8811888888
8888888888
1111111111
8888118811
8888118811
8888888888
8888881188
8888881188
8811111188
8888881188
8811111188
No.6
- 回答日時:
力ずくですが、以下ではどうでしょうか。
-----------------------------------------------------
#include<stdio.h>
int main(void)
{
int dt[5][5]={
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,88,88,88}
};
;
int x;
int y;
#define PRINT(P1,P2){\
for( x=0; x<=4; x++){\
printf("\n");\
for( y=0; y<=4; y++){\
printf("%d", dt[(P1)][(P2)]);\
}\
}\
}
PRINT(x,y)
PRINT(4-y,x)
PRINT(4-x,4-y)
}
-------------------------------------------------------------
以下、実行結果です
8811111188
8811888888
8811111188
8811888888
8811888888
8888888888
1111111111
8888118811
8888118811
8888888888
8888881188
8888881188
8811111188
8888881188
8811111188
No.5
- 回答日時:
Cの関数には「式」は渡せません。
式の計算した値が渡されます。なので、「式を渡そう」という風に考えてしまうと正解に辿りつけません
/* 関数ポインタを使って渡せないことも無いですが、他言語のラムダ式のような仕組が無いので、面倒なことになります */
そうすると
・呼び出し側から「角度」を受けとる
・角度に合せて、変換式を使い分ける
というのが現実的な方法となります。
真面目に全角度に対応させるなら、回転行列が必要となってきますが、
今回のように4種類しかないのなら、それに0,1,2,3とでも番号を付けて
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
/* 渡された「角度」によって、式を使い分けて
x,y→r,c を計算する */
printf("%-d", dt[r][c]);
}
}
とでもすればいいでしょう。
No.4
- 回答日時:
まずは #2 の疑問に対する回答.
「Cの仕様上どうなってんだろ」については「何も決まっていない」となります. そもそも「double」が何なのか仕様で決まっていないんだから, もうどうしようもありません. あと
pi = atan(1.0)*4;
でえられる pi の値は「真の π の値」とはちょっとだけ違います (そして「どっち向きに違うか」はやっぱり仕様上何も決まっていません). だから sin(pi/2) は 1 よりちょっと小さいと思わなきゃならないし, cos(pi/2) は 0 とちょっと違うことを覚悟しなきゃならない. なお悪いことに
・cos(pi/2) は正かもしれないし負かもしれない
・1-sin(pi/2) より abs(cos(pi/2)) のほうが大きい
ので cos(pi/2) + sin(pi/2) は 1 より大きいかもしれないし小さいかもしれないので, 単純に floor で切り捨ててしまうと 0 になっちゃうかもしれない.
つまりこの場合に限定していえば「double を導入する」という判断のせいで「全然ロジックと関係無いトコで苦労」していることになる. ある意味「盛大な自爆」ともいえる.
ということで「正しい」方法:
sin や cos の引数は 4種類しかないんだから, それを int の配列で持つ. 例えば
int sinkpi2[] = { 0, 1, 0, -1 }, coskpi2[] = { 1, 0, -1, 0 };
としておけば sin(kπ/2) や cos(kπ/2) はそれぞれ
sinkpi2[k%4], coskpi2[k%4]
で求まる. これくらいのメモリの余裕はあるでしょ.
No.3
- 回答日時:
あ、座標記述が間違ってますね。
すいません。dtの座標を次のように考える、って事です。
(-2, -2) (-2, -1) (-2, 0) (-2, 1) (-2, 2)
(-1, -2) (-1, -1) (-1, 0) (-1, 1) (-1, 2)
( 0, -2) ( 0, -1) ( 0, 0) ( 0, 1) ( 0, 2)
( 1, -2) ( 1, -1) ( 1, 0) ( 1, 1) ( 1, 2)
( 2, -2) ( 2, -1) ( 2, 0) ( 2, 1) ( 2, 2)
No.2
- 回答日時:
#1 氏の仰る通りですね。
最初に定義してるデータ型
int dt[5][5]={
{88,■,■,■,88},
{88,■,88,88,88},
{88,■,■,■,88},
{88,■,88,88,88},
{88,■,88,88,88}
};
ってのはマズいでしょう。
これは恐らく
char* dt[5][5]={
{"□","■","■","■","□"},
{"□","■","□","□","□"},
{"□","■","■","■","□"},
{"□","■","□","□","□"},
{"□","■","□","□","□"}
};
みたいにしないと通らないでしょうね。
それはともかく。
> ほぼ同じ For文が4つあり、違うのはprintfの中の変数だけなので、これを、関数化したい
ってのは良いアイディアですよね。
なるたけ共通機構を纏めちゃって、関数化した方が一般に見通しは良くなります。
そこで。
回転行列を使います。
回転行列:
https://ja.wikipedia.org/wiki/回転行列
恐らく高校数学で・・・習ってると思うんですが・・・・・。
例えば、
□■■■□ □□□□□
□■□□□ ■■■■■
□■■■□ -> □□■□■
□■□□□ □□■□■
□■□□□ □□□□□
となる場合は90度の回転ですよね。
このケースの場合、行列dtの[0][0]である□は回転された行列dt'の[0][4]へ移動してるわけです。
1列目を考えると次のような移動が行われてますね。
dt[0][0]:□ -> dt'[0][4]
dt[1][0]:□ -> dt'[0][3]
dt[2][0]:□ -> dt'[0][2]
dt[3][0]:□ -> dt'[0][1]
dt[4][0]:□ -> dt'[0][0]
こういう状況になってるんですが、このまま扱うのはちょっと見通しが悪いんで、左上左端の座標を[-2][-2]、右下右端の座標を[2][2]と考えます。
つまり、元のdtが次のような座標になってる、と考えます。
(-2, -2) (-2, -1) (-2, 0) (-2, 1) (-2, 2)
(-1, -2) (-1, -1) (-1, 0) (-1, 1) (-1, 2)
( 0, -2) ( 0, -1) ( 0, 0) ( 0, 1) ( 0, 2)
( 1, -2) ( 1, -2) ( 1, -2) ( 1, -2) ( 0, -2)
( 2, -2) ( 2, -2) ( 2, -2) ( 2, -2) ( 0, -2)
要するに中央の■の座標が(0, 0)と敢えて考えます。
そうすると、x->x'、y->y'の座標変換は、Wikipediaの回転行列での演算結果に従うと、
x' = x*cosθ-y*sinθ
y' = x*sinθ+y*cosθ
になりますね。
ここで、元のdtの添字に合わせれば
x' = x*cosθ-y*sinθ+2
y' = x*sinθ+y*cosθ+2
となって、これで当初の「座標変換」が成り立ちます。
基本的にはこいつをdtの添字に突っ込めば、「回転後」の図形が一丁出来上がり、となる筈です。
// ここから
#include<stdio.h>
#include<math.h>
void print_rotated(double theta, char* dt[][5]) {
int x; double x_prime;
int y; double y_prime;
for(x=-2; x<=2; x++){
printf("\n");
for(y=-2; y<=2; y++) {
/* 座標変換 */
x_prime = x*cos(theta)-y*sin(theta);
y_prime = x*sin(theta)+y*cos(theta);
/* ちとココの double -> int の変換がメンド臭い */
printf("%s", dt[(int)floor(x_prime+2.5)][(int)floor(y_prime+2.5)]);
}
}
}
int main(void)
{
char* dt[5][5]={
{"□","■","■","■","□"},
{"□","■","□","□","□"},
{"□","■","■","■","□"},
{"□","■","□","□","□"},
{"□","■","□","□","□"}
};
/* 基本的に C の仕様上、円周率が定義されていないので作ります。 */
double pi = atan(1.0) * 4.0;
int n;
for (n = 0; n < 4; n++) {
print_rotated(n*pi/2, dt);
printf("\n");
}
return 0;
}
// ここまで
注意点としては、僕も大ハマリにハマってたんですが(笑)、基本的に三角関数関係はdoubleを返すんですが、
int -> double
のキャストならいざ知らず、
double -> int
のキャストは甚だ難しい(笑)。
今回の場合、回転自体は90度、180度、270度なんで、三角関数は0か1か-1のdoubleを返してくる筈なんですが、こいつをそのままintにキャストして配列の添字として使おうとしても結果がおかしくなっちまうんですよね。
どうやら「切り捨て」がこっちの想像の斜め上やってるらしくって・・・(笑)。Cの仕様上どうなってんだろ(笑)?
あと、四捨五入のroundってのがANSI Cには無いんです。C99以降の規格にはあるんですが、万が一Visual C++辺り使われた日にゃあ・・・ねぇ(笑)。
そこで、加算する2を2.5にしてfloor(切り捨て)して無理矢理調整しています。
全然ロジックと関係無いトコで苦労するのがCですよ(笑)。全くもう(笑)。
こんなカンジじゃないんですか?
ありがとうございます。長い文章をかいていただいてありがとうございます。まったく考えていたやり方と違ったので、驚きです。試して理解してみます。そのあとに返信します。しかし、こんなものを普通に返信できる人に凄さを感じます(笑)。
No.1
- 回答日時:
具体的にどのように考えて、どうやったのですか?
それがどのように「うまくいかった」のでしょうか?
どこで間違えたかがわからなければ、今「正解」のソース見たところで、次には同じところで失敗します。
あと、このプログラム、ちゃんと動作しますか?
intの初期値に■なんてのが入っているし。
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%d", dt[x][y]);
}
}
は間違いではないですが、x,yが連想させる意味との違いに違和感があります。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 エラーの原因がわからな...
-
比較回数と交換回数表示について
-
複数桁10進数の*桁目だけを抽出...
-
nCmの関数
-
構造体の勉強中です 合計点の高...
-
C言語 配列と関数の練習問題
-
[C言語] 関数を利用する計算
-
実数の整数部,小数部の取得
-
C言語での引数の省略方法
-
数字列を3桁ごとにカンマで区切...
-
アスタリスクでダイヤ型を作る
-
覆面算のプログラムが分かりません
-
C言語の基礎 . 2乗値の差につ...
-
c言語
-
プログラミング
-
【C++】関数ポインタの使い方
-
毎回違う乱数を生成するにはど...
-
if と配列の組み合わせ
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
「指定されたキャストは有効で...
-
C言語 配列と関数の練習問題
-
複数桁10進数の*桁目だけを抽出...
-
(int *)の意味
-
if と配列の組み合わせ
-
ラップ関数とはどんなものですか?
-
卒業研究でよく分からないとこ...
-
【C++】関数ポインタの使い方
-
c言語
-
足して100になるような乱数のア...
-
C言語初心者です、、、お助けく...
-
数字列を3桁ごとにカンマで区切...
-
C言語 エラーの原因がわからな...
-
実数の整数部,小数部の取得
-
課題でつまってます・・・
-
商と剰余を同時に求める(C言語)
-
C言語の配列をC++のvectorに高...
-
std::set<int> で、ある値が何...
おすすめ情報
返信ありがとうございます。 ■の部分は、11 だったのですが、質問の際に、見た目がみにくすぎたので■にしましたが、よく考えてみるとint型なので、無理がありました。
分からない点は、引数にどんな形で値を設定すればよいかがわかりません。 今考えていることは、printfの部分の変数だけ変えてなんとかならないかということです。
間違えてはいますが、下記のように書きました。今のままでは、
関数の引数が0の時でも、xとyの値が引かれてしまいますし、x と Yを入れ替えることもできません。なかんいい方法がないか考えています。
続く
#include<stdio.h>
void FunctionXY(int a, int b)
{
int x = 0;
int y = 0;
int dt[5][5]={
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,11,11,88},
{88,11,88,88,88},
{88,11,88,88,88}
};
for( x=0; x<=4; x++){
printf("\n");
for( y=0; y<=4; y++){
printf("%-d", dt[a-x][b-y]);
}
}
}
int main(void)
{
FunctionXY( 0,0 );
FunctionXY( 4,4 ); //180℃右回転
return 0;
}