2015年03月04日

ランダムがいかにランダムっぽいかって話


ちょっとこんな記事読んで意外と面白かったので、
たまには真面目な話書こうかと思う。

この記事は、
「音楽聞き放題のサイトでランダム再生すると、完全ランダムじゃなくて、大人の事情が入ってないか?」
って感じるってことについて、色々語られてます。

------------------------------------------------------------------------
ギャンブラーの誤謬

たとえばコインを5回投げて、4回目まで連続して表が出たとします。最後の1回は、表か裏か、どちらが出そうでしょうか。次こそ裏が出るのではないか、そう思ってしまいそうです……。この心理傾向を、ギャンブラーの誤謬と呼びます。しかし実際には、何度コインを投げたところで、表と裏が出る確率はそれぞれ1/2ずつなのです。
------------------------------------------------------------------------
こんな1文があって、なかなか面白いなと思いました。
確かに、人間ってそんな考え方するよねと。自分にもそういう考え方する事あるなぁ、と。
パチンコもソシャゲのガチャも、完全抽選方式だから、何回回しても同じ確率なのよね。
でも「そろそろ来るやろ!?」とかいう謎の自信で次を回す...。

------------------------------------------------------------------------
『Spotify』代表のババール・ザファール氏は「私たちの脳は素晴らしい法則発見器で、実際には存在しない法則すらも見つけてしまう」と述べています。開発者たちは、ユーザが『さもランダムであるかのように感じられること』が重要だと悟ったのでした。
------------------------------------------------------------------------
なるほどな、と。
で、よくよく考えてみると、意外と自分でもプログラム書く時に、結構乱数には気を使ってたなと。

例えば、ボタンを押すと、画面上のランダムな座標にエフェクトが出るようなプログラムを組むとする。
ボタンが連打される事を想定して。

これ、実際、完全ランダムで座標設定すると、思ったより微妙だったんですよね。
で、僕は、色々工夫しました。
画面を4分割して、各象限からに連続では出ないようにしました。
このプログラムに関しては、これで意外とそれっぽくなったんで、それで終わりましたけども。

他にも、ボタンを押すと、画面中央から、自由落下する○を上向きに放出するプログラムを組むとする。
ボタンを連打すると、画面中央から左右ばらばらに、○が放物線を描いて落ちていく。

これが、本当にそのまま乱数で適当にやると、かなり微妙だったんですね...。
びっくりするくらい。
結構いろいろ悩みましたけど、とりあえず、左右は必ず交互になるようにしました。
これだけでも、やっぱ微妙だったので、X軸ベクトルの強さも、強弱がある程度交互に、
さらに重力加速度も物によって変え、これも強弱バラつくように工夫しました。

この辺までやって、初めてそれっぽく見えたんですけども、
「ランダムってプログラマのセンスが出るんだなー」とか、
その時は、あんま思ってなかったんですよねw
んで、この記事読んだときに「あぁ、そういえば」って思い出した訳です。

結局、ゲームや映像関連のプログラマも、この記事みたいなシステムのプログラマも、
結構似通ったところで悩んだり工夫したりしてるんだなぁと、思いましたまる。

あんましまとまってないけど終わりです、続きません。以上!




posted by あずお at 01:28| Comment(0) | TrackBack(0) | プログラム関連 | このブログの読者になる | 更新情報をチェックする

2013年09月15日

ゲームプログラマになろう010「アドレス操作」

前回の項で、アドレスの概念を学んでもらいました。今回は、実際にアドレスを取得し、操作するための記述方法を書いていきます。
頭がこんがらがらないように、ゆっくり読み解いて下さい。



▽アドレスを取得・操作する
まずは、アドレスを取得する方法です。
「aaa」という変数を用意して、その変数のアドレスを「pointer」という変数に取得します。
--------------------------------------------------------
int aaa;
int *pointer;
pointer = &aaa; // 「aaa」のアドレスを、「pointer」に入れる
--------------------------------------------------------
これで、アドレスの取得が完了です。
アドレスの取得には「int *」という変数の型を使用します。
「*」(ポインタ)が付くと、「その型のアドレスを入れる型」という意味になります。
char型の変数のアドレスは、「char *」型で取得しますし、
short型の変数のアドレスは、「short *」型で取得します。

「○○ *」は、本質は全て4BYTEの変数ですが、演算などをすると
意味合いが大きく変わってくるので、必ず、同じ型のポインタで受け取りましょう。

変数のアドレスがほしい場合は、変数名の前に「&」を記述します。
これで、アドレスが取得できます。


次に、取得したアドレスの中身を操作します。
アドレスの示す先に、値を入れましょう。
--------------------------------------------------------
int aaa;
int *pointer;
pointer = &aaa; // 「aaa」のアドレスを、「pointer」に入れる
*pointer = 10; // 「pointer」が示すアドレスの中に、「10」を入れる
--------------------------------------------------------
こうすると、「pointer」が示すアドレスの中に、「10」を入れます。
つまり、「aaa」に「10」が入ります。
「*pointer」が、「中身」という意味になります。
ですので、「pointer」はアドレスですが、
「*pointer」は、実数です。アドレスではありません。
この辺が、慣れないとややこしい。



▽アドレスの演算
アドレスは、足し算・引き算ができます。
これができると、かなり強いのですが、アドレス操作の項では、
なかなかに難しい箇所ですので、確実に覚えていってください。

アドレスに1足すと、次のアドレスを指します。
次のようなプログラムが記述できます。

--------------------------------------------------------
int aaa[10];
int *pointer;
pointer = &aaa[0]; // 「配列aaa」の先頭アドレスを、「pointer」に入れる
for(int i=0; i<10; i++)
{
*pointer = i;
pointer++;
}
--------------------------------------------------------
上記プログラムで、何ができるか、だいたい予想できますよね?
そうです、「aaa[0]〜aaa[9]」に、「0〜9」の値を入れる事ができます。
アドレスに足し算や引き算をすると、次のアドレスや、前のアドレスを参照できます。

ここで注意すべきは、型によって、指されるアドレスが変わってくる事です。
前回の表を、思い出してみましょう。

「char aaa[10]」だったら...、
アドレス変数 
0x0000 0000aaa[0]
0x0000 0001aaa[1]
0x0000 0002aaa[2]
 ・
 ・
 ・
 
0x0000 0009aaa[9]
この場合、「pointer = &aaa[0]」で、
「pointer」には「0x0000 0000」が入ります。
1足すと、「0x0000 0001」となります。

ですが「short aaa[10]」だったら...、
アドレス変数 
0x0000 0000aaa[0]
0x0000 0001 
0x0000 0002aaa[1]
0x0000 0003 
0x0000 0004aaa[2]
 ・
 ・
 ・
 
0x0000 0012aaa[9]
この場合、「pointer = &aaa[0]」に、
1足すと、「0x0000 0002」が入ります。
なので、安心して「*pointer = 1」を入れて大丈夫な訳です。

これは、「short *pointer;」変数なので、
1足しただけで、アドレス自体は2増えてるのです。
「int *pointer;」だったら、1足すと、4増えます。

また、上記の状況で、「0x0000 0001」に値を入れると、
とても変な事になるので、気を付けて下さい。



▽NULLアドレス
アドレス変数も、普通の変数と同様に、
変数宣言時は、訳の分からない値が入ってます。
なので、通常の変数でいう「0初期化」と同じような事をしてあげて下さい。

--------------------------------------------------------
int *pointer = NULL;
--------------------------------------------------------
これでOKです。
NULL(ぬる)は、値としては「0」です。
一般的に、アドレスとしての「0」という意味合いで、「\0」と表記します。
ヌルポインタ、略して「ぬるぽ」です。

ヌルのアドレスを操作しようとすると、訳分からんとこのアドレス操作する事になるので、
絶対にしないようにしましょう。
具体的には、下記のような記述をします。
--------------------------------------------------------
int *pointer = NULL;
if( pointer ==NULL )
{
*pointer = 10;
}
--------------------------------------------------------




▽練習問題
それでは、練習問題です。
それぞれ、下記の処理で、指定された変数に、どんな値が入るか考えてみて下さい。

練習問題1
「q1に入る値を答えよ」
--------------------------------------------------------

int q1 = 0;
int *pQ1 = &q1;
*pQ1 = 15;
--------------------------------------------------------


練習問題2
「q2[0]〜q2[4]に入る値を答えよ」
--------------------------------------------------------

int q2[5] = { 0 };
int *pQ2 = &q2[0];

*pQ2 = 10;
*(pQ2 + 2) += 5;
pQ2 += 3;
*pQ2 += 1;
--------------------------------------------------------

練習問題3
「q3[0]〜q3[4]に入る値を答えよ」
--------------------------------------------------------

int q3[5] = { 0, 1, 2, 3, 4 };
int *pQ3[5] = { &q3[0], &q3[1], &q3[2], &q3[3], &q3[4] };

*(pQ3[2] + 1) = (*(pQ3[1] + 3)) + 5;
--------------------------------------------------------

↓答え&解説
010_アドレス操作.cpp



posted by あずお at 14:23| Comment(0) | TrackBack(0) | プログラム関連 | このブログの読者になる | 更新情報をチェックする

2013年07月29日

ゲームプログラマになろう009「アドレスという概念」

さてさて。かなり日が空いてしまいましたが。

今までの講座で、だいたいの事はできるようになったのですが、
プログラムは、ソースをできるだけ短く、分かりやすくまとめるのが基本ですので。

うまくまとめる記述の方法をどんどん覚えていきましょう。



▽アドレスとは
アドレスとは、その変数などが、メモリ上のどこに配置されているかを明確にした「番地」です。
これだけじゃ分からんとは思うのですが、名前の通り、住所です。
住所とはいっても番地だけ、つまりただの「数字」です。

1BYTEにつき、1つずつ、番地が割り振られています。

変数を宣言すると、メモリ上に宣言した変数のサイズ分、
「ここ、なんちゃら変数さんが使用してますよ」という情報が保持されます。
これは「メモリ確保」とも呼ばれます。

メモリは、まぁ、だいたいWindowsXPなら、2GB〜3GBくらいあるだろうし、
Windows7とか8とかなら、8GBとか普通にもってますよね。

1BYTEのchar型変数なら、8*1024*1024*1024 個、変数宣言すると、
8GBのメモリがいっぱいになる訳ですが、まぁ、そんなに使うことはまずないですわw



▽表記する場合
アドレスは、基本的に十六進数で表記します。
十六進数は、(0x)か(H')を先頭に記述して表記します。
C言語の記述は(0x)なので、ここでは0x0000などと記述します。
0〜9の数字と、A〜Fのアルファベットで、0〜15を、1桁で表示する記述法です。
十進数の65535は、十六進数では0xFFFFと表記されます。

32bitマシンの場合、アドレスは32bit(4Byte)の数値です。
64bitマシンだったら、64bitですが、ここでは、32bitで説明します。


たとえば、
--------------------------------------------------------
char aaa; // 1Byte
char bbb; // 1Byte
short ccc; // 2Byte
long ddd; // 4Byte
--------------------------------------------------------
と、変数宣言した場合、下のように、
変数がメモリ上に配置されます。

アドレス変数 
0x0000 0000aaa
0x0000 0001bbb
0x0000 0002ccc
0x0000 0003 
0x0000 0004ddd
0x0000 0005 
0x0000 0006 
0x0000 0007 

こんな感じで、配置されます。
本来は、[0x0000 0000] なんてアドレスはOSが使ってると思うので、
実際に割り振られる事は絶対にありませんが。

普通の変数宣言では、必ず続きに宣言される保証はありません。
なので、メモリ空間上は、bbbが[0x0000 0000]に宣言され、
aaaが[0x0000 0001]に確保されるかも知れません。
それは、コンパイラとかOSとか状況次第です。

ですが、配列は、必ず連続して、メモリに確保されます。
--------------------------------------------------------
char aTable[4]; // 1Byte * 4
short bTable[2]; // 2Byte * 2
long cTable[3]; // 4Byte * 3
--------------------------------------------------------
だと、↓のようになります。
アドレス変数 
0x0000 0000aTable[0]
0x0000 0001aTable[1]
0x0000 0002aTable[2]
0x0000 0003aTable[3]
0x0000 0004bTable[0]
0x0000 0005 
0x0000 0006bTable[1]
0x0000 0007 
0x0000 0008cTable[0] 
0x0000 0009 
0x0000 000A 
0x0000 000B 
0x0000 000C cTable[1]
0x0000 000D 
0x0000 000E 
0x0000 000F 
0x0000 0010cTable[2]
0x0000 0011 
0x0000 0012 
0x0000 0013 
こんな感じに配置されます。
まぁ、そんなに難しくないっしょ?

でも、この「アドレス」という概念は、C言語やC++を勉強する上で、
1つ目の壁になる部分であるようです。

そうですね。
ギターで言うと、「F」のコードみたいな存在ですかね。
ここをキッチリ理解しないと、今後の話がなかなかよく分からなくなると思うので、
十分に理解して次に進んでほしいところです。

今日は、記述関連はなしで、概念の紹介のみでこの辺で終わっておきます。
なので、今回は、練習問題などは無しです。

次回から、アドレスを実際に取得して、変数操作をしますので!


posted by あずお at 23:41| Comment(0) | TrackBack(0) | プログラム関連 | このブログの読者になる | 更新情報をチェックする

2013年05月27日

ゲームプログラマになろう008「関数」

一応、
今まで勉強した分で、プログラムとしては、だいたい何でもできるようにはなりました。
まぁ、これだけの知識で書いてしまうと、プログラムのソース行が膨大になってしまいますので、
デバッグやら、確認やらが大変になってしまいます。

プログラムは、同じ動作をするなら、「簡潔に」「短く」「分かりやすく」
書く事が重要です。

一昔前は、処理速度やら、メモリの使用量やら、いろいろ気にしながら書く必要があったのですが、
最近のPCは、演算処理も早くメモリも大量に装備してるので、適当にプログラム書いても動きます(笑)
携帯ゲーム機とかは、その辺、気にして書く必要が、まだ有りますが...。
それでも、だいぶマシになってきました。
最近のスマホやPSVitaやらは、なかなか侮れないメモリ持ってますよ。

と言う訳で、最近のプログラマに求められるスキルは、
「人間が見て、解読しやすいコードを書くこと」になりつつあります。
まぁ、これは僕の意見ですけどね。

パチンコなんかは、バグ1つは、完全に致命傷ですから、
いかに解読しやすいコードを書けるかは、かなり重要です。
もちろん、処理落ちも致命傷なので、無駄な処理は書きませんけどね。


なので!
これからの講座は、主に、ソースをキレイにまとめる機能の講座になっていきます。
いろいろ使いこなして、ソースの行数を減らし、解読しやすいソースを書いていって下さい。


▽関数とは
で、今回の項目「関数(かんすう)」です。
関数は、前にもちょろっとお話ししましたけど、「処理をまとめたもの」です。
今までも「メイン関数」の中に処理を書いてきましたが、
それ以外の関数を「サブ関数」or「サブルーチン」と呼び、
自分で、いくらでも作成する事ができます。


▽関数が持つ要素
最初に、プログラムは「入力」「演算」「出力」の組み合わせと書きましたが、
関数というのは、まさにそれを具現化したような機能です。

「入力」→「引数(ひきすう)」
「演算」→「関数内に記述する処理」
「出力」→「戻り値」

という、それぞれの機能があります。

・引数
引数は、関数に対して、渡すことができる値です。
変数を渡したり、定数を渡したり色々できます。

・関数内に記述する処理
関数は、{}で括り、その中に処理を記述します。
この辺は、メイン関数も同じですよね。

・戻り値
その関数が返す値です。
受け取って、結果を確認するなどに使えます。


▽関数の記述書式
百聞は一見に如かず。実際に書いてみましょう。
といっても、記述方法は、メイン関数で見慣れてるとは思いますので、
1つ何かの機能を決めて、サブルーチンを作成してみます。

・機能:引数を2つ受け取って、その2つの値を足した値を戻り値として返す関数
--------------------------------------------------
int AddCalc(int a, int b)
{
int ans = a + b;
return ans;
}
--------------------------------------------------

こんな感じです。
んじゃ、この記述の解説をしていきます。

1行目が、関数の形を書いてます。
左端の「int」が「戻り値がint型」であることを表しています。
真ん中の「AddCalc」は、関数の名前です。
被ってなければ、何でも適当に名前を付けることができます。
使える文字の制限は、変数名の時と同じです。

右の「(int a, int b)」が引数です。
int型のaという引数と、int型のbという引数の2つ引数があります。
2つに限らず、「,」で区切って、いくつでも増やすことができます。(スタックが許す限り)
左から順に、第1引数、第2引数、と数えます。
これは不思議なことに、第0引数とは言いませんw

関数の中で変数宣言している「int ans」は、ローカル変数といいます。
関数の中に限らず、ローカル変数は{}で括った中でのみ、
変数として宣言されます。
なので、別の{}の中で、同じ名前の変数があっても問題はありません。
それらは、別の変数として、扱われます。

ちなみに、引数も、関数内のローカル変数と同じ扱いです。
最後の「return ans;」は、変数「ans」を、戻り値として返す記述です。


このサブルーチンを、メインルーチンから呼び出すと、
↓こんな感じになります。
--------------------------------------------------
int AddCalc(int a, int b);

void main()
{
int add;
add = AddCalc(10, 20);
}
--------------------------------------------------

一番上のAddCalcは、関数の「プロトタイプ宣言」と言います。
「AddCalc」という関数がありますよ、戻り値は「int」で、引数が2つありますよ、
と言うことを、プログラムに教える役割があります。

「add = AddCalc(10, 20);」で、10+20の計算結果を、
返ってきた戻り値で「add」変数で受け取っています。



処理をまとめる事。
それは、全てのソース整理のはじまりなり。
まだまだ、ソース整理機能は、いっぱいあります。
とりあえず、今回は、関数の機能を覚えてもらえれば。


▽練習問題
今回も練習問題出しますー。

練習問題1
 引数を2つ受け取り、比較し、第1引数が小さい場合は「1」、
 第2引数が小さい場合は「-1」、同じ場合は「0」を返す関数を作成する。
練習問題2
 引数を1つ受け取り、その数をお金に見立て、
 各お札・小銭が最小で何枚で表せるかを表示する関数を作成する。
 例)「532」を受け取った場合、「500円玉(1枚)、10円玉(3枚)、1円玉(2枚)」
練習問題3
 0をグー、1をチョキ、2をパーに見立て、
 引数を2つ受け取り、「第1引数VS第2引数」のじゃんけん結果として、
 「0:第1引数の勝ち」「1:第2引数の勝ち」「2:あいこ」を、
 戻り値として返す関数を作成する。
練習問題4
 練習問題3の、勝敗判定を、if文を極力使用しないような記述で作成する。

↓答えはコチラ
008_関数.cpp



posted by あずお at 23:32| Comment(0) | TrackBack(0) | プログラム関連 | このブログの読者になる | 更新情報をチェックする

2013年05月16日

ゲームプログラマになろう007「配列とループ」

さてさて、またまた結構日が空いてしまいましたが。
今日は「配列(はいれつ)」と、「ループ操作」を記述していきます。
ここまで来たら、もう何でもできます。
かなり、ゲームっぽいこともできます。
ではでは、説明〜。


▽配列
まず、配列とは何ぞや。と。
配列とは、変数がいっぱい並んだものと考えて下さい。
いっぱいの変数を「要素(ようそ)」と呼びます。
番号で管理されます。管理番号を「添え字(そえじ)」とか呼びます。
--------------------------------------------------
int table[10];
--------------------------------------------------
こんな感じで、変数宣言します。
すると、tableという10個の要素を持つ配列が宣言されます。

--------------------------------------------------
int table[10];
table[0] = 10;
table[1] = 3;
--------------------------------------------------
アクセスは、↑こんな感じでできます。
「table[10]」だと、0〜9の10個の要素があります。
ここ注意です!
「0〜9」です。
これが、プログラマが0から数を数えちゃう職業病が発生するメカニズムです。
--------------------------------------------------
int table[10];
table[10] = 10;
--------------------------------------------------
ちなみに、↑これはできません。
Windowsでやると、強制終了します。
他のハードでやると、強制終了しないまでも、
だいたいは全然関係無い変数に値を入れちゃったり、
すごく見つけにくいバグの原因となりますので、
配列を操作する場合は、必ず、要素数の範囲内で行って下さい。

▽配列の初期化
配列は、宣言時のみ、初期化ができます。
結構、省略して書けたりするので、色々覚えて下さい。

--------------------------------------------------
int table[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
--------------------------------------------------
こう書く事で、配列が宣言されたと同時に、値が代入されます。
table[0]に0が、table[1]に1が...table[9]に9が代入されます。
初期化用に書いた数値を「初期化子(しょきかし)」と呼びます。

--------------------------------------------------
int table[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
--------------------------------------------------
初期化をする場合、宣言時の要素数を省略する事もできます。
省略すると、初期化子の数が、配列の要素数となります。
この場合は、0〜9の10個の配列です。

--------------------------------------------------
int table[] = { 0, 1, 2, 3, 4 };
--------------------------------------------------
↑こんな感じだと、tableの要素数は、0〜4の5つになります。

--------------------------------------------------
int table[10] = { 0, 1, 2, 3, 4 };
--------------------------------------------------
↑こんな感じに書くと、0〜9の10個の要素を持つ配列が宣言され、
0〜4には0〜4が、記述されていない残りの5〜9には、固定で「0」が代入されます。

--------------------------------------------------
int table[100] = { 0 };
--------------------------------------------------
全部0入れたい場合は、これでOK。
100個も0書いてられないでしょw

ちなみに、初期化子を1つも書かない場合は初期化を行いませんので、
その配列には、どんな値が入っているかは保証されません。
0を入れたい場合は、必ず上記のように初期化して下さい。

--------------------------------------------------
int table[10] = {
0, // table[0] = 0
1, // table[1] = 1
2, // table[2] = 2
3, // table[3] = 3
4, // table[4] = 4
};
--------------------------------------------------

もちろん、複数行にまたがって書いても良いですよ。
また、最後の要素の後の , は、書いても書かなくてもどっちでもOKです。


▽多次元配列
ここまで来たんで、一気に覚えちゃいましょう。
多次元配列!
2次元や3次元、いくらでも作れてしまいます!
--------------------------------------------------
int table[5][10];
--------------------------------------------------
この場合、10個要素のある配列が、5個用意された、と考えて下さい。

--------------------------------------------------
table[0][0] = 0;
table[0][1] = 1;
table[1][0] = 10;
--------------------------------------------------
アクセスの方法も、そんなに難しくなく、1次元配列と同じようにアクセスできます。

初期化は、改行したりすると、見やすくなります。
--------------------------------------------------
int table[5][10] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
};
--------------------------------------------------

--------------------------------------------------
int table[5][10] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, },
{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, },
{ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, },
};
--------------------------------------------------

{}を{}で囲っても分かりやすいかもね。
2次元までなら改行で良いけど、3次元配列までいくと
{}で括った方が良いです。見にくいので。

--------------------------------------------------
int table[][10] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
};
--------------------------------------------------

多次元配列では、一番左側の要素数だけ、省略できます。
2次元配列で説明すると、
例えば、10個初期化子があった場合、2×5の配列なのか、
5×2の配列なのか、分かんないですよね?
だから、省けるのは1つだけになってます。


▽ループ処理
さてさて、配列と一緒に使って、驚異的なパワーを発するのが、ループ処理。
ちなみに、プログラムは、基本的に、上から下に進みますけど、
ほぼ唯一、上に戻る事ができる処理です。
故に、使い間違えると、永久に下まで行かない...、
俗に言う永久ループにハマってしまったりするので注意が必要です。


▽whileループ処理
while構文から説明します。
記述は、下記のようになります
--------------------------------------------------
while( 条件文 )
{
繰り返したい制御
}
--------------------------------------------------

条件文は、if文と同じ物が使えます。
条件がTRUEの間は、{}で括った中の制御を繰り返します。
条件がFALSEになるまでずっと繰り返します。
ちなみに、このwhileは、{}の制御をする前に、条件をチェックします。
なので、条件文がいきなりFALSEだった場合、1度も{}の中の制御をしない場合もあります。

--------------------------------------------------
do
{
繰り返したい制御
} while( 条件文 )
--------------------------------------------------

これは、後チェックの書き方です。
{}の中の処理を実行した後、条件をチェックし、
TRUEなら、また{}内の処理を実行、FALSEなら、ループを抜けます。

whileの使用例)
--------------------------------------------------
int num = 0;
while( num < 10 )
{
printf("%d\n", num);
num++;
}
--------------------------------------------------

これで、numが0〜9まで、10回ループができます。
あ、説明わすれてたかも...。「++」って記号は、変数に1足す記号です。
インクリメントとも呼びます。
1引くのも「--」であります。デクリメントと呼びます。

また、break; を使って、while構文を抜ける事もできます。
--------------------------------------------------
int num = 0;
while( 1 )
{
if( num >= 10 ) break;
printf("%d\n", num);
num++;
}
--------------------------------------------------

これは、さっきと同じ挙動をします。
while(1) で永久ループを作っておいて、
{}の中で、ループを抜けるかチェックを掛けるやり方です。
何となくですが、こっちの方がポピュラーな気がします。

まぁ、とにかくwhileは、使い方を間違うと簡単に永久ループしてしまうので、
使い方には注意しましょう。


▽forループ処理
こっちは、主に回数を指定してループしたい時に使います。
まぁ、そういう使い方以外でも使えるんですが、だいたいそんな感じで使います。
記述は、下記のようになります
--------------------------------------------------
for(初期化; 条件文; ループ後処理)
{
繰り返したい制御
}
--------------------------------------------------

「初期化」は、ループに入った時に1度だけ呼び出される処理です。
「条件文」は、whileと同じくループの条件です。
TRUEの間はループし、FALSEになったらfor文を抜けます。
この条件チェックは、whileで言うと、前チェックの方です。
なので、1度も{}内の処理を行わない可能性もあります。
「ループ後処理」は、{}の1ループ処理が終わった後、
次の条件文チェック前にする処理です。

forの使用例)
--------------------------------------------------
int i;
for(i=0; i<10; i++)
{
printf("%d\n", i);
}
--------------------------------------------------

while構文より、すごく、10回ループしますよ、って感じしません?w
ループ用のカウンタとしては、よく「i」という変数が使われます。
i が 0〜9 の間、ループされます。

0〜9の10回...。
配列のあれと組み合わせると...。
となりますよね、もちろん。


▽ループと配列を応用してみる
使用例)
--------------------------------------------------
int i;
int table[10] = { 0 };
// 値を入れる
for(i=0; i<10; i++)
{
table[i] = i;
}
// 値を表示する
for(i=0; i<10; i++)
{
printf("%d\n", i);
}
--------------------------------------------------


2次元配列もごらんの通り!
--------------------------------------------------
int x;
int y;
int counter = 0;
int table[5][10] = { 0 };
// 値を入れる
for(y=0; y<5; y++)
{
for(x=0; x<10; x++)
{
table[y][x] = counter;
counter++;
}
}
// 値を表示する
for(y=0; y<5; y++)
{
for(x=0; x<10; x++)
{
printf("%d, ", table[y][x]);
}
}
--------------------------------------------------

良い感じに、2次元配列にも、値を入れ、値を表示できます!


▽練習問題
ふぅ、今日はちょっと長かったな...。
今回も練習問題出すんで、頑張って下さい。

練習問題1
 要素10個の配列を宣言し、0〜9の値をそれぞれ入れ、順に表示する。
 ※初期化は使わない
練習問題2
 scanfで任意の値を入力させる。
 要素10個の配列を宣言し、要素[0]に、入力した値を、
 要素[1]以降には、それぞれ「1つ前の要素の値+1」の値を入れ、順に表示する。
練習問題3
 scanfで任意の値を5つ入力させる。
 要素5個の配列を宣言し、入力した5つの数値を、
 小さい値から順に配列に入れ、順に表示する。
練習問題4
 ゲームのスコアランキングプログラムを作成する。
 決まり1
  全部で10位までのランキングを作成。
  デフォルトで、1位から順に、100, 90, 80, 70, 60, 50, 40, 30, 20, 10ポイント
  のランキングを作成しておく。
 決まり2
  scanfで、今回のスコアを入力する。
  そのスコアを、正しい位置に挿入する。
 決まり3
  そのスコアを表示する。
 Ex
  スコア表示後、scanfで数値を入力させ、0なら「終了」、
  0以外ならもう一度、スコア入力に戻る。

↓答えはコチラ
007_配列とループ.cpp





posted by あずお at 01:07| Comment(0) | TrackBack(0) | プログラム関連 | このブログの読者になる | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。