缘起:

  在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制。所以想自己再写一个。

程序效果:

主要内容:

  程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分都存储1。

  如下图:

    

  shape采用4*4数组(shape)保存。如:

    0 0 0 0

    0 1 0 0

    1 1 1 0

    0 0 0 0

  另外用变量row和column保存shape数组左上角在board中的位置。

  每次下落或左右移动,先对row和column做出改变,然后检测当前row和column下,shape是否重合了为1的格子,如果有重合,就说明shape出界了或者到达下落最低点,则要恢复row和column值。另外,如果是下落,还要将shape放在board上,并产生新的shape。

  旋转时,先对shape数组进行旋转操作,然后检测重合,如果有重合,则反向旋转回来。

代码:

 #if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif #include <tchar.h>
#include <windows.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
/*-----------------宏定义--------------------------------------------------------*/
#define WIDTH 180
#define HEIGHT 400
#define LONG_SLEEP 300
#define BKCOLOR RGB(238,238,238)//背景色
/*-----------------变量----------------------------------------------------------*/
static int shapes[][][];//存储7个形状
static int high_score[]= {,,,};//前三个元素存储最高分,最后一个元素存储此次得分
static int **shape;//当前形状
static int **board;
static int M=;//显示的列数
static int N=;//显示的行数
static int MM=M+;//board的列数
static int NN=N+;//board的行数
static int LEFT=;//显示的最左一列
static int RIGHT=LEFT+M-;//显示的最右一列
static int TOP=;//显示的最上一列
static int BOTTOM=N-;//显示的最下一列
static int score=;
static int row=;//形状所在行
static int column=MM/;//形状坐在列
static bool is_pause=false;
static HBRUSH grey_brush =CreateSolidBrush (RGB(,,));
static HBRUSH white_brush =CreateSolidBrush (RGB(,,));
static HBRUSH bk_brush =CreateSolidBrush (BKCOLOR);
static HPEN hPen = CreatePen(PS_SOLID,,RGB(,,));
static int lattices_top=;//上面留白
static int lattices_left=;//左侧留白
static int width=WIDTH/M;//每个格子的宽度
static int height=(HEIGHT-lattices_top)/N;//每个格子的高度
/*-----------------函数-----------------------------------------------------------*/
void add_score() ;
bool check_is_lose() ;
void clear_up() ;//消除没有空格子的行
void* down_thread_function(void * args) ;//形状下落进程要执行的函数
void exit_game(HWND hwnd) ;
void give_new_shape() ;//随机生成一个新形状
int handle_key(HWND hwnd,WPARAM wParam) ;
int init_down_thread(HWND hwnd) ;//初始化形状下落进程
int init_game(HWND hwnd) ;//初始化游戏程序
void init_play() ;//初始化游戏数据
bool is_legel() ;//检测形状在当前位置是否合法(即是否重合了非空的格子)
int load_scores(int* a) ;//读取游戏最高分数据
int load_shape() ;//从文件中加载7个形状
void lose_game(HWND hwnd) ;
int move_down(HWND hwnd) ;//形状下落
int move_lr(HWND hwnd,int lr) ;//形状左右移动
void paint_lattice(HDC hdc,int x,int y,int color) ;//显示一个格子
void paint_UI(HDC hdc) ;//画界面
void reset_rc() ;
void rerotate_matrix(int mn) ;//顺时针旋转一个行列数为mn的方阵
void rotate_matrix(int mn) ;//逆时针旋转一个行列数为mn的方阵
int rotate_shape(HWND hwnd) ;//旋转当前形状并更新界面
bool save_score(HWND hwnd) ;//保存最高分数据
void shape_to_ground() ;//当前形状落地之后,更新board
bool sort_scores(int* a) ;//对最高分和此次得分排序,若创造新纪录则返回true
void update_UI(HWND hwnd) ;//更新界面,仅更新Rect区域(形状所在的那几行)内
void update_UI_all(HWND hwnd) ;//更新界面,更新整个界面
int write_scores(int* a) ;//写最高分数据 /* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); /* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("Tris"); int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow) {
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = ; /* No extra bytes after the window class */
wincl.cbWndExtra = ; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground =bk_brush;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return ; /* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
, /* Extended possibilites for variation */
szClassName, /* Classname */
_T("Tris"), /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
WIDTH+, /* The programs width */
HEIGHT+, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
); /* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow); /* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, , )) {
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
} /* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
//从文件中加载7个形状
int load_shape() {
FILE* f=fopen("shapes.txt","rb");
if(f==NULL) {
return -;
}
for(int i=; i<; i++) {
for(int j=; j<; j++) {
for(int k=; k<; k++) {
if(fscanf(f,"%d",&shapes[i][j][k])!=) {
return -;
}
}
}
}
fclose(f);
return ;
}
//随机生成一个新形状
void give_new_shape() {
int shape_num=rand()%;
for(int i=; i<; i++) {
for(int j=; j<; j++) {
shape[i][j]=shapes[shape_num][i][j];
}
}
}
void add_score() {
score+=;
}
//消除没有空格子的行
void clear_up() {
for(int i=row; i<=row+; i++) {
if(i>BOTTOM)continue;
bool there_is_blank=false;
for(int j=LEFT; j<=RIGHT; j++) {
if(board[i][j]==) {
there_is_blank=true;
break;
}
}
if(!there_is_blank) {
add_score();
for(int r=i; r>=; r--) {
for(int c=LEFT; c<=RIGHT; c++) {
board[r][c]=board[r-][c];
}
}
}
}
}
//检测形状在当前位置是否合法(即是否重合了非空的格子)
bool is_legel() {
for(int i=; i<; i++) {
for(int j=; j<; j++) {
if(shape[i][j]==&&board[row+i][column+j]==) {
return false;
}
}
}
return true;
}
//逆时针旋转一个行列数为mn的方阵
void rotate_matrix(int mn) {
int** a=shape;
int s=;
for(int n=mn; n>=; n-=) {
for(int i=; i<n-; i++) {
int t=a[s+i][s];
a[s+i][s]=a[s][s+n-i-];
a[s][s+n-i-]=a[s+n-i-][s+n-];
a[s+n-i-][s+n-]=a[s+n-][s+i];
a[s+n-][s+i]=t;
}
s++;
}
}
//顺时针旋转一个行列数为mn的方阵
void rerotate_matrix(int mn) {
int** a=shape;
int s=;
for(int n=mn; n>=; n-=) {
for(int i=; i<n-; i++) {
int t=a[s+i][s];
a[s+i][s]=a[s+n-][s+i];
a[s+n-][s+i]=a[s+n-i-][s+n-];
a[s+n-i-][s+n-]=a[s][s+n-i-];
a[s][s+n-i-]=t;
}
s++;
}
}
//显示一个格子
void paint_lattice(HDC hdc,int x,int y,int color) {
if(x<TOP||x>BOTTOM||y<LEFT||y>RIGHT) {
return ;
}
x-=TOP;
y-=LEFT;
int left=lattices_left+y*width;
int right=lattices_left+y*width+width;
int top=lattices_top+x*height;
int bottom=lattices_top+x*height+height;
MoveToEx (hdc,left,top, NULL) ;
LineTo (hdc,right,top) ;
MoveToEx (hdc,left,top, NULL) ;
LineTo (hdc,left,bottom) ;
MoveToEx (hdc,left,bottom, NULL) ;
LineTo (hdc,right,bottom) ;
MoveToEx (hdc,right,top, NULL) ;
LineTo (hdc,right,bottom) ;
SelectObject(hdc, grey_brush);
if(color==) {
SelectObject(hdc, white_brush);
}
Rectangle(hdc,left,top,right,bottom);
}
//更新界面,仅更新Rect区域(形状所在的那几行)内
void update_UI(HWND hwnd) {
static RECT rect;
rect.left=lattices_left;
rect.right=lattices_left+M*width+width;
rect.top=lattices_top+(row-)*height;
rect.bottom=lattices_top+(row+)*height;
InvalidateRect (hwnd,&rect, false) ;
}
//更新界面,更新整个界面
void update_UI_all(HWND hwnd) {
InvalidateRect (hwnd,NULL, false) ;
}
//画界面
void paint_UI(HDC hdc) {
SetBkColor(hdc,BKCOLOR);
SelectObject(hdc,hPen); //选用画笔
char score_str[];
sprintf(score_str,"Score:%d",score);
TextOut(hdc,,,score_str,strlen(score_str));
sprintf(score_str,"Highest Scores:");
TextOut(hdc,WIDTH+,,score_str,strlen(score_str));
for(int i=; i<; i++) {
sprintf(score_str,"%d",high_score[i]);
TextOut(hdc,WIDTH+,+(i+)*,score_str,strlen(score_str));
}
for(int i=TOP; i<=BOTTOM; i++) {
for(int j=LEFT; j<=RIGHT; j++) {
paint_lattice(hdc,i,j,board[i][j]);
}
}
for(int i=; i<; i++) {
for(int j=; j<; j++) {
if(shape[i][j]==)
paint_lattice(hdc,row+i,column+j,shape[i][j]);
}
}
}
//旋转当前形状并更新界面
int rotate_shape(HWND hwnd) {
int mn=;
rotate_matrix(mn);
if(!is_legel()) {
rerotate_matrix(mn);
}
update_UI(hwnd);
}
void reset_rc() {
row=;
column=MM/-;
}
//读取游戏最高分数据
int load_scores(int* a) {
FILE* f=fopen("scores.txt","r");
if(f==NULL)return -;
fscanf(f,"%d%d%d",&a[],&a[],&a[]);
return ;
}
//初始化游戏数据
void init_play() {
load_scores(high_score);
for(int i=; i<NN; i++) {
for(int j=; j<MM; j++) {
board[i][j]=;
}
}
for(int i=; i<N; i++) {
for(int j=; j<LEFT; j++) {
board[i][j]=;
}
}
for(int i=; i<N; i++) {
for(int j=RIGHT+; j<MM; j++) {
board[i][j]=;
}
}
for(int i=BOTTOM+; i<NN; i++) {
for(int j=; j<MM; j++) {
board[i][j]=;
}
}
reset_rc();
score=;
give_new_shape();
is_pause=false;
return ;
}
bool check_is_lose() {
if(row==)return true;
return false;
}
//对最高分和此次得分排序,若创造新纪录则返回true
bool sort_scores(int* a) {
int temp=a[];
for(int i=; i<; i++) {
for(int j=; j<; j++) {
if(a[j]<a[j+]) {
int t=a[j];
a[j]=a[j+];
a[j+]=t;
}
}
}
if(temp>a[])return true;
return false;
}
//写最高分数据
int write_scores(int* a) {
FILE* f=fopen("scores.txt","w");
if(f==NULL)return -;
fprintf(f,"%d\n%d\n%d\n",a[],a[],a[]);
return ;
}
//保存最高分数据
bool save_score(HWND hwnd) {
high_score[]=score;
bool made_record=sort_scores(high_score);
if(write_scores(high_score)!=) {
MessageBox(hwnd,"Write file error.Program will exit.","Error",NULL);
DestroyWindow(hwnd);
}
return made_record;
}
void lose_game(HWND hwnd) {
if(is_pause)return ;
is_pause=true;
char message[]="You lose the Game.\n";
char title[]="Game Over";
if(save_score(hwnd)) {
strcat(message,"You have made a new record.\n");
char score_str[];
sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[],high_score[],high_score[]);
strcat(message,score_str);
}
strcat(message,"\nPlay again?\n");
if(MessageBox(hwnd,message,title,MB_YESNO)==IDYES) {
init_play();
update_UI_all(hwnd);
} else {
exit();
}
}
void exit_game(HWND hwnd) {
is_pause=true;
char message[]="";
char title[]="Exit";
if(save_score(hwnd)) {
strcat(message,"You have made a new record.\n");
char score_str[];
sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[],high_score[],high_score[]);
strcat(message,score_str);
MessageBox(hwnd,message,title,NULL);
}
exit();
}
//当前形状落地之后,更新board
void shape_to_ground() {
for(int i=; i<; i++) {
for(int j=; j<; j++) {
board[row+i][column+j]=shape[i][j]==?:board[row+i][column+j];
}
}
}
//形状下落
int move_down(HWND hwnd) {
row++;
if(!is_legel()) {
row--;
if(check_is_lose()) {
lose_game(hwnd);
return ;
}
shape_to_ground();
clear_up();
update_UI_all(hwnd);
reset_rc();
give_new_shape();
}
update_UI(hwnd);
}
//进程参数结构体
struct thread_arg {
HWND arg_hwnd;
};
//形状下落进程要执行的函数
void* down_thread_function(void * args) {
thread_arg *arg=(thread_arg*)args;
HWND dhwnd=arg->arg_hwnd;
while(true) {
if(is_pause) {
Sleep();
continue;
}
move_down(dhwnd);
Sleep(LONG_SLEEP);
}
}
//初始化形状下落进程
int init_down_thread(HWND hwnd) {
int ret;
pthread_t t;
thread_arg *argp=new thread_arg;
argp->arg_hwnd=hwnd;
ret=pthread_create(&t,NULL,down_thread_function,argp);
delete argp;
if(ret!=) {
return -;
}
return ;
}
//初始化游戏程序
int init_game(HWND hwnd) {
board=new int*[NN];
for(int i=; i<NN; i++) {
board[i]=new int[MM];
}
shape=new int*[];
for(int i=; i<; i++) {
shape[i]=new int[];
}
srand(time());
if(load_shape()!=) {
MessageBox(hwnd,"Read file error.Program will exit.","Error",NULL);
exit(-);
}
init_play();
update_UI_all(hwnd);
if(init_down_thread(hwnd)!=) {
MessageBox(hwnd,"Thread error.Program will exit.","Error",NULL);
exit(-);
}
return ;
}
//形状左右移动
int move_lr(HWND hwnd,int lr) {
int temp=column;
if(lr==)column--;
else {
column++;
}
if(!is_legel()) {
column=temp;
}
update_UI(hwnd);
}
int handle_key(HWND hwnd,WPARAM wParam) {
if(wParam==VK_ESCAPE) {//ESC退出
exit_game(hwnd);
}
if(wParam==VK_SPACE) {//空格暂停
is_pause=!is_pause;
}
if(is_pause==true) {
Sleep();
return ;
}
if(wParam==VK_UP) {
rotate_shape(hwnd);
}
if(wParam==VK_DOWN) {
move_down(hwnd);
}
if(wParam==VK_LEFT) {
move_lr(hwnd,);
}
if(wParam==VK_RIGHT) {
move_lr(hwnd,);
}
return ;
}
/* This function is called by the Windows function DispatchMessage() */
HWND hwnd;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static HDC hdc;
static HDC hdcBuffer;
static HBITMAP hBitMap;
static PAINTSTRUCT ps ;
switch (message) { /* handle the messages */
case WM_CREATE:
init_game(hwnd);
break;
case WM_KEYDOWN:
handle_key(hwnd,wParam);
break;
case WM_DESTROY:
exit_game(hwnd);
PostQuitMessage (); /* send a WM_QUIT to the message queue */
break;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
paint_UI(hdc);
EndPaint (hwnd, &ps) ;
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return ;
}

嗯,后来发现 Codeblocks 可以在设置里设置不限时间地玩BYOGames。。。尬。。

程序写于2016年五一期间

随笔写于2016.5.8

END

俄罗斯方块(Win32实现,Codeblocks+GCC编译)的更多相关文章

  1. 局域网象棋游戏(C++实现,使用Socket,界面使用Win32,CodeBlocks+GCC编译)

    目录 成果 运行效果图 过程 1. 首先的问题是下棋的两端应该是什么样的? 2. 接下来的问题是怎么表示,怎么存储? 3. 然后应该怎么通信呢? 代码 main.cpp chinese_chess.h ...

  2. 抓鼠标的猫(Win32实现,Codeblocks+GCC编译)

    程序效果: 猫的眼睛一直跟着鼠标移动: 鼠标经过猫的右脚附近时,猫会抓住鼠标.(未使用Hook) 代码: //main.cpp 1 #include <windows.h> #includ ...

  3. 简单的词法分析和语法分析(C++实现,CodeBlocks+GCC编译)

    说明: 分析的语言是SNL语言,详见<编译程序的设计与实现>( 刘磊.金英.张晶.张荷花.单郸编著) 词法分析就是实现了词法分析的自动机 语法分析使用递归下降法 运行结果: 词法分析 得到 ...

  4. 在文件夹中 的指定类型文件中 查找字符串(CodeBlocks+GCC编译,控制台程序,仅能在Windows上运行)

    说明: 程序使用 io.h 中的 _findfirst 和 _findnext 函数遍历文件夹,故而程序只能在 Windows 下使用. 程序遍历当前文件夹,对其中的文件夹执行递归遍历.同时检查遍历到 ...

  5. GLine游戏(Win32GUI实现,CodeBlocks+GCC编译)

    游戏规则: 在10X10的棋盘上有五种颜色的棋子. 点击一个棋子,再点击一个空格子,如果两者之间有一条路径的话,棋子会移动到空格子内. 每移动一次,棋盘上会增加三个棋子,其位置和颜色都是随机的. 当横 ...

  6. Socket服务端和客户端(C++,CodeBlocks+GCC编译)

    //main.cpp 1 #include "j_socket.h" #include <stdio.h> #include <pthread.h> ; j ...

  7. Shell(C++实现,CodeBlocks+GCC编译)

    程序效果: 只实现了login .cd .ls .cat 四个命令.而且只能在 Windows 下运行. 代码: //main.cpp 1 #include <iostream> #inc ...

  8. gcc 编译 + 选项【转】

    转自:http://blog.csdn.net/princess9/article/details/6567678 一般来说要现有项目中的编译选项,设置新的project的编译选项 编译器 就是将“高 ...

  9. 在linux操作系统上进行简单的C语言源码的gcc编译实验

    尝试在linux上用gcc 而非封装完好的codeblocks,vs等ide 来编译c和cpp源程序 首先查看我的gcc版本,我的是VM centos 自带的,没有的话得自行安装,安装上gcc就可以在 ...

随机推荐

  1. 在Windows Server 2012 R2的Hyper-V中设置虚拟机启用增强会话模式

    在Windows Server 2012 R2的Hyper-V中,可以为虚拟机提供一种全新的连接方式,就是“增强会话模式”,它将让您更加方便的对虚拟机进行操作,比如分辨率的调整.设备的加载,最为方便的 ...

  2. MVC依赖性注入概述

    MVC框架之所以如此受欢迎的原因之一就是它十分注意支持关注分离,使各个功能部件尽量能够相互独立.今天我们就来看看MVC4如何使用DI方法实现一些组件的独立,使本来结合紧密的部件,松耦合.我现在所说的对 ...

  3. Collection框架

    Collection框架 集合框架(Collection Framework)泛指java.util包的若干个类和接口.如Collection,List,ArrayList,LinkedList,Ve ...

  4. linux 下 systemd-udevd 服务解析

    最近在看linux下重定向的时候看到 的这个系统的服务,所以记下来备忘. 描述:systemd-udevd是监听内核发出的设备事件,并根据udev规则处理每个事件. 选项: --daemon 脱离控制 ...

  5. 能力素质模型咨询工具(Part1)

          之前写过由企业家基本素质想到的文章,里面提及一些能力与素质,以下有内容也可以参考: 领导职位 表6-1 远见卓识的行为表现 级 别 行 为 表 现 A (1)关注行业的前景和环境的变化, ...

  6. java实现链表

    单链表 package com.voole.linkedlist; public class Test { public static void main(String[] args) { Linke ...

  7. 高性能 TCP & UDP 通信框架 HP-Socket v3.2.3

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...

  8. [转载]C#使用Interlocked进行原子操作

    原文链接:王旭博客 » C# 使用Interlocked进行原子操作 什么是原子操作? 原子(atom)本意是"不能被进一步分割的最小粒子",而原子操作(atomic operat ...

  9. arcgis for flex全国地图天气预报的具体实现过程解析

    系统架构是B/S,开发语言是flex,开发工具是myeclise或者flashbuild,通过调用百度提供的在线天气预报web api接口的方式来实现. 采用地图是ArcGIS全国地图,开发接口为ar ...

  10. html5快速入门(四)—— JavaScript

    前言: 1.HTML5的发展非常迅速,可以说已经是前端开发人员的标配,在电商类型的APP中更是运用广泛,这个系列的文章是本人自己整理,尽量将开发中不常用到的剔除,将经常使用的拿出来,使需要的朋友能够真 ...