Created
January 16, 2021 14:20
-
-
Save kohsuke/2847434056fd3fd2020f88e0cef99d50 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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