忍者ブログ
Profile
HN:gp-hss

職業:高校生

趣味:3DCG

言語:C全般

環境:VC++ 2008 EE

3DCG:Softimage Mod Tool

自己紹介:
ゲームプログラマー目指して勉強している者です。
現在 C++ 修得にむけて頑張っています。

Began study since 2009/8/21

Latest CM
[06/28 soulmorning]
Latest TB
(02/25)
25  24  23  22  21  20  19  18  17  16  15 
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

author : gp-hss ×

とうとうこいつを解説するときが来ました。
この下長くなりますのでご注意を。

    1.グローバル変数の説明
int x
 ○ または × を置く座標の x 座標値。
 5 , 10 , 15 の x 座標に置くようにする。
それぞれの座標値は画面に出力される表の横に並んだ 1 , 2 , 3 と同じ座標値。

int y
 ○ または × を置く座標の y 座標値。
 1 , 3 , 5 の y 座標に置くようにする。
それぞれの座標値は画面に出力される表の縦に並んだ 1 , 2 , 3 と同じ座標値。

int y2
縦横の数値を入力したあと、「その場所には置けません。(改行)もう一度入力してください。」という表示がされる y 座標値。
正確には「その場所には置けません。」という出力があった座標の y 座標値。

int p_y
第1回目の入力をさせる y 座標値。
または、第1回目に ○ :  と出力される座標の y 座標値。
その y 座標値は 7 。

int x_y[][]
 ○ または × が置かれた座標にどちらが置かれたか記憶するオブジェクト。
 [ 0 ][ 0 ] ~ [ 2 ][ 2 ] までの範囲で数値を格納する。
例えば [ 0 ][ 2 ] に数値が格納された場合、出力された表の横 1 , 縦 3 の位置に ○ か × のどちらかが置かれたことを意味する。

int ans
出力された表からの視点で、縦、横、斜めに値を足したときに生成される値を格納するオブジェクト。
例えば横 1 で縦の場合、 x_y[ 0 ][ 0 ] ~ x_y[ 0 ][ 2 ] の値を足した値が格納される。 
右上がりの斜めの場合は、 x_y[ 0 ][ 2 ] , x_y[ 1 ][ 1 ] , x_y[ 2 ][ 0 ] を足した値が格納される。

int ans_val[]
各ゲーム(試合)での勝敗を表す数値を格納するオブジェクト。

int ans_i
オブジェクト ans_val[] を操作するためのオブジェクト。

int ans_i_j
ゲームが何試合行われたかを表す数値を格納するオブジェクト。


    2.指定した座標へカーソルを移動させる方法の説明
まずは、標準出力のハンドルを得るために HANDLE 型の変数( hOut とします)を宣言します。
次に、カーソルの座標値を扱っている構造体の型をもつ変数( coset とします)を宣言します。
そして、先ほど宣言した hOut に標準出力のハンドルを取得させます。

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);

そしてカーソルの座標値を指定します。

    coset.X = 2;
    coset.Y = 2;

最後に指定した座標値にカーソルを移動させます。

    SetConsoleCursorPosition(hOut, coset);

これで完了です。
型については、こんな型があるんだな程度に思ってください。
ちなみに x 座標において 1 とは 1 バイト分を指しますが、 y 座標においては 2 バイト分の大きさを指します。
つまりカーソルを x 座標において 1 右に移動させた場合のカーソル移動距離を 1 とすると、カーソルを y 座標において 1 下に移動させた場合のカーソル移動距離は 2 なのです。
よって、 y 座標で移動させる場合は x 座標で移動させる場合の 2 倍の距離を移動します。
説明はわかりにくいと思いますが、やってみるとわかります。
何かを動かすプログラミングをするときはこういったことを考慮しなければいけません。
少なくともそのプログラムがコマンドプロンプト上で実行される場合ではのことですが。


   3.main()以外の関数の説明
void output_hyou()
まずは横の表を作っていきます。
 i を 3 で初期化し、 14 未満までの範囲で実行するようにし、1回処理が終わるごとに i に +5 したものを i に格納しています。
よって、それぞれの処理で i は以下のように値を変化させます。
1回目:i = 3
2回目:i = 8
3回目:i = 13
処理後:i = 18
 co.Y は 0 のまま一定ですが、 co.X は 3 , 8 , 13 と値を格納していきます。
それぞれの x 座標で [ kの値 ] を出力させています。
 k は 0 で初期化されていますが、 ++k なので k をインクリメントした値が出力されます。
 k++ だと k の値が出力され、その後 k がインクリメントされます。
 [ は1バイト文字なので数値自体は 4 , 9 , 14 の x 座標値に出力されます。

次に縦の表を作っていきます。
基本的には横の表を作るのと同じです。
 i の変化は、
1回目:i = 1
2回目:i = 3
3回目:i = 5
処理後:i = 7

最後に "横   縦" という文字列を出力します。
 ( x , y ) = ( 7 , 7 ) の位置から出力させています。


void output_setumei()
まずは i の変化について見ていきましょう。
1回目 ~ 5回目:i = 1 ~ 5
処理後:i = 6
カーソルの x 座標値は一定です。
文字列を出力するまえにカーソル位置を移動させています。
ここでどの文字列を出力させるかの選定で switch 分を利用しています。
 i = 1 のとき、 ( x , y ) = ( 55 , 1) の位置から文字列が表示されます。
つまり、行ごとにどの文字列を表示させるか選定しているわけです。


int maru_batu(int count)
この関数は勝敗判定のための関数です。
勝敗が定まったときには指定の場所に勝敗結果通知を出力します。
では上から順に for 文を見ていきましょう。

1.
 i と j はそれぞれ 0 ~ 2 までの値をとります。
i = 0 : j = 0 ~ 2
i = 1 : j = 0 ~ 2
i = 2 : j = 0 ~ 2
という具合で値をとっていきます。
そして、 x_y[ j ][ i ] というふうになっています。
よって、 x_y[ 0 ~ 2 ][ i ] の値を足した値を ans に格納しています。
つまりこれは、 「横」 の勝敗判定だということがわかります。
ans が 3 なら ○ が勝ち 、 -3 なら × が勝ちというふうになっています。
なぜかというと、○ が入力された場合はその座標を表す x_y[][] に 1 を、× の場合は -1 を格納しているからです。
勝敗がついたならば return 1 、つまり 1 を返します。
勝敗がついていない場合は、最後に ans を 0 で初期化しています。
ここで初期化しないと、複合代入演算子による演算でどんどん ans の値が増えていってしまうだけですね。

2.
これは前回の for 文の i と j が逆になっているだけですね。
つまり、 「縦」 の勝敗判定だということがわかります。
それ以外は前回の for 文と全く同じです。

3.
この for 文とセットなのは2つの if 文と1つの式文です。
これは、右下がりの 「斜め」 の勝敗判定です。
右下がりの場合、 x_y[ 0 ][ 0 ] , x_y[ 1 ][ 1 ] , x_y[ 2 ][ 2 ] ですね。
だからまず for 文でそれを足した値を ans に格納しているのです。
あとは前の for 文と全く同じです。

4.
この for 文では最後の右上がりの 「斜め」 の勝敗判定です。
この場合、x_y[ 0 ][ 2 ] , x_y[ 1 ][ 1 ] , x_y[ 2 ][ 3 ] が該当しますね。
ということで、 for 文に行く前に j を 2 で初期化し、for 文の中でデクリメントしています。
そしてすべての値を足した値を ans に格納しています。
あとは前の for 文と全く同じです。


最後の if 文では引き分け判定をしています。
 count が 10 のとき ○ と × で埋め尽くされているということになりますので、引き分けとなり 1 を返します。
なぜ 10 なのかは後の関数の説明で明らかになります。


最後に勝敗がつかなかった場合には 0 を返しています。 


void input_marubatu()
この関数は入力に関する制御から勝敗判定まで一挙に取り扱っています。
まず 入力をさせる回数は 9 回だけでいいというのは分かりますね。
なぜなら ○ と × を置けるところは 9 個しかないのですから。
ということで、この for 文は 9 回繰り返されるようにしています。
そして i が偶数か奇数かで ○ を入力させるターンか × を入力させるターンかを決定しています。
今回は偶数なら ○ のターンとなります。
ここでは分かりやすく i を 2 で初期化しています(本当は 0 です)。
○ のターンであれば ○ を出力させる関数をもってきています。
そして勝敗判定をする関数を呼び出し、勝敗がついたら for 文を抜けて関数を終了させるようにしています。
× のターンも同じことをさせています。


void output_maru()
まずは入力項目を出力させています。
 p_y ははじめ "横   縦" が出力された y 座標と同じ値をもっています。
つまり、まず "横   縦" が出力された行の先頭にカーソルを置き、文字列を出力させる前に改行文字を使って改行したところに項目を出力させています。
改行することで、次の行の先頭にカーソルが移動されます。
改行したことで1つ下の行にカーソルが移ったので p_y + 1 としています。
そして、なぜカーソルを x 座標 8 と 13 にしているのかというと、これはただ単に"横"という文字と"縦"という文字の位置に合わせるためです。
こうすることによって、プレイヤーは何の値を入力しているのか明示的になります。
最後に p_y++ することで次からは1つ下の行で今やったことをさせています。

次の if 文では横1 ~ 3 、縦1 ~ 3 までの範囲外の値が入力されたとき、指定の場所にその場所には置けないのでもう一度入力するように促す文を出力させます。
最初の if (p_y == (y2 + 1)) では今から出力する促し文が前回出力した促し文と重複していないか判断して、重複している場合は、前回の促し文を消す関数を呼び出しています。
促し文は入力項目と同じ y 座標値に出力しますので重複している場合は p_y == (y2 + 1) となるのです。
促し文を出力した後は goto 文で先ほどの入力のところまでプログラムの処理を戻しています。

次の if 文ではすでに何かが置かれていないかどうかを判定して、おかれている場合は重複の確認と促し文の出力をしたあと goto 文で戻しています。
 ○ か × かがおかれている場合、必ずその位置を表す x_y[][] に 1 か -1 が格納されています。

入力が正常に終わったならば、その座標を表す x_y[][] に ○ 表す 1 を格納しています。
例えば、横[1] , 縦[2] に ○ がおかれた場合、 x_y[ 0 ][ 1 ] に 1 が格納されます。

次に x と y に格納された値を専用の座標値に変換する関数を呼んで、そのあとにその位置にカーソルを移動して ○ を出力しています。


void output_batu()
ほとんど先の関数と同じで、相違点は入力が正常に完了したあとにその位置を表す x_y[][] に × を表す -1 が格納されるということだけです。


void cls_new()
この関数では空白で埋め尽くすことによって文字などを消しています。
行ごとに文字列を消すのに十分な量の空白を上書きしていきます。
ちなみにこの関数は、前の試合の勝敗と説明のところ以外を消すのに使います。
たとえば、もう一度ゲームをするときなどに使います。


void cls_string()
重複した促し文を消すのにつかいます。
促し文が表示されている座標を指定して、そこに空白を上書きしています。


void output_before()
前回の試合の結果を指定の場所に出力します。
前の試合の勝敗は別のオブジェクトに記憶させているので、条件分岐でどれを出力させるか指定しています。


void cls_new_be()
前の試合の結果の表示を消すために使います。
勝敗を記憶するオブジェクトは過去5回までしか記憶できないので、6回目からはまた新たに記憶するオブジェクトの先頭から順に勝敗を記憶させていきます。
よって、表示もまた新たに1から作っていかなければならないのです。


void x_y_val()
x , y の値を専用の座標値に変換します。
x の場合は座標値と横表の値との関係性を利用して変換していますが、 y のように switch をつかって変換させるのが簡単です。
ただ取りうる値の範囲が広いときは switch だと面倒なので、前者のような関係性や法則性を利用するわけです。


    4.main関数の説明
とりあえず WORD 型の変数の宣言は無視してください。
不必要です。
do によってもう一度試合をするときはもう一度この処理をさせるようにさせています。
最初の if はもう一度処理をさせる場合のオブジェクトの初期化です。

次に順次関数を呼び出して処理を進めさせます。
そして勝敗がついて main() に帰ってきたらその勝敗の結果を専用のオブジェクトに格納します。
最後に終了する場合の説明ともう一度する場合の説明を出力して getchar() で入力された情報を取得しています。




あぁ~疲れた。
もう無理・・・・・。
ていうか後半ものすごく雑だなぁ。
説明も下手だし。
ということでわからないところがあったらコメントください。
個別に返答していきます。

ではまた今度。

拍手[1回]

PR
author : gp-hss ×

COMMENT

ADD YOUR COMMENT

NAME
TITLE
MAIL
URL
COMMENT
PASS

TRACKBACK

TRACKBACK URL
忍者ブログ | [PR]
 | PAGE TOP
write | reply | admin