112 :
デフォルトの名無しさん:03/10/04 00:48
釣れた(藁
まだあったのかYO!このスレ
よし、今から オセロもどきを作ろうと思う。
まずは、型の宣言だな。やっぱりな。抽象化が必要だよな?
じゃ、駒からだ。
type TKOMA=(koNone,koWhite,koBlack);
どうだこの素晴らしい抽象化。 何も置いてないときは koNone、白黒は、koWhiteに koBllackだよ。
これはもう完璧な型宣言だろう。だからinterface部、 uses のすぐ後に書いてやろう。
次には、当然盤の型宣言だな。
これはもう、配列しかないだろ? な? じゃあこうだろ?
type TBAN =array [0..7,0..7]of TKOMA;
盤は駒が8x8に置けるんだからこれしかないよな?
なんでこんなのがagaって来るんだよ
沈め!沈め!
じゃあ下げで。
次は、表示だ。 Delphiには DrawGridって便利なコンポーネントがある。
これを貼り付けて、 そうだな。サイズが変更されても追従するように、
初期化はフォームのOnResizeでやろう。
procedure TForm1.FormResize(Sender: TObject);
begin
with DrawGrid1 do begin
ScrollBars:=ssNone;
ColCount:=8;
RowCount:=8;
DefaultColWidth:=Width div ColCount;
DefaultRowHeight:=Height div RowCount;
FixedCols:=0;
FixedRows:=0;
end;
end;
よし、実行っと・・・・ありゃ? ssNoneが無いって?
ヘルプ出すと StdCtrls にあるのか 何で StdCtrlsが自動的にusesされないんだ?
まあいいや、 uses に StdCtrlsを追加すりゃいいだけだろ。よしよし、とりあえず枠は表示されたと。
最初にやる事は、当然、盤を綺麗にすることだ。 だとしたら、手続きを作ろう。
まあ、メソッドの方が格好いいかもしれないけど、とりあえず手続きでやって必要になってから変えりゃいいや。
procedure InitBAN(var BAN:TBAN);
var x,y:Integer;
begin
for x:=Low(BAN) to High(BAN) do
for y:=Low(BAN[x]) to High(BAN[x]) do
BAN[x,y]:=koNone;
BAN[3,3]:=koWhite;
BAN[4,4]:=koWhite;
BAN[3,4]:=koBlack;
BAN[4,3]:=koBlack;
end;
こんなもんだな。
これをフォームのOnCreateで呼び出せばいいだろ。
procedure TForm1.FormCreate(Sender: TObject);
begin
InitBAN(BAN);
end;
おっと、var BAN:TBAN をどこに置こう。
一つあればいいんだから、グローバル変数でもいいけど、
とりあえず、これもフォームの public部でいいか。
ここに置く時はvar は不要だから、
TForm1 = class(TForm)
DrawGrid1: TDrawGrid;
procedure FormResize(Sender: TObject);
procedure FormCreate(Sender: TObject);
public
BAN:TBAN;
end;
さあ、次は、この初期状態を表示させるぞ。
これはDrawGridのOnDrawCell に書けばいい筈。
えい、まずは力技で、
procedure TForm1.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
DrawGrid1 .Canvas.Pen.Color:=clBlack;
case BAN[ACol,ARow] of
koWhite:DrawGrid1. Canvas.Brush.Color:=clWhite;
koBlack:DrawGrid1 .Canvas.Brush.Color:=clBlack;
end;
case BAN[ACol,ARow] of
koWhite,koBlack: DrawGrid1.Canvas.Ellipse(Rect);
end;
end;
これでどうだ。とりあえず表示されたぞ。
へへ、DrawCell1のAnchorsを全部Trueにしたら期待通り、フォームのサイズ変更したら
自動的に駒も描画されやがる。
ちくしょう、可愛いやつめ。
さあて、次に駒を置く操作と、置けたらひっくり換える操作が必要だな。
その為には、置けるかどうか検査する処理が必要だぞ。
それは関数だな。 引数は盤と駒と、その位置だから
function okeruka(const BAN:TBAN;K:TKOMA;x,y:Integer)
で、帰り値は 論理型でいいだろ。
どういう場合に駒が置けるか? どういう場合に駒が置けないのか?
まずは、既にに駒があったら置けないな
盤のx,y位置が空である事が条件だ。
Result:=BAN[x,y]=koNone; if not Result then exit;
って事だな。
それから、相手の駒を挟めないと置けない。
これはチョット考えないといけないぞ。
まあ考えるより手を動かそう。
まず相手の駒を返す関数を作ろうか。
function AiteNoKoma(K:TKOMA):TKOMA;
begin
result:=koNone;
case K of
koWhite: Result:=koBlack;
koBlack: Result:=koWhite;
end;
end;
で8方向に
1、最初の隣が相手の駒でないとダメ
2、次の駒が相手の駒ならさらに検索、空白か盤を超えたらダメ
3、自分の駒が見つかれば置ける
って感じで調べたらいい。
8方向は ステップ dx,dyで表現、位置はx,yで表現しよう。
とりあえず、文章をそのままコードにしてみよう。
関数 okerukaはこうだ。
置ける場所があって、置ける駒であって、8方向どこかで相手を挟める事
begin
Result:=BAN[x,y]=koNone; if not Result then exit;
Result:=K<>koNone; if not Result then exit;
Result:=Check( 0, 1,x,y); if Result then exit;
Result:=Check( 1, 0,x,y); if Result then exit;
Result:=Check( 0,-1,x,y); if Result then exit;
Result:=Check(-1, 0,x,y); if Result then exit;
Result:=Check( 1, 1,x,y); if Result then exit;
Result:=Check( 1,-1,x,y); if Result then exit;
Result:=Check(-1,-1,x,y); if Result then exit;
Result:=Check(-1, 1,x,y);
end;
2つの条件は満たさなければならないからif NOT 、8つの条件はどれか一つだだから if だ。
で、Checkという関数は関数内関数で書いてみる。
駒の隣と、その後では別けなきゃいけないから、さらに関数内関数を呼ぼう。
function okeruka(const BAN:TBAN;K:TKOMA;x,y:Integer):boolean;
function Check(dx,dy,x,y:Integer):boolean;
function Check1:boolean;
begin
x:=x+dx;
y:=y+dy;
Result:= x >=LOW(BAN); if not Result then exit;
Result:= x <=HIGH(BAN); if not Result then exit;
Result:= y >=LOW(BAN[x]); if not Result then exit;
Result:= y <=HIGH(BAN[x]); if not Result then exit;
Result:= BAN[x,y]=AiteNoKoma(K) ;
end;
function Check2:boolean;
begin
x:=x+dx;
y:=y+dy;
Result:= x >=LOW(BAN); if not Result then exit;
Result:= x <=HIGH(BAN); if not Result then exit;
Result:= y >=LOW(BAN[x]); if not Result then exit;
Result:= y <=HIGH(BAN[x]); if not Result then exit;
if BAN[x,y]=AiteNoKoma(K) then Result:= Check2;
result:= BAN[x,y]=K;
end;
begin
Result:=Check1; if not Result then exit;
Result:=Check2;
end;
ふぁああ。なんか眠くなった。 そんなに面白くなかったしな。 じゃバイ
「koBllackだよ。 」
面白かったよ。いい意味で
>>130ありがとうよ。
とりあえず、もう少しオセロらしく動くようにしてから止める事にする。
まずは、
>>128は同じ事をCheclk1 Check2でやってるんでそれをマトメテおこう。
function okeruka(const BAN:TBAN;K:TKOMA;x,y:Integer):boolean;
function Check(dx,dy,x,y:Integer):boolean;
function Check0:boolean;
begin x:=x+dx; y:=y+dy;
Result:= x >=LOW(BAN); if not Result then exit;
Result:= x <=HIGH(BAN); if not Result then exit;
Result:= y >=LOW(BAN[x]); if not Result then exit;
Result:= y <=HIGH(BAN[x]); if not Result then exit;
end;
function Check1:boolean;
begin Result:= Check0; if not Result then exit;
Result:= BAN[x,y]=AiteNoKoma(K) ;
end;
function Check2:boolean;
begin Result:= Check0; if not Result then exit;
if BAN[x,y]=AiteNoKoma(K)
then Result:= Check2
else result:= BAN[x,y]=K;
end;
begin Result:=Check1; if not Result then exit; Result:=Check2;
end;
続きは前のまま
begin
Result:=BAN[x,y]=koNone; if not Result then exit;
Result:=K<>koNone; if not Result then exit;
Result:=Check( 0, 1,x,y); if Result then exit;
Result:=Check( 1, 0,x,y); if Result then exit;
Result:=Check( 0,-1,x,y); if Result then exit;
Result:=Check(-1, 0,x,y); if Result then exit;
Result:=Check( 1, 1,x,y); if Result then exit;
Result:=Check( 1,-1,x,y); if Result then exit;
Result:=Check(-1,-1,x,y); if Result then exit;
Result:=Check(-1, 1,x,y);
end;
置けるかどうかの判定が出来たので、次は実際に駒を置く事を考える。
function KomaWoOku(var BAN:TBAN;var K:TKOMA;x,y:Integer):boolean;
今度はBAN K は参照型って奴にした。 これで、呼び出した方の変数が変更される筈だ。
置けたら置いて、相手の手番にして終わるという処理をする為には K も参照型にしなくちゃな。
begin
Result:=False;
if okeruka(BAN,K,x,y) then begin
Result:=Flip( 0, 1,x,y);
Result:=Flip( 1, 0,x,y);
Result:=Flip( 0,-1,x,y);
Result:=Flip(-1, 0,x,y);
Result:=Flip( 1, 1,x,y);
Result:=Flip( 1,-1,x,y);
Result:=Flip(-1,-1,x,y);
Result:=Flip(-1, 1,x,y);
BAN[x,y]:=K;
K:=AiteNoKoma(K);
Result:=True;
end;
end;
Flipは駒をヒックリ返す処理のつもりだ。
前の処理からそのままコピペしたから Result:=Flipなんてしてるが、Flipは関数にする必要はないな。
この駒をヒックリ返す処理が問題か。
前の置けるかどうかの判定で、再帰を使ったけど、判定に成功したら再帰で
帰ってくる時のループを使えば簡単じゃないかな?
判定に成功したらisOKって変数をTrueにしてやればいい。
って事で、判定ルーチンからコピペしてくる。
procedure Flip(dx,dy,x,y:Integer);
var isOK:boolean;
function Check0:boolean;
begin
x:=x+dx; y:=y+dy;
Result:= x >=LOW(BAN); if not Result then exit;
Result:= x <=HIGH(BAN); if not Result then exit;
Result:= y >=LOW(BAN[x]); if not Result then exit;
Result:= y <=HIGH(BAN[x]); if not Result then exit;
end;
function Check1:boolean;
begin Check0; if not Result then exit;
Result:= BAN[x,y]=AiteNoKoma(K) ;
end;
procedure Flip2;
begin
if not Check0 then exit;
if BAN[x,y]=AiteNoKoma(K)
then Flip2
else isOK:= BAN[x,y]=K;
if isOK then begin
x:=x-dx;
y:=y-dy;
BAN[x,y]:=K;
end;
end;
begin
isOK:=false;
Result:=Check1; if not Result then exit;
Flip2;
end;
これで、相手の駒があって、その先に自分の駒を見つけた時に isOKがTrueになる。
で、それから帰る時に isOKがTrueだったら 座標を戻して、その駒を自分の駒にしながら帰れば、
おお、ちゃんと勘定が合う。
・・・・当然か。
このルーチンをテストするにはと、
まあとりあえず、OnSelectCellに入れちゃえ。
procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
begin
KomaWoOku(BAN,TEBAN, ACol, ARow);
DrawGrid1.Invalidate;
end;
ヘヘ、とりあえず動いてるな。 満足だ。
次はパスだな。 置けない場合にパスが出来なくちゃな。
それには、どこにも置けないって判定が必要だな。
ムム
簡単にやっつけるには、盤を全部 okeruka でチェックすりゃいいんだろうが、
それって格好悪くないか?
・・・
っと思ったが、実行しても大した時間かからんな。 これでいいのか?
いいんだよな?
おっと、これが正しいかテストするのに時間くっちまった
function isPass(const BAN:TBAN;K:TKOMA):boolean;
var x,y:Integer;
begin
Result:=false;
for x:=Low(BAN) to High(BAN) do
for y:=Low(BAN[x]) to High(BAN[x]) do
if okeruka(BAN,K,x,y) then
exit;
Result:=True;
end;
こりゃ、なんかテストする方法考えないとダメだな。
期待してます
143 :
デフォルトの名無しさん:04/02/28 17:03
ハッ!
よくみたら「鼻」山だ!
おそっ!
誰か続ききぼんぬ
期待あげ
いや、スマン。
オセロプログラムのテストを、そのプログラム自身にやらせるにはどうやったらいいか
考えてたらそっちが面白くなったというか、行き詰まったというか・・・
>>146 >考えてたらそっちが面白くなったというか、行き詰まったというか・・・
・・・ん??
白黒ハッキリしてくださいよ!
ガンガレ期待してます
153 :
デフォルトの名無しさん:04/06/14 22:31
誰か続ききぼんぬ
期待あげ
>>鼻山
個人的にはCPUのロジックの手順が早く知りたいな
Delphi 6無料版を落としてこい。
付録のチュートリアルの内容が、そのものズバリ
「テキストエディタの作り方」だ。
説明の通りやってけば誰でもできる。
>>155 そのチュートリアルはPersonal版では進められないわけだが。
158 :
デフォルトの名無しさん:04/07/26 22:49
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
159 :
デフォルトの名無しさん:04/08/29 17:17
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
160 :
デフォルトの名無しさん:04/09/05 19:36
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
>>畠山→鼻山
ワロタ