作れるゲーム、作れないゲーム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
プーコ

本格的な野球のプログラムを作っているのですが・・・

#1

投稿記事 by プーコ » 18年前

何度もすいません(TT)
野球のプログラムを作っています!1回から9回までとりあえず打者がヒットと2ベース、スリーベース、HR、四死球、アウトのどれかになるようにしたいのです。

問題が生じました。
1番から9番打者までのヒット、2ベース、スリーベース、HR,四死球の確率を設定して乱数を取るのですが、
1打者につき5つの確率をどのように繰り返していいかわかりません。

また、どのようにしてベースを埋めていけばいいのか、なかなか思いつきません。

何かいい方法はないでしょうか?
質問ばかりすいません(TT)

box

Re:本格的な野球のプログラムを作っているのですが・・・

#2

投稿記事 by box » 18年前

> また、どのようにしてベースを埋めていけばいいのか、なかなか思いつきません。

一つの例を挙げてみます。

1バイトの変数を用意し、いちばん右のビットを第0ビット、
いちばん左のビットを第7ビットと呼ぶことにします。

第0ビットはバッターが打席に立っているかいないかを表わすことにします。
第1~第3の各ビットは、1塁~3塁の各ベースにランナーがいるかどうかを
表わすことにします。ビットが立っていれば、そのベースにランナーがいる状態です。

そうすると、バッターが打席に立っているときの
バッターとランナーの状態を1バイト(8ビット)で表わすと、
 ・ランナーなし(00000001)
 ・1塁 (00000011)
 ・2塁 (00000101)
 ・1、2塁 (00000111)
 ・3塁 (00001001)
 ・1、3塁 (00001011)
 ・2、3塁 (00001101)
 ・満塁 (00001111)
の8パターンのいずれかになります。

ヒットエンドランのように、1塁ランナーがシングルヒットで一挙に3塁へ
進むことを考えないとすると、
打撃結果によってバッターとランナーの塁を進めることは、
上記8パターンを所定のビットだけ左へシフトすることに相当します。
つまり、シングルヒットまたは四死球ならば1ビット左へシフトし、
ホームランならば4ビット左へシフトします。

シフトした結果、第0~第3の各ビットが、
その時点でのバッター(打席に立っていない状態)とランナーの状態を
表わします。
そして、第4~第7ビットのうち、オンになっているビットの数が
当該の打撃結果によって加わる得点数を表わします。

box

Re:本格的な野球のプログラムを作っているのですが・・・

#3

投稿記事 by box » 18年前

> つまり、シングルヒットまたは四死球ならば1ビット左へシフトし、

四死球の場合、単純に1ビットシフトするわけにはいかないですね。

バッターの第0ビットを1ビット左へシフトしようとする際に、
第1ビット(1塁)の状態を見て、さらに必要があれば
第2ビット(2塁)や第3ビット(3塁)の状態も見てから
シフトしないと、野球のルールと合わなくなります。

box

Re:本格的な野球のプログラムを作っているのですが・・・

#4

投稿記事 by box » 18年前

> 1番から9番打者までのヒット、2ベース、スリーベース、HR,四死球の確率を設定して乱数を取るのですが、
> 1打者につき5つの確率をどのように繰り返していいかわかりません。

[9][5]の配列を用意し、あらかじめ適切に設定しておいた初期値にしたがって
打撃結果を決めればよいのではないでしょうか。

やそ

Re:本格的な野球のプログラムを作っているのですが・・・

#5

投稿記事 by やそ » 18年前

本格的というなら、ボークでの進塁、けん制アウト、盗塁、タッチアップ、振り逃げとかは?
ランナーが居る場合、ダブルプレイやトリプルプレイだって考えられますよ。
アルゴリズムというより、野球のルール、戦略などについてもっと理解を深めるのが先決じゃないでしょうか?
どのような攻撃パターンが考えられ、結果、成功したときのパターン(大成功、成功)、失敗したときのパターン。
いろんな場面を想定し、全ての動きを論理的に捉える思考が必要かと。
ランナー1塁でバッターがシングルヒットを打った場合でもランナーの走力と守備力、打球の行方、返球までの時間により3塁に進めるかもしれません。さらに返球がそれればホームインだってw
それらを全体の確率からはじき出して反映させられれば、かなり本格的だと思います。

どうしたら出来るのか?ではなくて
何をどうしたいのか。またそれはどこまで細かく考えて処理するのか?
を明確にするほうが先じゃないかな?

boxさんの考えるように2進数で考えてBit演算するのもいい考えですし、各桁それぞれを別の変数で確保したって良いわけです。
プーコさんはバッターを基準に考えておられるようですね。
特に監督からのサインとかバッターの打率、クセ、相手の投手力、守備力、風向きなどを考えない完全確率ならば4bit(もしくは変数4個)でそれぞれの塁に対応させればよいのでは?

あとは刻々と変わる状況ごとにどのように(バッターの結果の)確率をとっていくかですね。

余計にハードルを上げて混乱させてしまうようなら申し訳ない、スルーしていいです。。。

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#6

投稿記事 by プーコ » 18年前

boxさん、やそさん、ありがとうございます。
本格的と言う表現が誤りでした!今私は完全確率の簡単な野球のプログラムを作りたいのです。
力では走力や、ボーク、またはエラーやイレギュラー等の細部をプログラムに入れる事はできないです(TT)
また、bit演算をした事がないのですが、c言語の話ですよね?

また、配列で、P[9][5]というものはできるのですか?(P[1][1]でヒット、P[1][2]でツーベース等)

バグ

Re:本格的な野球のプログラムを作っているのですが・・・

#7

投稿記事 by バグ » 18年前

例えば、1番バッターのデータを…

ヒット 20%
2塁打  5%
3塁打  3%
本塁打  2%
四死球 10%
アウト 60%

みたいに設定するとします。
そうすると、下記のように処理できるかと思います。

a = rand() % 100;

if (a < 20) ヒット
else if (a < 25) 2塁打
else if (a < 28) 3塁打
else if (a < 30) 本塁打
else if (a < 40) 四死球
else アウト

と、こんな感じでどうでしょうか?
if文の判定用の数値を変数にしてれば打者毎に違う確率になると思いますよ。

バグ

Re:本格的な野球のプログラムを作っているのですが・・・

#8

投稿記事 by バグ » 18年前

コンソールアプリで画面だけ作ってみました(笑)

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#9

投稿記事 by プーコ » 18年前

バグさんありがとうございます!!
私は今こんな感じでプログラムを作っています!!
とりあえず、ランナーを考えずにバッターの結果のみを表しているだけです。
boxさんのアドバイスを参考にすると大丈夫でした!!ありがとうございます。
#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <time.h>

int main()

{

int e,o,s,k;

float ran0,P[9][5];

srand((unsigned)time( NULL ));

/*イニング数、アウト数、得点、打順の初期設定*/

e=1; o=0; s=0; k=1;

/*1から9番までの打者のヒット、二塁打、三塁打、HR、四死球の確立の設定*/

P[1][1]=0.25;

P[1][2]=0.30;

P[1][3]=0.31;

P[1][4]=0.34;

P[1][5]=0.36;



P[2][1]=0.23;

P[2][2]=0.25;

P[2][3]=0.26;

P[2][4]=0.27;

P[2][5]=0.31;



P[3][1]=0.23;

P[3][2]=0.26;

P[3][3]=0.27;

P[3][4]=0.34;

P[3][5]=0.39;



P[4][1]=0.22;

P[4][2]=0.24;

P[4][3]=0.24;

P[4][4]=0.34;

P[4][5]=0.38;



P[5][1]=0.26;

P[5][2]=0.30;

P[5][3]=0.31;

P[5][4]=0.32;

P[5][5]=0.37;



P[6][1]=0.20;

P[6][2]=0.23;

P[6][3]=0.24;

P[6][4]=0.26;

P[6][5]=0.30;



P[7][1]=0.30;

P[7][2]=0.32;

P[7][3]=0.33;

P[7][4]=0.34;

P[7][5]=0.38;



P[8][1]=0.13;

P[8][2]=0.18;

P[8][3]=0.20;

P[8][4]=0.21;

P[8][5]=0.25;



P[9][1]=0.36;

P[9][2]=0.38;

P[9][3]=0.40;

P[9][4]=0.45;

P[9][5]=0.50;







for(k==1;k<=9;k++)

{

ran0 = rand()/(RAND_MAX+1.0);

if(0.0<ran0&&ran0<P[k][1])

{

printf(" %d番打者 ヒットです!\n",k);

}

else if(P[k][1]<ran0&&ran0<P[k][2])

{

printf(" %d番打者 ツーベースヒットです!!\n",k);

}

else if(P[k][2]<ran0&&ran0<P[k][3])

{

printf(" %d番打者 スリーベースヒットです!!!\n",k);

}

else if(P[k][3]<ran0&&ran0<P[k][4])

{

printf(" %d番打者 HRです!!!!\n",k);

s=s+1;

}

else if(P[k][4]<ran0&&ran0<P[k][5])

{

printf(" %d番打者 四死球です!!!!!\n",k);

}

else

{

printf(" %d番打者 アウト!\n",k);

o=o+1;

}

if(o==3)

{

o=0;
e=e+1;

printf(" 3アウトになりました! \n%d回の攻撃に移ります。\n",e);

}

if(k==9)

{

k=0;

}

if(e==10)

{

printf(" 10回の攻撃はありません!\n試合終了です!\n総得点は%d点です!\n",s);

break;

}

}

return 0;

}

box

Re:本格的な野球のプログラムを作っているのですが・・・

#10

投稿記事 by box » 18年前

> float ran0,P[9][5];

C言語の配列の添字はゼロ始まりですね。
P[9][5]と定義したら、使えるのはP[0][0]~P[8][4]の範囲です。
したがって、初期化の部分が正しくありません。
また、初期化の際、ひとつひとつの要素に値を代入しても
もちろんかまいませんが、ソースコードが冗長になるきらいがあります。
そこで、定義と同時に初期化を行なうことにしてみてはいかがでしょうか。
例えば、
float P[9][5] = {
		{ 0.25, 0.30, 0.31, 0.34, 0.36 },
		{ 0.23, 0.25, 0.26, 0.27, 0.31 },
		// 以下、同様に3番打者~9番打者の定義
	};

バグ

Re:本格的な野球のプログラムを作っているのですが・・・

#11

投稿記事 by バグ » 18年前

これ、打率の他に選手の名前なんかもメンバにして構造体にして、値はファイルから読み込むようにしたら、管理が楽な気がしますね。

野球盤みたいで、ちょっと面白くなってきました。

基本は見てるだけなんだけど、いくつかチームを用意してペナントレースモードとか付けると燃えるかも…

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#12

投稿記事 by 管理人 » 18年前

>バグさん
うぉ、ササッとコンソールでそれらしいウィンドウが出来ているw
さすがバグさんw
いや~こういうトピがあると簡単な野球ゲーム作ってみたくなりますね~^^
作ってる間に簡単の字が本格の字に変わってきそうですがw

>プーコさん
厳密な確率が計算したいという事なので、乱数を生成するライブラリを使うとか、少なくとも少し上のビットを利用するとかしてみてはいかがでしょうか。簡単に言えば1の位は使わないとか。
標準関数の乱数は質がよくないとよく言われますし、例えばLinuxでrandを呼ぶと偶数と基数が交互に現れ、
rand()%2なんかで利用すると酷い目に合います。
VC++環境であまり切り捨てて上を使いすぎると確率が変わってしまうのでお気をつけて。
例えば150が乱数のマックスだとして、この環境でrand()%100を使うと0~50に偏ります。
VC++のRAND_MAXは32767ですが、Linux環境なら2の31乗まであったと思うので20億位まで使えると思います。
あと、投稿は<pre>と</pre>タグ(括弧は半角)に挟んでコードを書くと字下げされてきれいに表示されますよ。
たとえば
for(i=0;i<10;i++)
        if(rand()%2)
                printf("酷い目");
 
こんなかんじです。目にはみえませんが、プレタグで挟んであります。

0時

作れるゲーム、作れないゲーム

#13

投稿記事 by 0時 » 18年前

ようやく入門編を終えました。
これからゲーム基本編に入る所ですが、ふと疑問に思ったので投稿しました。

DXライブラリで出来るゲームのジャンルで作れない、作り難いゲームというのはあるんでしょうか?
ゲームにも色々とあります。
RPGやアクション、シューティングにパズル・落ちモノ、シミュレーションや格闘ゲーム、果てはタイピングやカードゲームなどなど。
私はカードゲームを一度作ってみようかなと思ってるんですが、これは作りやすい方でしょうか?作り難い方でしょうか?
例えばキー入力でなく、マウスクリックでクリックした位置の処理を行うとか。
表示したカード(画像)をクリックする事でカードを場に出したり、手札に戻したりするように処理するとか。
宜しければご指導お願いします。

また、良ければ皆さんが作っているゲームや作ろうとしているゲームはどういうジャンルか教えて貰えると参考として有り難いです。

tk-xleader

Re:作れるゲーム、作れないゲーム

#14

投稿記事 by tk-xleader » 18年前

Dxライブラリには「2D」という制限以外あまりないと思います。無理すれば3Dでもいけるようです。

管理人

Re:作れるゲーム、作れないゲーム

#15

投稿記事 by 管理人 » 18年前

DXライブラリではどんなゲームでも作れます。
なんちゃってオンラインゲームでも作れます。チャットソフトでも作れます。
唯一つ作れないのは3Dです。もしDXライブラリを利用して本体を作り、背景を3Dで表示したい場合などは、
DXライブラリはDirectX7のライブラリであることから、その部分をDirectX7で書く事になります。

DXライブラリだけで作ろうとすると一般的に2Dのみだと思ってください。
私が思う、ゲームを作るその難易度のジャンルを簡単な順番に書いて見ます。
以下私が勝手に感じた難易度ですので、参考程度にしてください。

簡単

サウンドノベルゲーム
ボードゲーム・タイピングゲーム
パズルゲーム(どんなパズルかにもよる)
FF1やドラクエ1のような簡単なRPG
シューティングゲーム
アクションゲーム・格闘ゲーム・アクションRPG等

難しい

何度も言いますが、あくまで個人的な見解です。
ゲームを作る難しさというものは「どれだけ見栄えをよくするか」でものすごく大きく変わります。
決定ボタンを押した瞬間別の場面に何のエフェクトも無くかわるのと、
決定ボタンを押した瞬間キラキラするエフェクトが出てワイプを使ってキレイにシーン変化させるなどするのでは
難易度が全く違います。ですから、上記の順番で作ったとしても、そこにどれだけの見栄えを要求するかで難易度は全く異なります。
例えば私が作ったぷよぷ○もどきのBLACKでは「ぷよんっ」とする質感を出すために色々試行錯誤しました。
しかし、そんな演出にこだわらず、石が等速で落ちてくるように描けばとても簡単です。

ボードゲームはゲームの中でもかなり簡単に作れる方でしょう。
何のエフェクトもなく、ボードゲームを作ると言うテーマは入門時にうってつけだと思います。
私がはじめて作ったゲームはFF1のようなRPGでしたが、高飛びしすぎて色々苦労しました。
その苦労は無駄にはならないですけどね、作るのが嫌になってやめてしまったらそこまでになってしまうので、その危険性だけの問題です。

マウスクリックの処理はそこまで難しい処理じゃないですし、手札に戻すような処理も、DXライブラリの問題ではなく、普通のC言語として処理をかくことになるでしょうし。
DXライブラリの知識としては入門編を終えればある程度網羅したと思います。
まだまだ使い方は定着していないでしょうけど、そこは書きながら覚えればOKです。
後、必要な知識として 30~34 , s0 の章は見てください。
また、これらの内容は見てしっかり理解出来なくてもいいです。
作っていく中でいつかつまずいたら、またココを見る繰り返しで覚えてください。

とおりすがり

Re:作れるゲーム、作れないゲーム

#16

投稿記事 by とおりすがり » 18年前

オンゲーは作れませんね。LANで直接つなげない限りサーバーが必要になりますから。

0時

Re:作れるゲーム、作れないゲーム

#17

投稿記事 by 0時 » 18年前

皆さん、アドバイスありがとうございます。

どうやら3Dだけは無理なようですね。
さすがにそこまで追求するのは準・初心者の私には無謀というものですので素直に2Dで作る事にしますよ。
最初の作成もボードゲームで行こうと思います。
まだまだ勉強中ですが、じっくり時間を掛けて作りますよ。

ここから雑談ですが、実は一度C++でゲームを作ったことがあるんですよ。
というのも専門校でC++やっててプログラミング課題でゲームを作ったのでね。
当時は毎日朝から夕方までC++やってたものですが、卒業して数年たった今はすっかり当時の学習内容を忘れてしまったという始末です。
作ったゲームもCDに焼いてあるんですが、一部データが消えてたり(一番苦労した自作画像が消滅)、何より「こんな難しいプログラムよく作れたなぁ~」と昔の自分を誉めてるんだか今の自分を馬鹿にしてるんだか分からない状態でして(^^;
人間やっぱり毎日使ってないとすぐに物を忘れてしまうものですねぇ~、漢字とか。<!--1

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#18

投稿記事 by プーコ » 18年前

皆様のアドバイスを参考にさせていただいて、1つのチームについて1回から9回まで攻撃するプログラムはできました!!(^^)
次に、二つのチームを対戦させようと思ったのですが、うまくできない事があります!!
1回表の攻撃→1回裏の攻撃→二回表の攻撃→二回裏の攻撃・・・
などと、別のチームの攻撃に移すのに、どのようにループすればよいかわかりません(TT)
何か良いアイデアはないでしょうか?
よろしくお願いいたします!!

バグ

Re:本格的な野球のプログラムを作っているのですが・・・

#19

投稿記事 by バグ » 18年前

論理演算を利用してはいかがでしょうか?

int OmoteUra = 0;

while(1){
OmoteUra = (OmoteUra + 1) & 1;
printf("%d\n", OmoteUra);
}

これで、OmoteUraの中身は1と0で切り替わるはずです。0の時を表、1の時を裏みたいに管理してはいかがでしょう?

C++ならばbool型を使用してもいいかと思います。

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#20

投稿記事 by 管理人 » 18年前

おそらくココであそこでループをと言葉で言っても解りにくいと思いますので、サンプルプログラムを書いてみました。
3イニングだけ書いてみました。
行動はヒット、HR、三振の三パターンだけです。
{20,10}とpに格納する事で20%ヒット、10%HR、70%三振ということになります。
70%はどこにも書いてありませんが、自然と前の確率からそうなります。
pは三次元配列で

int p[チーム数][イニング数][行動パターン-1];

で宣言してあります。

行動はact関数で決定します。3種類の行動のどれになったかは、0~2の数字で返されます。

詳しい中身は注釈と一緒にみてください。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int p[2][3][2]=
{
	{//セ・リーグの確率
		{20,10},//1イニング目、20%ヒット、10%HR、70%三振
		{25,15},
		{30,20}
	},
	{//パ・リーグ
		{25,15},
		{35,20},
		{40,25}
	}
};
char name[2][16]={"セ・リーグ","パ・リーグ"};
char st[3][16]={"三振 ","ヒット","本塁打"};

int act(int team, int i){
	int r=rand()%100;

	if(r < p[team][0])
		return 1;//ヒット
	else if(r < p[team][0] + p[team][1])
		return 2;//ホームラン
	else
		return 0;//三振
}

int main(){
	int i,out=0,result,team=0;
	srand((unsigned)time( NULL ));//初期化

	for(i=0;i<3;i++){//3イニングループ
		printf("%dイニング目\n",i+1);
		for(team=0;team<2;team++){//2チームのループ
			printf("  %sの攻撃\n",name[team]);
			while(out<3){//3アウトまでループ
				result = act(team,i);//行動結果を0~2の数字で格納
				printf("      %sです。\n",st[result]);
				if(result == 0){//act関数にiを渡し、返って来た結果が三振だったら
					out++;//アウトをカウントアップ
					printf("    %dアウト\n",out);
				}
			}
			out=0;//3アウトになってイニングが変わるときoutを0に。
		}
	}
	return 0;
}


実行結果例

1イニング目
  セ・リーグの攻撃
      本塁打です。
      ヒットです。
      ヒットです。
      三振 です。
    1アウト
      三振 です。
    2アウト
      ヒットです。
      三振 です。
    3アウト
  パ・リーグの攻撃
      三振 です。
    1アウト
      本塁打です。
      ヒットです。
      三振 です。
    2アウト
      本塁打です。
      三振 です。
    3アウト
2イニング目
  セ・リーグの攻撃
      ヒットです。
      三振 です。
    1アウト
      本塁打です。
・・・(略)
 
 



こんな感じでループしてはいかがでしょうか?

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#21

投稿記事 by プーコ » 18年前

管理人様のサンプルがわかりそうでイマイチぴんときません(TT)申し訳ありません・・
バグ様のプログラムも、わかりそうでもう少しです・・・
具体的にプログラムの中のどこにどのようにして加えるのか分かりません・・・。

box

Re:本格的な野球のプログラムを作っているのですが・・・

#22

投稿記事 by box » 18年前

> 1つのチームについて1回から9回まで攻撃するプログラムはできました

すでにできあがっている「1つのチームについて」の部分を各イニングの表とみなして、
同様の処理を各イニングの裏として構成すればよいのではないでしょうか。

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#23

投稿記事 by プーコ » 18年前

box様ありがとうございます!!
まず、Aチームの1回から9回までの攻撃を実行し、それからBチームの1回から9回までの攻撃を実行させる、それでふたつのチームの総得点を比べてどちらが勝ったか(負けたか、引き分けか)を表示するプログラムを作りました。
表示する際に、Aチームの攻撃(表)→Bチームの攻撃(裏)→・・・と言う風に表示させたいと言う思いで、改良をしたかったのですが・・・
なかなかうまくいきません(TT)

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#24

投稿記事 by 管理人 » 18年前

3次元配列とか3重ループとか使っているので混乱なさっているのかもしれませんが、めちゃくちゃ簡単な事しか
やってないので、落ち着いてみてください。
昔提示されたコードを読むときなかなか理解出来なくて苦労した経験が邪魔して、きっとコードを見てもすぐにはわからないだろう・・という先入観にとらわれているのだと思います。
私のサンプルは効率のよいものかどうかわからないので、そこまでして理解する必要があるかどうかはわかりませんが・・。
とりあえず上のサンプルを日本語で書くと
3アウト分が2チーム分、それが3イニングあるわけですから3重ループで以下のようにかけますね。

-------------------------

3イニング分ループ{

  2チーム分ループ{

    3アウト分ループ{

      //ここにヒットや三振などの処理

    }

  }
}

------------------------------

ここまでOkでしょうか?

ここで、act関数は、チーム情報とそのイニング数を渡せば、そのチームとイニングにあった
確率で計算した行動結果が返ってきます。
チーム情報とは0か1が入る「team」です。
イニング数は0~2が入る「i」です。ただのループカウンタiに見えますが、
inningのiを取ったものです。

result = act( team , i );

teamとiを渡すと0~2のどれかが帰ってきます。0は三振、1はヒット、2はHRです。
その結果がresultに入ります。
現在アウトになるのは三振だけですから、返って来た数値resultが0ならアウトの
カウントをあげればいいですね。
だから

if(result == 0)//三振だったら
	out++;//アウトをカウントアップ

と書いています。
このことを理解したうえで、先ほどのサンプルをみてみましょう。
以下はprintf文を取っただけの全く同じものです。


for(i=0;i<3;i++){//3イニングループ

	for(team=0;team<2;team++){//2チームのループ

		while(out<3){//3アウトまでループ

			result = act(team,i);//行動結果を0~2の数字で格納

			if(result == 0)//三振だったら
				out++;//アウトをカウントアップ
		}
		out=0;//3アウトになってイニングが変わるときoutを0に。
	}
}

どうでしょう。上の理論をただ実装しただけですよね。
余計なprintf文が沢山はいっているのでややこしくみえただけです。

で、確率の計算ですが、普通に0~99までの乱数をとってきて、
確率の情報として格納しているpにはいっている数値にそって確率を計算しています。

3次元配列を使っているので少々難しいかもしれませんが、

int p[チーム数][イニング数][行動パターン-1]; 

で宣言していることに注意すればすぐわかると思います。
もし3次元配列を使いたくなければ、お使いになっている2次元配列を2チーム分作ればOKです。
具体的にどこがわからないか教えていただければその辺を重点的に解説します。

もし他の回答者様がもっといいプログラムを提示なさればそちらを参考にしてください・・。
 

box

Re:本格的な野球のプログラムを作っているのですが・・・

#25

投稿記事 by box » 18年前

> Aチームの1回から9回までの攻撃を実行し、それからBチームの1回から9回までの攻撃を実行させる

どうせ作るなら、
 ・1回~9回のイニング順に実行する
 ・各イニングでは、先攻、後攻の順に攻撃する
とする方が、実際の試合の流れに沿っていてそれらしく見えると思います。

ループの仕方を
 ・まず、イニングのループを構成する
 ・イニングのループの中で、先攻チームの攻撃と後攻チームの攻撃を構成する
とすればよいです。

今は、ループの優先順位の考え方が逆になっていて、
 ・先攻チームの1回~9回の攻撃を構成する
 ・後攻チームの1回~9回の攻撃を構成する
となっているのではありませんか?

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#26

投稿記事 by プーコ » 18年前

管理人様、box様、丁寧にありがとうございます!!
私は、イニングを、ループではなく、アウトが3つになったらイニングがひとつ増える、というようにしていました!
if(o==3)
{
i=i+1;
}
というように!
イニングをループにし、やってみます!!
管理人様の解説で突破口がみえてきた気がします!!やってみてできなかったらまたお願い致します!!

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#27

投稿記事 by プーコ » 18年前

管理人様やbox様のアドバイスをもとに作ってみました!
構造は良いと思うのですが、実行すると、3アウトで攻撃が終わらずにアウトが無限に表示されてしまいます(TT
while(o<3)としてやっているのですが、なぜうまくいかないのでしょうか?

3イニング分ループ{



  2チーム分ループ{



    3アウト分ループ{

1番から9番までの打順のループ{

      //ここに動きの処理



    }



  }

}
}

というような感じですが。。。

box

Re:本格的な野球のプログラムを作っているのですが・・・

#28

投稿記事 by box » 18年前

そこの、実際のコードを見せていただけますか?

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#29

投稿記事 by プーコ » 18年前

box様!!自分で改良を加えているうちに、アウトの問題は解決しました!!!!
ご迷惑をおかけしました。。
そして、また問題が(TT)
打順に関してなのですが、
Aチームが3番で終わるとBチームの攻撃は3番からになってしまいます。
Bチームが8番で終わるとAチームの攻撃は8番からになってしまいます。
うまく打順を運ぶ方法を現在考えています。
コードはこのような感じです!!

ヒットの確立をP[team][k][1]としています。
このような感じでツーベースやスリーベースも書いています!
for(e==0;e<9;e++)
	{	
		printf("  %d回の攻撃です!!\n\n",e+1);
		for(team=0;team<2;team++)
			{
				printf("  %sの攻撃です!!\n\n\n",name[team]);
				while(o<3)
					{

						for(k==1;k<=9;k++)
							{
								ran0 = rand()/(RAND_MAX+1.0);
								if(0.0<ran0&&ran0<P[team][k]][1])/*ヒット*/
									{
											/*ランナーなしの時の動き*/
										if(b[1]==0&&b[2]==0&&b[3]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!ランナー一塁!\n",k);
														b[1]=1;
														b[2]=0;
														b[3]=0;
														b[0]=1;
													}
											/*ランナー一塁のときの動き*/
										else if(b[1]==1&&b[2]==0&&b[3]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!ランナー一塁二塁!!\n",k);
														b[1]=1;
														b[2]=1;
														b[3]=0;
														b[0]=1;
													}
											/*ランナー一塁二塁のときの動き*/
										else if(b[1]==1&&b[2]==1&&b[3]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!満塁!!ランナー満塁!!\n",k);
														b[1]=1;
														b[2]=1;
														b[3]=1;
														b[0]=1;
													}
											/*ランナー満塁の時の動き*/
										else if(b[1]==1&&b[2]==1&&b[3]==1&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!一点追加!!なおもランナー満塁!\n",k);
														b[1]=1;
														b[2]=1;
														b[3]=1;
														b[0]=1;
														s[team]=s[team]+1;
													}
											/*ランナー一塁三塁の時の動き*/
										else if(b[1]==1&&b[3]==1&&b[2]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!一点追加でランナー一塁二塁!\n",k);
														b[1]=1;
														b[2]=1;
														b[3]=0;
														b[0]=1;
														s[team]=s[team]+1;
													}
											/*ランナー二塁三塁のときの動き*/
										else if(b[2]==1&&b[3]==1&&b[1]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!一点追加でランナー一塁三塁!\n",k);
														b[1]=1;
														b[2]=0;
														b[3]=1;
														b[0]=1;
														s[team]=s[team]+1;
													}
											/*ランナー二塁のとき*/
										else if(b[1]==0&&b[2]==1&&b[3]==0&&b[0]==1)
													{
														printf("   %d番打者   ヒットです!ランナー2塁3塁!!\n",k);
														b[1]=0;
														b[2]=1;
														b[3]=1;
														b[0]=1;
													}			
										/*ランナー三塁のとき*/
										else if(b[1]==0&&b[2]==0&&b[3]==1&&b[0]==1)
													{	

														printf("   %d番打者   ヒットです!一点追加でランナー一塁!!\n",k);
														b[1]=1;
														b[2]=0;
														b[3]=0;
														b[0]=1;
														s[team]=s[team]+1;
													}
 
 
}

box

Re:本格的な野球のプログラムを作っているのですが・・・

#30

投稿記事 by box » 18年前

> 打順に関してなのですが、
> Aチームが3番で終わるとBチームの攻撃は3番からになってしまいます。
> Bチームが8番で終わるとAチームの攻撃は8番からになってしまいます。

打順を管理する領域が1個だけなのではありませんか?
dajun[2]のように配列にしてもいいですし、
dajun_top, dajun_bottomのように別々の名前を付けてもいいです。

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#31

投稿記事 by 管理人 » 18年前

これではおかしいと思うのですが・・。

>3イニング分ループ{
>  2チーム分ループ{
>    3アウト分ループ{
>      1番から9番までの打順のループ{
>        //ここに動きの処理
>      }
>    }
>  }
>}

この部分は

>      1番から9番までの打順のループ{

後から付け足されたものだと思いますが、ここに1~9番までループしてしまっては・・。
ブレイク文をどのように書いているかわかりませんが、
1アウトのうちに1イニングから9イニングまで全部の確率で計算する事になるのではないでしょうか。
サンプルプログラムで3イニングというのは、プログラムを複雑にしないように短くしたものなので、ここを9イニングにしてもらったらいいだけです。ですので

9イニング分ループ{
  2チーム分ループ{
    3アウト分ループ{
        //ここに動きの処理
    }
  }
}

こうなるべきだと思います。
私の作ったact関数もそのまま使ってもらったほうが便利な気がしますが。

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#32

投稿記事 by 管理人 » 18年前

ベースに居る人の情報を管理するのが大変そうですね。
何かスマートに書ける方法は無いか考えてみました。
例によってこの方法が最適かどうかはわかりませんが、一応書いておきますね。

まず、
1バイトの状態変数Sを用意します。

0の状態だとSのビットの状態が

0000 0000

ですね。ここで、後ろの5ビットのみに焦点をあててみましょう。
5ビット目はホームベースを表し、4ビット目は3塁を表し・・

0     0     0     0     1
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

このように表します。0ならランナー無し、1ならランナーありとします。
打者は打順が回ってきた時には、常に1です。
nベースヒットが出た時は、全部のビットを一つ左にnビットずらしてやればいいのです。
入った点数はHMの5ビット目以降にあるビットのたっている数でわかります。

今、打順が回ってきました。
0000 0001
0     0     0     0     1
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

ここで、四球になりました。すると1ビット左にずらします。

0000 0010
0     0     0     1     0
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

このように変わりますね?
四球になったので、現在1塁のみにいます。
次に、打順が回ってきました。また打者は1にします。

0000 0011
0     0     0     1     1
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

ここでツーベースヒットが出ました。2ビット左にずらします。

0000 1100
0     1     1     0     0
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

ちゃんとランナー2,3塁になっています。ここで打順が回ってきます。
打者を1にします。

0000 1101
0     1     1     0     1
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

ここでスリーベースヒットが出ました。3ビット左にずらします。

0110 1000
0     1     0     0     0
↑HM  ↑3塁 ↑2塁 ↑1塁 ↑打者

ここで5ビット目より左に立っているビットの数は2ですね。
得点はここで2点入った事がわかります。

これをプログラムで実装した方がif文を沢山かかなくてすむのではないでしょうか。

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#33

投稿記事 by 管理人 » 18年前

ビットシフトなんたらと言葉で言っても解りにくいと思うのでサンプルを書いてみました。

上記理論を実装したものです。
return (x >> k) & ~(~0 << 1);

これはxの変数のk番目のビットが立っていれば1を、たっていなければ0を返す方法です。
これは落ち着いてみればわかりますが、面倒でしたら、そういう機能だと思ってください。


#include <stdio.h>

char st_base[3][16]={"一塁","二塁","三塁"};
char st_hit[4][4]={"一","二","三","本"};

//xのkビット目が立っているか調べる関数
//返り値= 1(立っている),0(立っていない)
int bits(int x, int k){
   return (x >> k) & ~(~0 << 1);
}

//打者が入ったとき、0ビット目を1にする関数。
//0ビット目が0なら1を立てる。
void in_bits(int *x){
	if(bits(*x,0)==0)
		*x+=1;
}

//今どこの塁にランナーがいるかを表示する関数。
//xの1ビット目から3ビット目はそれぞれ1塁から3塁に対応している事に注目
void show_base(int x){
	int i;
	printf("\nベース [[");
	for(i=1;i<4;i++){
		if(bits(x,i)==1)//iビット目はi塁を示す。
			printf("%s ",st_base[i-1]);
		else
			printf("   ");
	}
	printf("]]\n");
}

//n塁打を打ったとき、nビットだけxを移動する関数。
//同時に何点入ったかも計算する。
int move_bits(int *x,int n){
	int score=0;
	*x;
	while(n>0){//n塁打分ループ
		*x= *x << 1;//1つずつずらす。
		if(bits(*x,4)==1){//ホームベースに人が帰ったら
			score++;//スコアアップ
			*x -= 1<<4;//ホームベースの人を消す。
			printf("ホームイン!\n");
		}
		n--;
	}
	return score;
}

void base_calc(int *x,int hit,int *score){
	in_bits(x);
	printf("\n打者が入りました。\n");
	printf("%s塁打、打った~!!\n",st_hit[hit-1]);
	*score+=move_bits(x,hit);
	printf("現在[%d]点\n",*score);
	show_base(*x);
}

int main(){
	int x=1,score=0,hit=0;

	show_base(x);//現在の塁の状態を見せる。
	base_calc(&x,1,&score);//引数は順に 塁の状態変数、○塁打数、スコア
	base_calc(&x,2,&score);
	base_calc(&x,1,&score);
	base_calc(&x,3,&score);

	return 0;
}

実行結果

ベース [[         ]]

打者が入りました。
一塁打、打った~!!
現在[0]点

ベース [[一塁       ]]

打者が入りました。
二塁打、打った~!!
現在[0]点

ベース [[   二塁 三塁 ]]

打者が入りました。
一塁打、打った~!!
ホームイン!
現在[1]点

ベース [[一塁    三塁 ]]

打者が入りました。
三塁打、打った~!!
ホームイン!
ホームイン!
現在[3]点

ベース [[      三塁 ]]
 
 
見てて意味がわからなくなったら、上の理論を書いた記事と見比べながらサンプルを確認してください。
こっちの方が汎用的にかけるだろうと思って紹介しましたが、難しかったですかね・・(汗

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#34

投稿記事 by プーコ » 18年前

box様、管理人様ありがとうございます。。
管理人様のビットのコードは、見ていると大変わかりやすいのですが、
ビットを使ったコードを学んだことがありません!!
ですので、if文を使って作成していたのです。
if文を使えば、1チームだけの攻撃であればまちがいなくできていると思います。
それを2チーム分にして対戦させるのがなかなかうまくいかないのです(TT)
もう少し考えてみます!!
ほんとうにいつも丁寧にありがとうございます!!!!

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#35

投稿記事 by プーコ » 18年前

管理人様の構造でプログラムを作るとすれば、
どこに打順をもってくればよいのでしょうか?

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#36

投稿記事 by 管理人 » 18年前

すみません、イニングによる確率分けをしたいのかと思っていました。
打順による確率わけですね。考えてみれば当然ですね(汗
プログラムの流れはほとんどかわりませんが、打順に沿った確率わけが出来るサンプルにしてみました。

変更した箇所は、打順の変数を用意した事です。
これからチームによる変数が色々でてくるでしょうから、今後の事を考えて
構造体にしてみました。

typedef struct{
	int dajun;
}team_states_t;

このように用意する事で、team_states_t型の型が作成でき、dajunを持つことになります。

team_states_t team_states[2] ;

と宣言してこの型をチーム分作ります。だから打順は

team_states[team].dajun

で表す事になります。

サンプルはほとんどそのままですが、チョコチョコ変えています。
行動できるパターンは
一塁打、二塁打、三塁打、HR、三振 の5種類です。
act関数の確率の計算部分がfor文に変わっている事に注目してください。
このようにかけばif文は一つでOKです。
理屈は同じなので前のサンプルと見比べてください。

黄色の部分が主な変更点です。
pは

int p[チーム数][打席数][行動パターン-1] で格納しているので

int p[2][9][4];

となっています。行動パターン-1の引く1はなぜかというと、三振はelseで計算するため、これ自身に確率は必要ないからです。
どの行動もしなかった場合、三振となります。



#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct{
	int dajun;
}team_states_t;

team_states_t team_states[2] ;
int p[2][9][4]=
{
	{//セ・リーグの確率
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
	},
	{//パ・リーグ
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
		{30,20,10,10},//1塁打30%、2塁打20%、3塁打10%、本塁打10%、三振30%
	}
};
char name[2][16]={"セ・リーグ","パ・リーグ"};
char st[5][16]={"三振 ","一塁打","二塁打","三塁打","本塁打"};

int act(int team, int dajun){//チームと打順にあった行動結果を返す
	int r=rand()%100,i,range=0;
	
	for(i=0;i<4;i++){
		if(range <= r && r < range+p[team][dajun])
			return i+1;//i+1塁打
		range += p[team][dajun];
	}
	return 0;
}//return 0:三振 1:一塁打 2:二塁打 3:三塁打 4:HR

int main(){
	int i,out=0,result,team=0;
	srand((unsigned)time( NULL ));//初期化

	for(i=0;i<9;i++){//9イニングループ
		printf("%dイニング目\n",i+1);
		for(team=0;team<2;team++){//2チームのループ
			printf("  %sの攻撃\n",name[team]);
			while(out<3){//3アウトまでループ
				result = act(team,team_states[team].dajun);//行動結果を0~2の数字で格納
				printf("      %d番打者\n",team_states[team].dajun+1);
				printf("      %sです。\n",st[result]);
				if(result == 0){//act関数にiを渡し、返って来た結果が三振だったら
					out++;//アウトをカウントアップ
					printf("    %dアウト\n",out);
				}
				team_states[team].dajun = (++team_states[team].dajun)%9;//打順を回す。9になったら0へ			}
			out=0;//3アウトになってイニングが変わるときoutを0に。
		}
	}
	return 0;
}

実効結果

・・・
・・・(略


      8番打者
      三振 です。
    3アウト
2イニング目
  セ・リーグの攻撃
      8番打者
      二塁打です。
      9番打者
      本塁打です。
      1番打者
      三振 です。
    1アウト
      2番打者
      三塁打です。
      3番打者
      二塁打です。
      4番打者
      三振 です。
    2アウト
      5番打者
      一塁打です。
      6番打者
      三振 です。
    3アウト
  パ・リーグの攻撃
      9番打者
      三振 です。
    1アウト
      1番打者

・・・
・・・(略

 
 
このサンプルはかなり縦に長い結果を表示するので、バッファサイズが小さいと全部表示できないかもしれません。
もしXPでしたら、
コマンドプロンプトの上の青いステータスバー上で右クリックし、「既定値」を選択。
「画面のバッファサイズ」をこれからのことも考えて、500以上位にして置いてください。

やそ

Re:本格的な野球のプログラムを作っているのですが・・・

#37

投稿記事 by やそ » 18年前

main関数内にロジックを組めばいいと思います。

管理人さんのロジックを借りるならば・・・
各チームの打順をdajun[2]とする。
dajunの初期値は1
dajun[0]=1
dajun[1]=1
9イニング分ループ{ 
  2チーム分ループ{ //for(j=0;j<=1;j++)のループでいいでしょう。
	if(j=0) //チーム名の表示
		printf("\nA(先攻)チームの攻撃");
	else
		printf("\nB(後攻)チームの攻撃");

	out=0;//アウトカウントのクリア

    3アウト分ループ{ 
		乱数取得
		乱数判定
		アウトならout++;
		塁打ならbasecalcに渡す。
		打順を進める
		dajun[j]++;//j=0ならAチーム
		if(dajun[j]>9)
			dajun[j]=1;
    } 
  } 
}
basecalcは打順の表示はないようなので引数を増やしてdajun[/url]も受け渡せばうまく表示できるかも^^
全て推測で書いてますが、誰かフォローして下さいませ^^;

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#38

投稿記事 by 管理人 » 18年前

DXライブラリを使って表現してみました。
やりたい事はこういう感じでしょうか?
ちなみに自動終了条件は無いので、適当に見飽きたらEcsボタンで止めてください。

http://dixq.net/zip/base.zip

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#39

投稿記事 by プーコ » 18年前

管理人様、やそ様!!
できましたっ!!!!(^^)打順はdajun[1]というふうにふたつの変数にすればうまくいきました。
大きすぎるのかな、ここに載せられないのが残念です。。
アドバイスありがとうございました。
できればこれをもっと発展させていきたいです!!

プーコ

Re:本格的な野球のプログラムを作っているのですが・・・

#40

投稿記事 by プーコ » 18年前

以前プログラムができたと書き込みましたが、疑問に残る点が浮かんできました。
:2チームの選手を全員同じ打者にして、全ての確立(ヒット、二塁打、三塁打、HR、四死球)を全員同じにしました。が、srand((unsigned)time( NULL ));で乱数を初期化しても、疑問があります。
全員がまったく同じ打率なので、それぞれの勝数は大体同じくらいになると予想していたのですが、
100試合繰り返したら、毎回大体、先攻勝ち:後攻勝ち:引き分け=6:3:1
くらいになります。1000試合しても大体勝ちの割合は同じです。
なにか理由が分かればいいのですが(TT)
乱数の取りかたがわるいのでしょうか?

管理人

Re:本格的な野球のプログラムを作っているのですが・・・

#41

投稿記事 by 管理人 » 18年前

srand((unsigned)time( NULL ));
の書き方が悪いのかもしれません。
この行が呼ばれるのは最初の1回だけですか?

この関数で取得するのは現在の「秒数」だと思ってください。
今の瞬間33秒だったとしましょう。(実際はもっと多い数字ですが)
同じ1秒間に100回初期化したら、毎回33で初期化されます。
同じ数で初期化するということは、乱数の出方も一緒になります。
だから、プログラムで
srand((unsigned)time( NULL ));
を書くのは最初の一回だけにしてください。

もしそれでも解決しなければ、ここにアップロードしてください。
「参照」ボタンを押せばソースファイルがアップ出来ます。
その際、このトピは長くなりすぎたので、どうぞお気軽に新しくトピを立てて下さい。

(あと、何度か書き込みがあったので念の為に。○確率、×確立、ではm(_ _)m)

閉鎖

“C言語何でも質問掲示板” へ戻る