|
|
|
2006/10/10(Tue) 22:17:19|NO.2928
いつもお世話になってます。
オセロゲームを作ろうと思い、下のようなスクリプトを作りました。
とりあえず駒をランダムに並べ、クリックするとその場所で駒をいくつとれるか判定
します。しかし、取れる駒の判定の部分がうまくいかず、どうも数が変です。
いろいろ試してみましたが、なかなか直りません。
どうすればうまく数えることができるでしょうか。
よろしくお願いします。
randomize
#const global BOARD_COLOR $036903
#const global BOARD_LIGHT_COLOR $008000
#const global BOARD_DARK_COLOR $024F02
#const global BOARD_MOUSEOVER_COLOR $81F8F8
#const global BOARD_MOUSEOVER_LIGHT_COLOR $AAFFFF
#const global BOARD_MOUSEOVER_DARK_COLOR $27F1F1
#const global MASU_SIZE 57
#const global KUGIRI_WEIGHT 2
#const SCREEN_X (MASU_SIZE * 8) + (KUGIRI_WEIGHT * 9) + 1
#const SCREEN_Y (MASU_SIZE * 8) + (KUGIRI_WEIGHT * 9) + 1
#const global KOMA_NOKOMA 0
#const global KOMA_KURO 1
#const global KOMA_SIRO 2
#uselib "user32.dll"
#cfunc WindowFromPoint "WindowFromPoint" int, int
#module
#deffunc color32 int intA
color intA >> 16 & $FF,intA >> 8 & $FF,intA & $FF
return
#defcfunc getcolor32 int intR,int intG,int intB
return (intR << 16 & intG << 8 & intB)
#define global PrintMasu(%1,%2,%3=BOARD_COLOR,%4=BOARD_LIGHT_COLOR,%5=BOARD_DARK_COLOR) _PrintMasu %1,%2,%3,%4,%5
#deffunc _PrintMasu int intX,int intY,int COL,int lightCOL,int darkCOL,local x,local y ;マス1マスだけ描画
x = intX * MASU_SIZE + (KUGIRI_WEIGHT * intX) + 2
y = intY * MASU_SIZE + (KUGIRI_WEIGHT * intY) + 2
color32 COL
boxf x,y,x+MASU_SIZE,y+MASU_SIZE
color32 lightCOL
line x+MASU_SIZE,y,x,y
line x,y+MASU_SIZE,x,y
color32 darkCOL
line x+MASU_SIZE,y+MASU_SIZE,x,y+MASU_SIZE
line x+MASU_SIZE,y
return
#deffunc PrintBoard ;ボード全体を描画
redraw 0
color 0,0,0
boxf
color32 BOARD_COLOR
repeat 9
mx = cnt
repeat 9
PrintMasu mx,cnt
loop
loop
redraw 1
return
#deffunc PrintKomaM int intX,int intY,int intK,local x,local y ;コマ一つだけ描画
if intK{
x = intX * MASU_SIZE + (KUGIRI_WEIGHT * intX) + 2
y = intY * MASU_SIZE + (KUGIRI_WEIGHT * intY) + 2
gsel 0
pos x,y
if intK==KOMA_KURO:color 0,0,0:else:color 255,255,255
mes "●"
}
return
#deffunc PrintKoma local cn ;コマ全て描画
repeat 8
cn = cnt
repeat 8
PrintKomaM cnt,cn,board@(cnt,cn)
loop
loop
return
;cneckA(x移動量,y移動量,場所x,場所y)
;実際に1つ1つの方向でおけるかどうかを確かめる
;置けるなら、取れる数を返す
#defcfunc checkA int xv,int yv,int x,int y,int myColor,local okeru,local aiColor,local sx,local sy,local aiAtta
if board@(x,y)!KOMA_NOKOMA:return 0 ;駒があれば0を返す
if myColor=KOMA_KURO:aiColor=KOMA_SIRO:else:aiColor=KOMA_KURO ;自分の色と反対の色を相手の駒にする
if ((x+xv)<0)|((x+xv)>7):return 0 ;その方向に移動すると盤の外に出る場合は、0を返す
if ((y+yv)<0)|((y+yv)>7):return 0
if board@(x+xv,y+yv)!aiColor:return 0 ;その方向の1つめが相手の駒でなければ0を返す
okeru=0 ;取れる数
sx=x+xv:sy=y+yv ;確かめる場所
aiAtta=0 ;相手の駒があったか
repeat
if ((sx<0)|(sx>7)):aiAtta=0:break ;自分の駒がくる前に盤の外に出たら0を返す(return 0とするとエラーが出るのでこうした)
if ((sy<0)|(sy>7)):aiAtta=0:break
if board@(sx,sy)=myColor:break ;次の場所が自分の駒ならここで終了
if board@(sx,sy)=aiColor:aiAtta=1:okeru++ ;相手の駒ならaiAttaを1にし、取れる数を1増やす
sx+=xv ;次の場所へ
sy+=yv
loop
return okeru*aiAtta ;相手の駒が途中にあれば取れる数を返し、そうでなければ0を返す
;x移動量が-1〜1、y移動量が-1〜1の場合でそれぞれ取れる数を合計、結果的にそのマスに置いたら取れる個数を返す
;ただし、x,y移動量が共に0の場合は飛ばす
#defcfunc okerucheck int x,int y,local isToreru
isToreru = 0
repeat 3
xcnt = cnt-1
repeat 3
ycnt=cnt-1
if (xcnt=0)&(ycnt=0):continue
isToreru += checkA(xcnt,ycnt,x,y,KOMA_KURO)
loop
loop
return isToreru
#global
screen 0,SCREEN_X,SCREEN_Y
gmode 2
PrintBoard ;ボード描画
dim board,8,8 ;ボード board(X,Y)
/* board(3,3)=KOMA_KURO
board(3,4)=KOMA_SIRO
board(4,3)=KOMA_SIRO
board(4,4)=KOMA_KURO*/
repeat 8
xcn=cnt
repeat 8
board(xcn,cnt)=rnd(3)
loop
loop
font msgothic,55
PrintKoma ;コマ全て描画
*main
if WindowFromPoint(ginfo(0),ginfo(1)) = hwnd{
redraw 0
PrintMasu xx,yy ;マス描画
PrintKomaM xx,yy,board(xx,yy) ;コマxx,yyの座標のみ描画
tempx=(mousex-(mousex/MASU_SIZE)*KUGIRI_WEIGHT-2)/MASU_SIZE
tempy=(mousey-(mousey/MASU_SIZE)*KUGIRI_WEIGHT-2)/MASU_SIZE
xx = tempx - (tempx >= length(board)) ;色を変えるマスX
yy = tempy - (tempy >= length2(board)) ;色を変えるマスY
if board(xx,yy)=0{
PrintMasu xx,yy,BOARD_MOUSEOVER_COLOR,BOARD_MOUSEOVER_LIGHT_COLOR,BOARD_MOUSEOVER_DARK_COLOR ;マウス上に乗ったときのいろでマス描画
PrintKomaM xx,yy,board(xx,yy) ;コマ描画
}
redraw 1
}
stick key
if key&256:dialog "ここで取れる:"+okerucheck(xx,yy) ;左クリックの場合にそのマスで取れる数を表示
wait 3
goto *main
| |
|
2006/10/10(Tue) 22:52:57|NO.2929
#1. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
#これって必要部分なら長くてもいいってことなのかな...
>取れる駒の判定の部分がうまくいかず、どうも数が変です
どういうシチュエーションで変になるのかを説明してください。
|
|
2006/10/10(Tue) 23:32:51|NO.2930
> #1. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
> #これって必要部分なら長くてもいいってことなのかな...
できれば長いスクリプトのままでなく、不要な部分を限りなく削除したものを
提示してもらいたいものですが…そうも行かない場合もありますね。
今回のような長いスクリプトを提示したい場合、ご自分のサイトをお持ちの方は
asファイルを自分のサイトスペースにアップロードし、掲示板へはそこへの
アドレスを貼り付けるだけにとどめるのがベストな対応だと思います。
サイトをお持ちでない方は、一般のファイルをアップロードできるサービスを
利用するか、この掲示板にそのまま貼り付けることになります。
さて、今回の場合は前者なのでできればご自分のサイトにアップしてくれると良かったですね。
> します。しかし、取れる駒の判定の部分がうまくいかず、どうも数が変です。
プレイヤーは黒…みたいですね。ですよね?
適当に実行してみましたが、置けないはずのところでたまに1以上返すことがあるようです。
デバッグの方針は、とりあえず確実にエラーが起きるパターンを捜すか、
スクリプトをよく見直すか…アルゴリズムをもう一度検証してみるとかあたりかな?
眠いので今日はこれまで…。
|
|
2006/10/11(Wed) 03:33:36|NO.2931
> 今回のような長いスクリプトを提示したい場合、ご自分のサイトをお持ちの方は
> asファイルを自分のサイトスペースにアップロードし、掲示板へはそこへの
> アドレスを貼り付けるだけにとどめるのがベストな対応だと思います。
> サイトをお持ちでない方は、一般のファイルをアップロードできるサービスを
> 利用するか、この掲示板にそのまま貼り付けることになります。
他にはHSPWikiかHSP開発Wikiに載せるとか。
とにかく掲示板にそのまま生で書くと見づらくなるので出来るだけ遠慮して欲しいと
いうのが実情ですね。
まあ、それもまた面倒なんですが。
|
|
2006/10/11(Wed) 08:33:38|NO.2932
斜めの判定が、ダメですね。
白をはさんだ黒のあるべき所が空欄でも、黒があると判定されています。
僕ではちょっと....^^;
「じゃぁ投稿すな」(影声)
|
|
2006/10/11(Wed) 09:19:39|NO.2933
ちょっと読んでみたところ、取れるかどうか(置けるかどうか)の条件が足りないですね。
問1:マスの状態は以下の3つある。空欄を埋めなさい。(^^;テスト風)
1.●が置いてある
2.○が置いてある
3.( )
# 書いている間にhirokiさんと被ったかも。
# preが上手くいかず...
|
|
2006/10/11(Wed) 15:40:30|NO.2934
オセロのアルゴリズムについてですが
http://piza2.2ch.net/tech/kako/984/984182993.htmlの337-338にて、
平面に並んでいるマスを二次元配列と考えず、一次元配列と考える方法で書いてあります。
HSPではなくCなのですが、オセロの盤を一本に引き伸ばし基点となるマスからの増分で処理を行っています。
このスレッドは特殊な環境要因(7行のショートソース)があるので、
逆に言うと最低限の動作をさせるための簡潔なソースになっているかと思います。
参考にしてみるのもいいかもしれません。
|
|
2006/10/11(Wed) 18:25:17|NO.2941
長いスクリプトは、今度から気をつけるようにします。
klzさんの紹介してくださった考え方は、
7行スクリプトということで解読が難しく、意味も分かりませんでした。
kz3さんの問題の3は、(何も置いてない)ですね。
…でしょうか?
その意味を考えると、何も置いてなかった場合の処理を忘れてたことに気付きました。
そして、
if board@(sx,sy)=aiColor:aiAtta=1:okeru++ ;相手の駒ならaiAttaを1にし、取れる数を1増やす
の後に
if board@(sx,sy)=KOMA_NOKOMA:aiAtta=0:break
を追加すると、一応正しく動きました。どうでしょうか?
これでなにか問題があれば、ご指摘お願いします。
|
|
2006/10/12(Thu) 10:58:44|NO.2950
>を追加すると、一応正しく動きました。どうでしょうか?
>これでなにか問題があれば、ご指摘お願いします。
動いたなら動いたでいいんじゃないんでしょうか?(まずは)
あとはよーく自分の書いたものを読んで、似たようなことを書いている部分があったら、
そこは整理できるかも知れない部分になるかも知れません。
# 具体的に無駄なところを書いてみたけど、やっぱりやめた。
# やっぱり読まなきゃね^^;
|
|
2006/10/13(Fri) 21:59:43|NO.2963
Dripです。
うひょさん、こんにちは。
リバーシゲームの石の取れる数をカウントするには、二次元配列変数の取り扱いに慣れている必要があります。
取れる石の数をカウントするときには8方向に対する適切な条件判断の式を書く必要があるので、
ゲーム開発に慣れるためには良い学習になると思います。
プログラムに煮詰まったら、まず自分のプログラムの問題点を見つけ、それがわかったら
解決策を考査するより、一旦自分の書いたプログラムを全て消去し、再びゼロから組み上げることで、
より洗練された、効率の良いプログラムが組める場合がかなりあります。私はよくこれをします^^;
勇気を持った行動は何かしら教訓を残してくれるので、一度やってみると良いと思います。
リバーシゲームで自分が取れる石をカウントするスクリプトは、そんなに長く書かなくても
実現できます。これは慣れと経験なので、何度もプログラムを書いて徐々にアルゴリズムを
洗練していってください。
以下にリバーシゲームで取得可能な石の数を取得するサンプルを示します。
//白石が置ける場所に取れる石の数を表示するサンプル
#define mx 16 //フィールドの広さ
#define size 32 //マスのサイズ
dim map,mx,mx //フィールド
//マスの情報を取り出すマクロ
#define chk(%1,%2,%3) if %2>=0 & %2<mx & %3>=0 & %3<mx:{%1=map(%2,%3)}else{%1=-1}
//マスをp1,p2ずつずらしながら一直線に検索するマクロ
#define chk_nest2(%1,%2) xt=0:repeat mx,1:chk tmp,tx+%1*cnt,ty+%2*cnt:\
if tmp!stnID:{break}else{xt++}:loop:if tmp=stnID\2+1:{ct+=xt}
//フィールドを描画
screen 0,mx*size,mx*size:font "MS ゴシック",size:color ,255:boxf:color
repeat mx:line cnt*size,0,cnt*size,mx*size:line 0,cnt*size,mx*size,cnt*size:loop
//石を適当に置く
repeat mx*mx/2
tx=rnd(mx):ty=rnd(mx)
if map(tx,ty)!0:continue cnt
map(tx,ty)=cnt\2+1
color cnt\2*255,cnt\2*255,cnt\2*255:pos tx*size,ty*size:mes "●"
loop
//取れる数チェックして描画。stnID=1で白石の数、stnID=2で黒石の取れる数を取得する。
stnID=1:font "MS ゴシック",size/2,1
color (stnID\2)*255,(stnID\2)*255,(stnID\2)*255
repeat mx:tx=cnt:repeat mx:ty=cnt
if map(tx,ty)!0:continue
ct=0
chk_nest2 -1,0:chk_nest2 0,-1:chk_nest2 1,0:chk_nest2 0,1
chk_nest2 -1,-1:chk_nest2 1,-1:chk_nest2 1,1:chk_nest2 -1,1
if ct>0:pos tx*size+size/4,ty*size+size/4:mes ct
loop:loop
もしもWEBサイトなどで他人の書いたプログラムを見つけ、それに自分のプログラムにない技術が使われていたり、自分より短いスクリプトで同じ動作をしているものを見つけたなら、それはうひょさんがこれからまだまだ成長できる証です。
これからも頑張ってくださいね。
| |
|
2006/10/13(Fri) 22:18:00|NO.2964
>ゲーム開発に慣れるためには良い学習になると思います。
たしかに。自分も昔(4〜5年くらいまえ)にオセロ(、、ともいえないような)
ゲームを作ったことがあります。
ゲーム作っていると、、なんだかプログラムがうまくなったような
気がしますよね?あれが面白いw
で、オセロゲームなんですが、「うわーん難しい」と難しく考えずに
リラックスしてみましょう。
まず、オセロのルールで駒をはさんだことになるのはどんなときですか?
縦・横・斜め(右上など)の「8」方向ですね。4じゃありませんよ。
8方向分調べればいいのです。
別に比例の「Y=2X」みたいな急な斜めはないのでずいぶんらくだと思います。
っというかもっといい方法は知らないんですけど、、、
で、駒反転は、、、別にいいですね。「変数(X,Y) = 駒の値」でいいので
#おまけ。敵の思考について。
度適当思考(Lv.1)は
まず「rnd」で適当に値(X,Yのことね)を求めます。
でX,Yがとれる位置にきたらそこにおきます。
でも取れる位置にぜんぜんこれなく、100回くらい反復してしまったら、「パス」
などの手もあります。
頭いい思考(Lv.10)は
まず「rnd」で適当に値(X,Yのことね)を求めます。(ここ一緒。)
で、まず、その位置を記録します。(何でもいいので配列に。)
これを、、、まぁ、20回くらい??繰り返して、
一番いっぱい取れそうなところにおく、、、という手あります。
以上です。長々すみません。
|
|
2006/10/13(Fri) 23:16:01|NO.2965
>取れる石の数をカウントするときには8方向に対する適切な条件判断の式を書く必要があるので
>縦・横・斜め(右上など)の「8」方向ですね。4じゃありませんよ。
>8方向分調べればいいのです。
ん...?
みなさん、うひょさんのスクリプト読んでないのかな?(盤作成コードは私も読んでませんが...)
8方向ちゃんと調べられてますよ。
|
|
2006/10/14(Sat) 00:14:59|NO.2966
Dripです。
kz3さん、私の投稿は
> いろいろ試してみましたが、なかなか直りません。
> どうすればうまく数えることができるでしょうか。
という書き込みより、具体的な問題点の指摘の他に、別の視点から問題を捕らえた
回答のひとつとして投稿しました。
> みなさん、うひょさんのスクリプト読んでないのかな?
このような発言はスクリプトを丁寧に読んで返信している投稿者全員に対し
嫌悪感や反感を抱かせ、質問者に対し不信感を与えることになります。
|
|
2006/10/14(Sat) 08:42:42|NO.2970
>> みなさん、うひょさんのスクリプト読んでないのかな?
>このような発言はスクリプトを丁寧に読んで返信している投稿者全員に対し嫌悪感や反感を抱かせ、
すみません...「8方向〜」の書き込みが二つあったのでそちらばかりに気が捕られていました。
なので前回のコメントの真意は「うひょさんもそれなりに考えて書いていますよ」というフォローのつもりでした。
気を悪くさせてごめんなさい。
|
|
2006/10/16(Mon) 09:30:45|NO.2995
皆様、ありがとうございます。
整理は、がんばってやってみます。
Dripさんのサンプルを見て、マクロで
ここまでできることがすごいと思いました。
マクロで複雑なことをするのは慣れてないもので…。
がんばって解読してみたいと思います。
#関係ないですが、掲示板でエラーが出るようになってから
#ついにクッキーが消えたのでいちいち名前、マスコット、HPアドレス、
#削除用パスワードをいちいち書かないといけないので
#めんどくさいのですが…
|
|