锁谜题:一个令人费解的谜题
一个烧脑的谜题,您必须转动几个相互连接的钥匙才能找到解决方案。
目录
引言
这个项目是一个非常容易上瘾,并且有些催眠的谜题游戏,玩家需要尝试将所有16个钥匙都调整到垂直位置。 规则如下:
- 锁有16个钥匙,排列成4x4的阵列;每个钥匙要么水平放置,要么垂直放置。
- 为了打开锁,所有的钥匙都必须垂直放置。
- 当你将一个钥匙转到另一个位置时,同一行和同一列的所有其他钥匙也会自动切换它们的位置。
背景
在这篇文章中,我想展示如何创建一个源自名为“锁难题”的数学问题的游戏。 Paul Zeitz 教授在他最近的题为“数学问题解决的艺术和技巧”的系列讲座中提出了这个问题,在看到这个问题后,我受到了启发,并使用 C# 将其转换为一个简单的谜题游戏。
关注点
好吧,让我们先组织我们的零件。棋盘有 16 个元素,排列在四行四列中。我们该如何安排,才能使点击一个钥匙也能旋转其他六个相应的钥匙? 可能有几种方法可以实现这一点,但这就是我决定尝试的方法。 我首先根据 4x4 阵列中每个元素的位置为其分配一个数字 ID。 第一个数字表示行,第二个数字表示列。

第一行第一列的元素被命名为 L11,而第三行第二个元素被命名为 L32。 让我们点击钥匙 L32。

我们的代码需要遍历 L11-L44 的元素列表,并找到哪些元素的 ID 与点击的元素相对应。 在 L32 的情况下,我们希望找到任何以 3 开头或以 2 结尾的 ID。

这是用于查找和旋转钥匙的主要方法。
private void ToggleKeyStates(object sender, EventArgs e)
{
// Get Sender cell coordinates and assign them to X and X char arrays
// This is the Key that was clicked
char[] XY = ((Key)sender).Name.ToCharArray(1, 2);
char X = XY[0];
char Y = XY[1];
// Using the clicked object as a reference,
// Cycle through controls and find the corresponding key objects
foreach (Key l in this.panel1.Controls)
{
// split the names of the key objects into char array
char[] xy = l.Name.ToCharArray(1, 2);
char x = xy[0];
char y = xy[1];
// Change state of rows and columns only
if (X == x || Y == y)
{
if(l.IsTurning == false)
l.TurnKey();
}
}
}
Using the Code
关于Key
控件的几句话:它有两个public
布尔属性,名为isTurning
和isLocked
。 isTurning
属性告诉调用方法该钥匙正在旋转过程中。 如果isLocked
属性为true
,则告诉调用方法该钥匙处于水平锁定位置。
public bool IsLocked
{
get{return m_isLocked;}
set {m_isLocked = value;}
}
public bool IsTurning
{
get{return m_isTurning;}
set{m_isTurning = value;}
}
锁和解锁
当我们点击钥匙对象时,isTurning
和isLocked
属性将被切换,计时器启动,并且钥匙旋转开始。 启用计时器后,会持续调用DefinePositions()
,该方法设置线上最外层点的限制,使其位于 12 点、3 点、6 点或 9 点钟位置。 钥匙旋转到水平或垂直位置,然后禁用计时器并停止旋转。
private void DefinePositions()
{
// Rotate and stop at the 3, 6, 9, and 12 o'clock positions.
if (Degrees == 360)
{
Degrees = 0; // reset
this.timer1.Enabled = false; // stop timer
m_isTurning = !m_isTurning; // toggle turning flag
m_isLocked = false; // toggle locked flag
}
else if (Degrees == 90)
{
this.timer1.Enabled = false;
m_isTurning = !m_isTurning;
m_isLocked = true;
Degrees++;
}
else if (Degrees == 180)
{
this.timer1.Enabled = false;
m_isTurning = !m_isTurning;
m_isLocked = false;
Degrees++;
}
else if (Degrees == 270)
{
this.timer1.Enabled = false;
m_isTurning = !m_isTurning;
m_isLocked = true;
Degrees++;
}
else // keep moving and let us know that you are moving.
{
Degrees++;
m_isTurning = true;
}
// Update the form and controls.
this.Refresh();
}
跟随路径
圆形路径的原点和表面在DefineSurfacePath
方法中定义。
private void DefineSurfacePath(out int x_center, out int y_center,
out float x_path, out float y_path, out float x_path2, out float y_path2)
{
int Radius = 30;
x_center = this.Width / 2;
y_center = this.Height / 2;
// define outer rotation path for first line
x_path = (GetCos(360 + Degrees + x_center + degreeOffset) * Radius) + x_center;
y_path = (GetSin(360 + Degrees + y_center + degreeOffset) * Radius) + y_center;
// define outer rotation path for second line
x_path2 = (GetCos(360 + Degrees + 180 + x_center + degreeOffset) * Radius) + x_center;
y_path2 = (GetSin(360 + Degrees + 180 + y_center + degreeOffset) * Radius) + y_center;
}
渲染
OnPaint(PaintEventArgs e)
重写持续调用DrawKey(Graphics g)
。
protected override void OnPaint(PaintEventArgs e)
{
// give .net the first try
base.OnPaint(e);
// then take over
Graphics g = e.Graphics;
DrawKey(g);
}
在定义所有绘图点和位置后,DrawKey(Graphics g)
方法只是将给定的值绘制到屏幕上。
public void DrawKey(Graphics g)
{
// ake sure all graphics are smooth, not blocky.
g.SmoothingMode = SmoothingMode.AntiAlias;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Declare Brush and pen objects
Brush brshREC = new SolidBrush(Color.White);
Pen p = new Pen(brshREC, 10);
// Declare radius and origin of circle
int x_center;
int y_center;
float x_path;
float y_path;
float x_path2;
float y_path2;
DefineSurfacePath(out x_center, out y_center, out x_path, out y_path,
out x_path2, out y_path2);
// draw previously defined points
g.DrawLine(p, x_center, y_center, x_path, y_path);
g.DrawLine(p, x_center, y_center, x_path2, y_path2);
}
历史
- 2010-06-22 - 第一个版本