using System;
using System.Collections;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace 連連看
{
public partial class Form1 : Form
{
#region LinkType enum
public enum LinkType
{
LineType,
OneCornerType,
TwoCornerType
};
#endregion
private readonly int[] m_map = new int[10*10];
private int BLANK_STATE = -1;
private int GameSize = 10; //布局大小即行列數
private LinkType LType; //連通方式
private bool Select_first; //是否已經選中第一塊
private Bitmap Source; //所有動物圖案的圖檔
private int W = 50; //動物方塊圖案的寬度
private int m_nCol = 10;
private int m_nRow = 10;
private int x1; //被選中第一塊的地圖坐标
private int x2; //被選中第二塊的地圖坐标
private int y1; //被選中第一塊的地圖坐标
private int y2; //被選中第二塊的地圖坐标
private Point z1, z2; //折點棋盤坐标
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Source = (Bitmap) Image.FromFile("..\\..\\res\\animal.bmp");
pictureBox1.Height = W*(m_nRow + 2);
pictureBox1.Width = W*(m_nCol + 2);
pictureBox1.Top = 0;
pictureBox1.Left = 0;
//目前窗體标題欄高度
int d = (Height - ClientRectangle.Height);
Height = pictureBox1.Height + pictureBox1.Top + d;
Width = pictureBox1.Width + pictureBox1.Left;
//for (int i = 0; i < 10 * 10; i++)
//{
// m_map[i] = i % 6;
//}
StartNewGame();
Init_Graphic();
}
private void StartNewGame()
{
//初始化地圖,将地圖中所有方塊區域位置置為空方塊狀态
for (int iNum = 0; iNum < (m_nCol*m_nRow); iNum++)
{
m_map[iNum] = BLANK_STATE;
}
Random r = new Random();
//生成随機地圖
//将所有的動物物種放進一個臨時的地圖tmpMap中
ArrayList tmpMap = new ArrayList();
for (int i = 0; i < (m_nCol*m_nRow)/4; i++)
for (int j = 0; j < 4; j++)
tmpMap.Add(i);
//每次從上面的臨時地圖tmpMap中取走(擷取後并在臨時地圖删除)
//一個動物放到地圖的空方塊上
for (int i = 0; i < m_nRow*m_nCol; i++)
{
//随機挑選一個位置
int nIndex = r.Next()%tmpMap.Count;
//擷取該標明物件放到地圖的空方塊
m_map[i] = (int) tmpMap[nIndex];
//在臨時地圖tmpMap除去該動物
tmpMap.RemoveAt(nIndex);
}
}
private void Init_Graphic()
{
Graphics g = get_Graphic(); //生成Graphics對象
for (int i = 0; i < 10*10; i++)
{
g.DrawImage(create_image(m_map[i]), W*(i%GameSize) + W,
W*(i/GameSize) + W, W, W);
}
}
private Graphics get_Graphic()
{
if (pictureBox1.Image == null)
{
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = bmp;
}
Graphics g = Graphics.FromImage(pictureBox1.Image);
return g;
}
public Graphics GetGraphicsObject(ref PictureBox pic)
{
Graphics g;
Bitmap bmp = new Bitmap(pic.Width, pic.Height);
pic.Image = bmp;
g = Graphics.FromImage(bmp);
return g;
}
//create_image()方法實作按标号n從所有動物圖案的圖檔中截圖。
private Bitmap create_image(int n) //按标号n截圖
{
Bitmap bit = new Bitmap(W, W);
Graphics g = Graphics.FromImage(bit); //生成Graphics對象
Rectangle a = new Rectangle(0, 0, W, W);
Rectangle b = new Rectangle(0, n*39, 39, 39);
//截取原圖中b矩形區域的圖形
g.DrawImage(Source, a, b, GraphicsUnit.Pixel);
return bit;
}
///檢測是否已經赢得了遊戲
private bool IsWin()
{
//檢測是否尚有非未被消除的方塊
// (非BLANK_STATE狀态)
for (int i = 0; i < m_nRow*m_nCol; i++)
{
if (m_map[i] != BLANK_STATE)
{
return false;
}
}
return true;
}
private bool IsSame(int x1, int y1, int x2, int y2)
{
if (m_map[y1*m_nCol + x1] == m_map[y2*m_nCol + x2])
return true;
else
return false;
}
//
//X直接連通即垂直方向連通
//
private bool X_Link(int x, int y1, int y2)
{
//保證y1的值小于y2
if (y1 > y2)
{
//資料交換
int n = y1;
y1 = y2;
y2 = n;
}
//直通
for (int i = y1 + 1; i <= y2; i++)
{
if (i == y2)
return true;
if (m_map[i*m_nCol + x] != BLANK_STATE)
break;
}
return false;
}
//
//Y直接連通即水準方向連通
//
private bool Y_Link(int x1, int x2, int y)
{
if (x1 > x2)
{
int x = x1;
x1 = x2;
x2 = x;
}
//直通
for (int i = x1 + 1; i <= x2; i++)
{
if (i == x2)
return true;
if (m_map[y*m_nCol + i] != BLANK_STATE)
break;
}
return false;
}
//
// 1直角接口連通
//
private bool OneCornerLink(int x1, int y1, int x2, int y2)
{
if (x1 > x2) //目标點(x1,y1),(x2,y2)兩點交換
{
int n = x1;
x1 = x2;
x2 = n;
n = y1;
y1 = y2;
y2 = n;
}
if (y2 < y1) //(x1,y1)為矩形左下頂點,(x2,y2)點為矩形右上頂點
{
//判斷矩形右下角折點(x2,y1)是否空
if (m_map[y1*m_nCol + x2] == BLANK_STATE)
{
if (Y_Link(x1, x2, y1) && X_Link(x2, y1, y2))
//判斷折點(x2,y1)與兩個目标點是否直通
{
z1.X = x2;
z1.Y = y1; //儲存折點坐标到z1
return true;
}
}
//判斷矩形左上角折點(x1,y2)是否空
if (m_map[y2*m_nCol + x1] == BLANK_STATE)
{
if (Y_Link(x2, x1, y2) && X_Link(x1, y2, y1))
//判斷折點 (x1,y2)與兩個目标點是否直通
{
z1.X = x1;
z1.Y = y2; //儲存折點坐标到z1
return true;
}
}
return false;
}
else //(x1,y1)為矩形左上頂點,(x2,y2)點為矩形右下頂點
{
//判斷矩形左下角折點(x1,y2)是否空
if (m_map[y2*m_nCol + x1] == BLANK_STATE)
{
if (Y_Link(x1, x2, y2) && X_Link(x1, y1, y2))
//判斷折點 (x1,y2)與兩個目标點是否直通
{
z1.X = x1;
z1.Y = y2; //儲存折點坐标到z1
return true;
}
}
//判斷矩形右上角折點(x2,y1)是否空
if (m_map[y1*m_nCol + x2] == BLANK_STATE)
{
if (Y_Link(x1, x2, y1) && X_Link(x2, y1, y2))
//判斷折點(x2,y1)與兩個目标點是否直通
{
z1.X = x2;
z1.Y = y1; //儲存折點坐标到z1
return true;
}
}
return false;
}
}
///2折點連通
private bool TwoCornerLink(int x1, int y1, int x2, int y2)
{
if (x1 > x2)
{
int n = x1;
x1 = x2;
x2 = n;
n = y1;
y1 = y2;
y2 = n;
}
//右
int x, y;
for (x = x1 + 1; x <= m_nCol; x++)
{
if (x == m_nCol)
//兩個折點在選中方塊的右側,且兩個折點在圖案區域之外
if (XThrough(x2 + 1, y2, true))
//Y_Link(x2 + 1, m_nCol-1, y2)&&m_map[y1 * (m_nCol-1) + x]== BLANK_STATE
{
z2.X = m_nCol;
z2.Y = y1;
z1.X = m_nCol;
z1.Y = y2;
return true;
}
else
break;
if (m_map[y1*m_nCol + x] != BLANK_STATE)
break;
if (OneCornerLink(x, y1, x2, y2))
{
z2.X = x;
z2.Y = y1;
return true;
}
}
//左
for (x = x1 - 1; x >= -1; x--)
{
if (x == -1)
//兩個折點在選中方塊的左側,且兩個折點在圖案區域之外
if (XThrough(x2 - 1, y2, false))
{
z2.X = -1;
z2.Y = y1;
z1.X = -1;
z1.Y = y2;
return true;
}
else
break;
if (m_map[y1*m_nCol + x] != BLANK_STATE)
break;
if (OneCornerLink(x, y1, x2, y2))
{
z2.X = x;
z2.Y = y1;
return true;
}
}
//上
for (y = y1 - 1; y >= -1; y--)
{
if (y == -1)
//兩個折點在選中方塊的上側,且兩個折點在圖案區域之外
if (YThrough(x2, y2 - 1, false))
{
z2.X = x1;
z2.Y = -1;
z1.X = x2;
z1.Y = -1;
return true;
}
else
break;
if (m_map[y*m_nCol + x1] != BLANK_STATE)
break;
if (OneCornerLink(x1, y, x2, y2))
{
z2.X = x1;
z2.Y = y;
return true;
}
}
//下
for (y = y1 + 1; y <= m_nRow; y++)
{
if (y == m_nRow)
//兩個折點在選中方塊的下側,且兩個折點在圖案區域之外
if (YThrough(x2, y2 + 1, true))
{
z2.X = x1;
z2.Y = m_nRow;
z1.X = x2;
z1.Y = m_nRow;
return true;
}
else
break;
if (m_map[y*m_nCol + x1] != BLANK_STATE)
break;
if (OneCornerLink(x1, y, x2, y2))
{
z2.X = x1;
z2.Y = y;
return true;
}
}
return false;
}
private bool XThrough(int x, int y, bool bAdd) //水準方向判斷到邊界的連通性
{
if (bAdd) //True,水準向右判斷是否連通(是否為空)
{
for (int i = x; i < m_nCol; i++)
if (m_map[y*m_nCol + i] != BLANK_STATE)
return false;
}
else //false, 水準向左判斷是否連通(是否為空)
{
for (int i = 0; i <= x; i++)
if (m_map[y*m_nCol + i] != BLANK_STATE)
return false;
}
return true;
}
private bool YThrough(int x, int y, bool bAdd) //垂直方向判斷到邊界的連通性)
{
if (bAdd) //True, 垂直方向向下判斷是否連通(是否為空)
{
for (int i = y; i < m_nRow; i++)
if (m_map[i*m_nCol + x] != BLANK_STATE)
return false;
}
else //false, 垂直方向向上判斷是否連通(是否為空)
{
for (int i = 0; i <= y; i++)
if (m_map[i*m_nCol + x] != BLANK_STATE)
return false;
}
return true;
}
//
// 判斷選中的兩個方塊是否可以消除
//
private bool IsLink(int x1, int y1, int x2, int y2)
{
//X直連方式即垂直方向連通
if (x1 == x2)
{
if (X_Link(x1, y1, y2))
{
LType = LinkType.LineType;
return true;
}
}
//Y直連方式即水準方向連通
else if (y1 == y2)
{
if (Y_Link(x1, x2, y1))
{
LType = LinkType.LineType;
return true;
}
}
//一個轉彎(折點)的聯通方式
if (OneCornerLink(x1, y1, x2, y2))
{
LType = LinkType.OneCornerType;
return true;
}
//兩個轉彎(折點)的聯通方式
else if (TwoCornerLink(x1, y1, x2, y2))
{
LType = LinkType.TwoCornerType;
return true;
}
return false;
}
private bool Find2Block()
{
bool bFound = false;
//第一個方塊從地圖的0位置開始
for (int i = 0; i < m_nRow*m_nCol; i++)
{
//找到則跳出循環
if (bFound)
break;
//無動物的空格跳過
if (m_map[i] == BLANK_STATE)
continue;
//第二個方塊從前一個方塊的後面開始
for (int j = i + 1; j < m_nRow*m_nCol; j++)
{
//第二個方塊不為空 且與第一個方塊的動物相同
if (m_map[j] != BLANK_STATE && m_map[i] == m_map[j])
{
//算出對應的虛拟行列位置
x1 = i%m_nCol;
y1 = i/m_nCol;
x2 = j%m_nCol;
y2 = j/m_nCol;
//判斷是否可以連通
if (IsLink(x1, y1, x2, y2))
{
bFound = true;
break;
}
}
}
}
if (bFound)
{
//(x1,y1)與(x2,y2)連通
Graphics g = pictureBox1.CreateGraphics(); //生成Graphics對象
//**********************************
//Graphics g = get_Graphic(); //生成Graphics對象
//************************************
Pen myPen = new Pen(Color.Blue, 3);
Rectangle b1 = new Rectangle(x1*W + 1 + W, y1*W + 1 + W, W - 3, W - 3);
g.DrawRectangle(myPen, b1);
Rectangle b2 = new Rectangle(x2*W + 1 + W, y2*W + 1 + W, W - 3, W - 3);
g.DrawRectangle(myPen, b2);
}
return bFound;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
//Init_Graphic();
}
private void Delay(int second) //讓程式延時數秒
{
DateTime now = DateTime.Now;
while (now.AddSeconds(second) > DateTime.Now)
{
}
}
/// <summary>
/// 畫選中方塊之間連接配接線
/// </summary>
private void DrawLinkLine(int x1, int y1, int x2, int y2, LinkType LType)
{
Graphics g = pictureBox1.CreateGraphics(); //生成Graphics對象
Pen p = new Pen(Color.Red, 3);
Point p1 = new Point(x1*W + W/2 + W, y1*W + W/2 + W);
Point p2 = new Point(x2*W + W/2 + W, y2*W + W/2 + W);
if (LType == LinkType.LineType)
g.DrawLine(p, p1, p2);
if (LType == LinkType.OneCornerType)
{
Point pixel_z1 = new Point(z1.X*W + W/2 + W, z1.Y*W + W/2 + W);
g.DrawLine(p, p1, pixel_z1);
g.DrawLine(p, pixel_z1, p2);
}
if (LType == LinkType.TwoCornerType)
{
Point pixel_z1 = new Point(z1.X*W + W/2 + W, z1.Y*W + W/2 + W);
Point pixel_z2 = new Point(z2.X*W + W/2 + W, z2.Y*W + W/2 + W);
if (!(p1.X == pixel_z2.X || p1.Y == pixel_z2.Y))
{
//p1與pixel_z2不在一直線上,則pixel_z1,pixel_z2交換
Point c;
c = pixel_z1;
pixel_z1 = pixel_z2;
pixel_z2 = c;
}
g.DrawLine(p, p1, pixel_z2);
g.DrawLine(p, pixel_z2, pixel_z1);
g.DrawLine(p, pixel_z1, p2);
}
}
/// <summary>
/// 清除選中方塊之間連接配接線
/// </summary>
private void UnDrawLinkLine(int x1, int y1, int x2, int y2, LinkType LType)
{
Graphics g = pictureBox1.CreateGraphics(); //生成Graphics對象
Pen p = new Pen(BackColor, 3);
Point p1 = new Point(x1*W + W/2 + W, y1*W + W/2 + W);
Point p2 = new Point(x2*W + W/2 + W, y2*W + W/2 + W);
if (LType == LinkType.LineType)
g.DrawLine(p, p1, p2);
if (LType == LinkType.OneCornerType)
{
Point pixel_z1 = new Point(z1.X*W + W/2 + W, z1.Y*W + W/2 + W);
g.DrawLine(p, p1, pixel_z1);
g.DrawLine(p, pixel_z1, p2);
}
if (LType == LinkType.TwoCornerType)
{
Point pixel_z1 = new Point(z1.X*W + W/2 + W, z1.Y*W + W/2 + W);
Point pixel_z2 = new Point(z2.X*W + W/2 + W, z2.Y*W + W/2 + W);
if (!(p1.X == pixel_z2.X || p1.Y == pixel_z2.Y))
{
//p1與pixel_z2不在一直線上,則pixel_z1,pixel_z2交換
Point c;
c = pixel_z1;
pixel_z1 = pixel_z2;
pixel_z2 = c;
}
g.DrawLine(p, p1, pixel_z2);
g.DrawLine(p, pixel_z2, pixel_z1);
g.DrawLine(p, pixel_z1, p2);
}
}
private void DrawSelectedBlock(int x, int y, Pen myPen, Graphics g)
{
//畫選中方塊的示意邊框線
Rectangle b1 = new Rectangle(x*W + 1 + W, y*W + 1 + W, W - 3, W - 3);
g.DrawRectangle(myPen, b1);
}
private void ClearSelectedBlock(int x, int y, Graphics g)
{
//清除選中方塊
SolidBrush myBrush = new SolidBrush(BackColor); //定義背景色畫刷
Rectangle b1 = new Rectangle(x*W + W, y*W + W, W, W);
g.FillRectangle(myBrush, b1);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Cursor.Current = Cursors.Hand;
Graphics g = pictureBox1.CreateGraphics(); //生成Graphics對象
//**********************************
//Graphics g = get_Graphic(); //生成Graphics對象
//************************************
Pen myPen = new Pen(Color.Red, 3);
int x, y;
if (e.Button == MouseButtons.Left)
{
//計算點選的方塊的位置坐标
x = (e.X - W)/W;
y = (e.Y - W)/W;
//如果該區域無方塊
if (m_map[y*m_nCol + x] == BLANK_STATE) return;
if (Select_first == false)
{
x1 = x;
y1 = y;
//畫標明(x1,y1)處的框線
DrawSelectedBlock(x1, y1, myPen, g);
Select_first = true;
}
else
{
x2 = x;
y2 = y;
//判斷第二次點選的方塊是否已被第一次點選選取,如果是則傳回。
if ((x1 == x2) && (y1 == y2)) return;
//畫標明(x2,y2)處的框線
//myPen = new Pen(Color.Red, 3);
//Rectangle b = new Rectangle(x2 * W + 1, y2 * W + 1, W - 3, W - 3);
//g.DrawRectangle(myPen, b);
DrawSelectedBlock(x2, y2, myPen, g);
//判斷是否連通
if (IsSame(x1, y1, x2, y2) && IsLink(x1, y1, x2, y2))
{
DrawLinkLine(x1, y1, x2, y2, LType); //畫選中方塊之間連接配接線
Thread.Sleep(500); //延時0.5秒
ClearSelectedBlock(x1, y1, g); //清除第一個標明方塊
ClearSelectedBlock(x2, y2, g); //清除第一個標明方塊
//清空記錄方塊的值
m_map[y1*m_nCol + x1] = BLANK_STATE;
m_map[y2*m_nCol + x2] = BLANK_STATE;
Select_first = false;
UnDrawLinkLine(x1, y1, x2, y2, LType); //清除選中方塊之間連接配接線
}
else //重新標明第一個方塊
{
//重畫(x1,y1)處動物圖案來達到取消原標明(x1,y1)處的框線
int i = y1*m_nCol + x1;
g.DrawImage(create_image(m_map[i]), W*(i%GameSize) + W,
W*(i/GameSize) + W, W, W);
//設定重新標明第一個方塊的坐标
x1 = x;
y1 = y;
//畫新標明(x1,y1)處的框線
//myPen = new Pen(Color.Red, 3);
//Rectangle b2 = new Rectangle(x1 * W + 1, y1 * W + 1, W - 3, W - 3);
//g.DrawRectangle(myPen, b2);
Select_first = true;
}
}
}
if (e.Button == MouseButtons.Right) //智能查找功能
{
if (!Find2Block()) MessageBox.Show("沒有連通的方塊了!!");
}
//察看是否已經勝利
if (IsWin())
{
MessageBox.Show("恭喜您成功闖關。");
//StartNewGame();
}
}
}
}