畠山くんのdelphi教室

このエントリーをはてなブックマークに追加
112デフォルトの名無しさん:03/10/04 00:48
釣れた(藁
まだあったのかYO!このスレ
と、>>1さんが保全に参りました。
115鼻山:04/02/20 22:40
よし、今から オセロもどきを作ろうと思う。

まずは、型の宣言だな。やっぱりな。抽象化が必要だよな?

じゃ、駒からだ。
type TKOMA=(koNone,koWhite,koBlack);

どうだこの素晴らしい抽象化。 何も置いてないときは koNone、白黒は、koWhiteに koBllackだよ。
これはもう完璧な型宣言だろう。だからinterface部、 uses のすぐ後に書いてやろう。


116鼻山:04/02/20 22:42
次には、当然盤の型宣言だな。
これはもう、配列しかないだろ? な? じゃあこうだろ?

type TBAN =array [0..7,0..7]of TKOMA;

盤は駒が8x8に置けるんだからこれしかないよな?
なんでこんなのがagaって来るんだよ
沈め!沈め!
118鼻山:04/02/20 22:52
じゃあ下げで。

次は、表示だ。 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を追加すりゃいいだけだろ。よしよし、とりあえず枠は表示されたと。
119鼻山:04/02/20 23:05
最初にやる事は、当然、盤を綺麗にすることだ。 だとしたら、手続きを作ろう。

まあ、メソッドの方が格好いいかもしれないけど、とりあえず手続きでやって必要になってから変えりゃいいや。

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;
120鼻山:04/02/20 23:06
おっと、var BAN:TBAN をどこに置こう。
一つあればいいんだから、グローバル変数でもいいけど、
とりあえず、これもフォームの public部でいいか。

ここに置く時はvar は不要だから、

TForm1 = class(TForm)
  DrawGrid1: TDrawGrid;
  procedure FormResize(Sender: TObject);
  procedure FormCreate(Sender: TObject);
  public
   BAN:TBAN;
  end;
121鼻山:04/02/20 23:09
さあ、次は、この初期状態を表示させるぞ。
これは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;

これでどうだ。とりあえず表示されたぞ。
122鼻山:04/02/20 23:11
へへ、DrawCell1のAnchorsを全部Trueにしたら期待通り、フォームのサイズ変更したら
自動的に駒も描画されやがる。

ちくしょう、可愛いやつめ。
123鼻山:04/02/20 23:19
さあて、次に駒を置く操作と、置けたらひっくり換える操作が必要だな。

その為には、置けるかどうか検査する処理が必要だぞ。
それは関数だな。 引数は盤と駒と、その位置だから
function okeruka(const BAN:TBAN;K:TKOMA;x,y:Integer)

で、帰り値は 論理型でいいだろ。
124鼻山:04/02/20 23:24

どういう場合に駒が置けるか? どういう場合に駒が置けないのか?

まずは、既にに駒があったら置けないな
盤のx,y位置が空である事が条件だ。
Result:=BAN[x,y]=koNone; if not Result then exit;

って事だな。

それから、相手の駒を挟めないと置けない。
これはチョット考えないといけないぞ。

125鼻山:04/02/20 23:30
まあ考えるより手を動かそう。

まず相手の駒を返す関数を作ろうか。


function AiteNoKoma(K:TKOMA):TKOMA;
begin
  result:=koNone;
  case K of
  koWhite: Result:=koBlack;
  koBlack: Result:=koWhite;
  end;
end;
126鼻山:04/02/20 23:38
で8方向に
 1、最初の隣が相手の駒でないとダメ

 2、次の駒が相手の駒ならさらに検索、空白か盤を超えたらダメ

 3、自分の駒が見つかれば置ける

って感じで調べたらいい。
8方向は ステップ dx,dyで表現、位置はx,yで表現しよう。
127鼻山:04/02/21 00:06
とりあえず、文章をそのままコードにしてみよう。
関数 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 だ。
128鼻山:04/02/21 00:08
で、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;

129鼻山:04/02/21 00:21
ふぁああ。なんか眠くなった。 そんなに面白くなかったしな。 じゃバイ
「koBllackだよ。 」
面白かったよ。いい意味で
>>130
レスつけんなよ
132鼻山:04/02/21 19:10
>>130ありがとうよ。
とりあえず、もう少しオセロらしく動くようにしてから止める事にする。
まずは、>>128は同じ事をCheclk1 Check2でやってるんでそれをマトメテおこう。
133鼻山:04/02/21 19:12
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;
134鼻山:04/02/21 19:12
続きは前のまま

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;
135鼻山:04/02/21 19:18
置けるかどうかの判定が出来たので、次は実際に駒を置く事を考える。
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は駒をヒックリ返す処理のつもりだ。
136鼻山:04/02/21 19:23
前の処理からそのままコピペしたから Result:=Flipなんてしてるが、Flipは関数にする必要はないな。

この駒をヒックリ返す処理が問題か。

前の置けるかどうかの判定で、再帰を使ったけど、判定に成功したら再帰で
帰ってくる時のループを使えば簡単じゃないかな?

判定に成功したらisOKって変数をTrueにしてやればいい。
って事で、判定ルーチンからコピペしてくる。

137鼻山:04/02/21 19:24
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;
138鼻山:04/02/21 19:26
これで、相手の駒があって、その先に自分の駒を見つけた時に isOKがTrueになる。

で、それから帰る時に isOKがTrueだったら 座標を戻して、その駒を自分の駒にしながら帰れば、
おお、ちゃんと勘定が合う。

・・・・当然か。
139鼻山:04/02/21 19:28
このルーチンをテストするにはと、

まあとりあえず、OnSelectCellに入れちゃえ。

procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
begin
 KomaWoOku(BAN,TEBAN, ACol, ARow);
  DrawGrid1.Invalidate;
end;



ヘヘ、とりあえず動いてるな。 満足だ。


次はパスだな。 置けない場合にパスが出来なくちゃな。

それには、どこにも置けないって判定が必要だな。
140鼻山:04/02/21 19:32
ムム
 簡単にやっつけるには、盤を全部 okeruka でチェックすりゃいいんだろうが、
 それって格好悪くないか?

・・・

っと思ったが、実行しても大した時間かからんな。 これでいいのか?

いいんだよな?
141鼻山:04/02/21 19:43
おっと、これが正しいかテストするのに時間くっちまった

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鼻山:04/02/29 08:42
いや、スマン。
オセロプログラムのテストを、そのプログラム自身にやらせるにはどうやったらいいか

考えてたらそっちが面白くなったというか、行き詰まったというか・・・
>>146
>考えてたらそっちが面白くなったというか、行き詰まったというか・・・

・・・ん??
白黒ハッキリしてくださいよ!
ガンガレ期待してます
>>147
うまい
>>147
うまい
>>147
うまい
151でぶや:04/03/04 23:11
>>147
まいう〜
152ほんじゃまか石塚:04/03/05 17:06
>>147
おいしいを通り越して、おいD
153デフォルトの名無しさん:04/06/14 22:31
誰か続ききぼんぬ
期待あげ
>>鼻山

個人的にはCPUのロジックの手順が早く知りたいな
155Socket775:04/06/16 20:43
Delphi 6無料版を落としてこい。
付録のチュートリアルの内容が、そのものズバリ
「テキストエディタの作り方」だ。
説明の通りやってけば誰でもできる。
>>155
そのチュートリアルはPersonal版では進められないわけだが。
>>154
先に日本語勉強しような
158デフォルトの名無しさん:04/07/26 22:49
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
159デフォルトの名無しさん:04/08/29 17:17
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
160デフォルトの名無しさん:04/09/05 19:36
期待+ヽ(`Д´)ノ ボボボボボボッキアゲ
>>畠山→鼻山
ワロタ