Skip to content

Instantly share code, notes, and snippets.

@kohsuke
Created January 16, 2021 14:20
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kohsuke/2847434056fd3fd2020f88e0cef99d50 to your computer and use it in GitHub Desktop.
#include <OWL.h>
#include <Dialog.h>
#include <Button.h>
#define HAIWIDTH (24) //牌の幅(Local)
#define HAIHEIGHT (30) //牌の高さ(Local)
#define STANDARDWIDTH (10*HAIWIDTH+64+192+16) //画面の幅
#define STANDARDHEIGHT (HAIHEIGHT*13+GetSystemMetrics(SM_CYMENU) \
+GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYBORDER)*2+32)
//画面の高さ
#define SMALLWIDTH (STANDARDWIDTH/2) //縮小時の幅
#define SMALLHEIGHT (HAIHEIGHT*13/2+GetSystemMetrics(SM_CYMENU) \
+GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYBORDER)*2+32/2)
void SankakuCBF(void);
void HishiCBF(void);
void TokeiCBF(void);
void GyakuCBF(void);
HBITMAP Hai[7]; //牌のビットマップ
HBITMAP Logo; //ロゴビットマップ
int Board[13][13]; //ボードの状態
int NextHai; //次の牌
int CurMode=1; //現在の難易度
int CurTumi=0; //現在の牌の積み方
POINT History[13*13]; //過去のヒストリ
int HP=0; //ヒストリのポインタ
BOOL UseSmall=FALSE; //縮小セットの使用
void (*ClearBoardFunc[])(void)=
{
SankakuCBF,HishiCBF,TokeiCBF,GyakuCBF
};
int HaiNum[]= //牌の数
{
91,127-1,81-4,93-2
};
int LogoPos[]= //ロゴの表示位置
{
0,0,1,2
};
class Apr : public TApplication
{
public:
Apr(LPSTR a, HANDLE b, HANDLE c, LPSTR d, int e)
:TApplication(a,b,c,d,e){};
virtual void InitMainWindow(void);
};
class Win : public TWindow
{
public:
Win(PTWindowsObject Parent,LPSTR Title);
virtual LPSTR GetClassName(void);
virtual void GetWindowClass(WNDCLASS& WndClass);
virtual void WMCreate(RTMessage Msg)=[WM_FIRST+WM_CREATE];
virtual void WMPaint(RTMessage Msg)=[WM_FIRST+WM_PAINT];
virtual void WMLButtonDown(RTMessage Msg)=[WM_FIRST+WM_LBUTTONDOWN];
virtual void CMNewGame(RTMessage Msg)=[CM_FIRST+101];
virtual void IDNewGame(RTMessage Msg)=[ID_FIRST+101];
virtual void CMOption(RTMessage Msg)=[CM_FIRST+102];
virtual void CMBackStep(RTMessage Msg)=[CM_FIRST+103];
virtual void CMRetry(RTMessage Msg)=[CM_FIRST+104];
virtual void CMUseSmallSet(RTMessage Msg)=[CM_FIRST+105];
void InvalidateNextHai(void);
void InvalidateHai(int x,int y);
};
class OptDlg : public TDialog
{
public:
OptDlg(PTWindowsObject a,LPSTR b):TDialog(a,b){};
virtual void WMInitDialog(RTMessage Msg)=[WM_FIRST+WM_INITDIALOG];
virtual void Ok(RTMessage Msg)=[ID_FIRST+IDOK];
};
void SankakuCBF(void)
{
int x,y;
for(y=0;y<13;y++)
for(x=6-(y+1)/2;x<=6+y/2;x++)
Board[x][y]=-2;
}
void HishiCBF(void)
{
int x,y;
for(y=0;y<=6;y++)
for(x=6-(y+3)/2-2;x<=7+y/2+2;x++)
Board[x][y]=Board[x][12-y]=-2;
}
void TokeiCBF(void)
{
int x,y;
for(y=0;y<=6;y++)
for(x=6-(y+3)/2;x<=7+y/2;x++)
Board[x][6-y]=Board[x][6+y]=-2;
}
void GyakuCBF(void)
{
int x,y;
for(y=0;y<13;y++)
for(x=6-(y+1)/2;x<=6+y/2;x++)
Board[x][12-y]=-2;
Board[5][12]=Board[7][12]=-2;
}
void Apr::InitMainWindow(void)
{
MainWindow=new Win(NULL,"九龍");
}
Win::Win(PTWindowsObject Parent,LPSTR Title)
:TWindow(Parent,Title)
{
Attr.Style=WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX;
if(!UseSmall)
{
Attr.H=STANDARDHEIGHT;
Attr.W=STANDARDWIDTH;
}
else
{
Attr.H=SMALLHEIGHT;
Attr.W=SMALLWIDTH;
}
}
LPSTR Win::GetClassName(void)
{
return "Syanhai";
}
void Win::GetWindowClass(WNDCLASS& WndClass)
{
TWindow::GetWindowClass(WndClass);
WndClass.hIcon=
LoadIcon(GetApplication()->hInstance,"Main2");
WndClass.lpszMenuName=
"Main";
}
//////////////////////////////////////////////////////////////////////////////
//メインウィンドウメッセージ処理関数
//////////////////////////////////////////////////////////////////////////////
void Win::WMCreate(RTMessage Msg)
{
TWindow::WMCreate(Msg);
CMNewGame(Msg);
if(UseSmall)
CheckMenuItem(GetMenu(HWindow),105,MF_CHECKED);
}
void Win::WMPaint(RTMessage Msg)
{
PAINTSTRUCT ps;int x,y;HDC DC;
BeginPaint(HWindow,&ps);
DC=CreateCompatibleDC(ps.hdc);
for(y=0;y<13;y++)
for(x=0;x<13;x++)
{
if(Board[x][y]<0) continue;
SelectObject(DC,Hai[Board[x][y]]);
if(UseSmall)
StretchBlt(ps.hdc,x*12+((y%2)?6:0)+8,y*15+8,12,15,
DC,0,0,24,30,SRCCOPY);
else
BitBlt(ps.hdc,x*24+((y%2)?12:0)+16,y*30+16,24,30,DC,0,0,SRCCOPY);
}
//ロゴ描画
SelectObject(DC,Logo);
if(UseSmall)
StretchBlt(ps.hdc,10*12+32,15*LogoPos[CurTumi]*5,96,36,
DC,0,0,192,72,SRCCOPY);
else
BitBlt(ps.hdc,10*24+64,30*LogoPos[CurTumi]*5,192,72,DC,0,0,SRCCOPY);
SelectObject(DC,Hai[NextHai]);
if(UseSmall)
StretchBlt(ps.hdc,10*12+32+10,18+15*LogoPos[CurTumi]*5,12,15,
DC,0,0,24,30,SRCCOPY);
else
BitBlt(ps.hdc,10*24+64+20,36+30*LogoPos[CurTumi]*5,24,30,DC,0,0,SRCCOPY);
DeleteDC(DC);
EndPaint(HWindow,&ps);
}
void Win::WMLButtonDown(RTMessage Msg)
{
int x,y;
if(UseSmall)
{
Msg.LP.Hi*=2;
Msg.LP.Lo*=2;
}
y=(Msg.LP.Hi-16)/30;
if(((Msg.LP.Hi-16)/30)%2==1)
Msg.LP.Lo-=12;
x=(Msg.LP.Lo-16)/24;
//正常な位置か判定
if(y<0 || y>12 || x<0 || x>12) {MessageBeep(0);return;}
//牌が取る牌と違う
if(Board[x][y]!=NextHai) {MessageBeep(0);return;}
//判定の例外による分岐処理
if(y!=0)
{//最上段なら判定省略
if(x!=0)
{//一番左なら左判定は行わない
//左判定
if(Board[x+((y%2)?0:-1)][y-1]>=0 && Board[x-1][y]<0)
{MessageBeep(0);return;}
}
if(x!=12)
{//一番右なら右判定は行わない
//右判定
if(Board[x+((y%2)?1:0)][y-1]>=0 && Board[x+1][y]<0)
{MessageBeep(0);return;}
}
}
//OKとみなす
History[HP].x=x;History[HP].y=y;HP++; //ヒストリ前進!!
EnableMenuItem(GetMenu(HWindow),103,MF_ENABLED);
Board[x][y]=-1;
NextHai++;
if(NextHai==7) NextHai=0;
InvalidateNextHai();
InvalidateHai(x,y);
}
//////////////////////////////////////////////////////////////////////////////
//メニュー処理関数
//////////////////////////////////////////////////////////////////////////////
void Win::IDNewGame(RTMessage Msg)
{
CMNewGame(Msg);
}
void Win::CMNewGame(RTMessage Msg)
{
int x,y,i,j;
//初期化
for(y=0;y<13;y++)
for(x=0;x<13;x++)
Board[x][y]=-1;
ClearBoardFunc[CurTumi]();
//穴開け
for(i=0;i<7*CurMode;i++)
{
do
{
y=random(13);
x=random(13);
}while(Board[x-1][y]!=-2 || Board[x][y]!=-2 || Board[x+1][y]!=-2 || x==0 || x==12);
Board[x][y]=-3;
}
//逆を辿る
i=6;
for(j=0;j<HaiNum[CurTumi]-7*CurMode;j++)
{//一つ一つ置く
while(TRUE)
{
y=random(13);
x=random(13);
//物理的におけないところ
if(Board[x][y]!=-2)
continue;
//最下段は無条件にOK
if(y==12)
break;
//下に牌があればOK
if(Board[x][y+1]>=0)
break;
//この状態で端であればやりなおし
if(x+((y%2)?1:-1)==-1 || x+((y%2)?1:-1)==13)
continue;
//下2に牌があればOK
if(Board[x+((y%2)?1:-1)][y+1]>=0)
break;
}
Board[x][y]=i;
i--;
if(i==-1) i=6;
}
NextHai=0;
HP=0;
EnableMenuItem(GetMenu(HWindow),103,MF_GRAYED);
InvalidateRect(HWindow,NULL,TRUE);
SendMessage(HWindow,WM_PAINT,0,0);
}
void Win::CMOption(RTMessage Msg)
{
GetApplication()->ExecDialog(new OptDlg(this,"Option"));
}
void Win::CMBackStep(RTMessage Msg)
{
if(HP==0)
{
MessageBox(HWindow,"これ以上戻れません","九龍",MB_OK|MB_ICONSTOP);
return;
}
HP--;
if(HP==0)
EnableMenuItem(GetMenu(HWindow),103,MF_GRAYED);
NextHai--;
if(NextHai==-1) NextHai=6;
Board[History[HP].x][History[HP].y]=NextHai;
InvalidateNextHai();
InvalidateHai(History[HP].x,History[HP].y);
}
void Win::CMRetry(RTMessage Msg)
{
while(HP!=0)
CMBackStep(Msg);
}
void Win::CMUseSmallSet(RTMessage Msg)
{
RECT r;
UseSmall=!UseSmall;
CheckMenuItem(GetMenu(HWindow),105,UseSmall?MF_CHECKED:MF_UNCHECKED);
GetWindowRect(HWindow,&r);
if(UseSmall)
MoveWindow(HWindow, r.left, r.top, SMALLWIDTH , SMALLHEIGHT , TRUE);
else
MoveWindow(HWindow, r.left, r.top, STANDARDWIDTH, STANDARDHEIGHT, TRUE);
}
//////////////////////////////////////////////////////////////////////////////
//その他private関数
//////////////////////////////////////////////////////////////////////////////
void Win::InvalidateNextHai(void)
{
RECT r={10*24+64+20,0,10*24+64+20+24,0};
r.top=36+30*LogoPos[CurTumi]*5;
r.bottom=r.top+30;
if(UseSmall)
{
r.left/=2;
r.top/=2;
r.right/=2;
r.bottom/=2;
}
InvalidateRect(HWindow,&r,TRUE);
}
void Win::InvalidateHai(int x,int y)
{
RECT r;
r.left=16+x*24+((y%2)?12:0);
r.top=16+y*30;
r.right=r.left+24;
r.bottom=r.top+30;
if(UseSmall)
{
r.left/=2;
r.top/=2;
r.right/=2;
r.bottom/=2;
}
InvalidateRect(HWindow,&r,TRUE);
}
//////////////////////////////////////////////////////////////////////////////
//ダイアログ処理関数
//////////////////////////////////////////////////////////////////////////////
void OptDlg::WMInitDialog(RTMessage Msg)
{
SendDlgItemMessage(HWindow,100+CurMode,BM_SETCHECK,TRUE,0);
SendDlgItemMessage(HWindow,200+CurTumi,BM_SETCHECK,TRUE,0);
SetFocus(GetDlgItem(HWindow,100+CurMode));
Msg.Result=FALSE;
}
void OptDlg::Ok(RTMessage Msg)
{
int i;
for(i=0;i<5;i++)
if(SendMessage(GetDlgItem(HWindow,100+i),BM_GETCHECK,0,0))
CurMode=i;
for(i=0;i<4;i++)
if(SendMessage(GetDlgItem(HWindow,200+i),BM_GETCHECK,0,0))
CurTumi=i;
TDialog::Ok(Msg);
((Win *)Parent)->CMNewGame(Msg);
}
int PASCAL WinMain(HANDLE a,HANDLE b,LPSTR c,int d)
{
int x,y;
Apr Ap("九龍",a,b,c,d);
static char w[5]="HAI@";
CurMode=GetPrivateProfileInt("九龍","難易度",1,"Kuron.ini");
CurTumi=GetPrivateProfileInt("九龍","積み方",0,"Kuron.ini");
if(GetSystemMetrics(SM_CYSCREEN)<480) //VGA以下
UseSmall=TRUE;
randomize();
for(y=0;y<13;y++)
for(x=0;x<13;x++)
Board[x][y]=-1;
NextHai=0;
for(x=0;x<7;x++)
{
w[3]='1'+x;
Hai[x]=LoadBitmap(a,w);
}
Logo=LoadBitmap(a,"Logo");
Ap.Run();
for(x=0;x<7;x++)
DeleteObject(Hai[x]);
DeleteObject(Logo);
w[1]=0;w[0]='0'+CurMode;
WritePrivateProfileString("九龍","難易度",w,"Kuron.ini");
w[0]='0'+CurTumi;
WritePrivateProfileString("九龍","積み方",w,"Kuron.ini");
return Ap.Status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment