我一直在尝试为我一直在努力的程序编写一些逻辑,并遇到了一些困难。
基本上我在我的舞台上以编程方式创建的是一个4x4网格(16个块),看起来就像这样:
用户的任务是通过单击块将连续的形状绘制到网格上,并且它们的形状应该包含无间隙和没有对角线绘制的块,例如以下是合法的形式:
但是,以下形状不会,并会以弹出图形的形式向用户抛出错误:
网格的绘图过程与布尔阵列形式的网格的4x4虚拟表示相关联,如下所示:
public static var ppnRowArray1:Array = [false,false,false,false];
public static var ppnRowArray2:Array = [false,false,false,false];
public static var ppnRowArray3:Array = [false,false,false,false];
public static var ppnRowArray4:Array = [false,false,false,false];
public static var ppnColumnArray:Array = [ppnRowArray1,ppnRowArray2,ppnRowArray3,ppnRowArray4];
当用户单击并选择一个块时,将color属性更改为brown,我的“虚拟网格表示”数组中的相关布尔属性将从false更改为true。如果非法制作地块,则此属性将更改为false,然后邀请用户再次尝试下一个绘图。
我已设法编写强制用户绘制合法形状的代码,并在制作非法绘图时计算出来,但我现在需要编写逻辑,以便当用户从现有内容中取消选择块时合法的形状,使其不连续,这就是我的问题所在。
这是现有的工作解决方案。
//---------------------------------------------------------------------
public static function ppnCountSetCells():int
{
//Count Each 4x4 Grid Cell
var count:int = 0;
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row])
{
count++;
}
}
}
return count;
}
//---------------------------------------------------------------------
public static function ppnBlockValid():Boolean
{
if (ppnCountSetCells() > 1)
{
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row] == true)
{
// Check if we are connected to another set square
var validNeighbours:int = 0;
// Check North
if (row > 0)
{
if (ppnColumnArray[col][row - 1] == true)
{
validNeighbours++;
}
}
// Check South
if (row < 3)
{
if (ppnColumnArray[col][row + 1] == true)
{
validNeighbours++;
}
}
// Check West
if (col > 0)
{
if (ppnColumnArray[col - 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------------------------
// Check East
if (col < 3)
{
if (ppnColumnArray[col + 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------
if (validNeighbours < 1)
{
return false;
}
//-----------------------------------------------------------------------
}
}
}
}
return true;
}
//---------------------------------------------------------------------
function addBlock(e:MouseEvent):void
{
//trace("You Have Clicked On Grid Block Number: " + e.currentTarget.id);
if (InterfaceButtons.panelOpen == false)
{
//Listen to see if the block click is adjoining and pass back to see if it is valid on the grid
var col:int = (e.currentTarget.id - 1) % 4;
var row:int = (e.currentTarget.id - 1) / 4;
ppnColumnArray[col][row] = true;
addOrRemove = "add";
ppnBlockValid();
//Get the Block Valid Result (True or False) and pass it into a Boolean variable to use later
ppnGridError = ppnBlockValid();
trace("Is This Valid? " + ppnBlockValid());
//----------------------------------------------------------------------------------------------
//Push Blocks Selected into Array
ppnShapeArray[e.currentTarget.id] = true;
trace(ppnShapeArray);
//----------------------------------------------------------------------------------------------
//Add 1 to the block count which directly effects the final outcome depending on ++ or --
ppnBlocksSelected++;
PlantPopNitDesignPlot.ppnPlotMade = false;
//Hide Block to Reveal Brown One
e.currentTarget.alpha = 0;
//-----------------------------------------------------------------------------------------------
//Output an error if one is present on Click based on gridError Boolean Variable
ppnOutputAddError();
if (ppnGridError == false)
{
//Restore the block's alpha property as it isn't allowed to be selected, removing counter by one -- and changing final output accordingly
e.currentTarget.alpha = 1;
ppnBlocksSelected--;
ppnColumnArray[col][row] = false;
ppnShapeArray[e.currentTarget.id] = false;
ppnPopulateTotalSiteUnitsTxt();
}
//Update final total
ppnPopulateTotalSiteUnitsTxt();
//Call again to do dynamic colour font change should total exceed 10
ppnPopulateTotalSiteUnitsTxt();
//Added in to make sure it executes every time if an error is made.
if (ppnGridError == true)
{
e.currentTarget.removeEventListener(MouseEvent.CLICK, addBlock);
e.currentTarget.addEventListener(MouseEvent.CLICK, removeBlock);
}
}
}
function removeBlock(e:MouseEvent):void
{
if (InterfaceButtons.panelOpen == false)
{
var col:int = (e.currentTarget.id - 1) % 4;
var row:int = (e.currentTarget.id - 1) / 4;
ppnColumnArray[col][row] = false;
addOrRemove = "remove";
ppnBlockValid();
ppnGridError = ppnBlockValid();
trace("Is This Removal Valid? " + ppnBlockValid());
//trace("You Have Clicked On Grid Block Number: " + e.currentTarget.id);
e.currentTarget.alpha = 1;
ppnShapeArray[e.currentTarget.id] = false;
//trace("ppnShapeArray - " + ppnShapeArray);
//---------------------------------------------------------------------
ppnBlocksSelected--;
PlantPopNitDesignPlot.ppnPlotMade = false;
//Output an error if one is present on Click based on gridError Boolean Variable
ppnOutputRemoveError();
if (ppnGridError == false)
{
//Restore the block's alpha property as it isn't allowed to be selected, removing counter by one -- and changing final output accordingly
e.currentTarget.alpha = 0;
ppnBlocksSelected--;
ppnColumnArray[col][row] = true;
ppnShapeArray[e.currentTarget.id] = true;
ppnPopulateTotalSiteUnitsTxt();
}
//Update Final Total
ppnPopulateTotalSiteUnitsTxt();
//Call again to do dynamic colour font change should total falls below 10
ppnPopulateTotalSiteUnitsTxt();
//Added in to make sure it executes every time.
if (ppnGridError == true)
{
e.currentTarget.addEventListener(MouseEvent.CLICK, addBlock);
e.currentTarget.removeEventListener(MouseEvent.CLICK, removeBlock);
}
}
}
}
}
//---------------------------------------------------------------------
现在,对于大多数情况,这个逻辑在向形状添加或移除块时会起作用并检测非法图,但是最近我发现当我有5个&gt;在某些情况下,形状中的块,用于检测删除错误的逻辑失败。
一些形状被声明为真实且合法的例子(如果一个块被删除)如下:
我可以看到它是我的'ppnBlockValid():Boolean'函数中编写的逻辑,需要调整以补偿这些输出。看起来你只能移除一个块,前提是相邻的块仍然与其他块相连。虽然这适用于较小的形状,但理论上较大的形状(例如5个或更多个)可以在中间分割,所以我认为代码需要调整以解释这个问题。
但是怎么样?对此的任何帮助将不胜感激。非常感谢,如果您需要我的任何进一步信息,请告诉我。
干杯,
乔尔
被修改
非常感谢您提供增强的代码和解释@dhc我真的很感激,但我仍然对如何正确实现所有这些感到困惑。
以下是我目前的'ppnBlockValid'功能代码,基于您的建议:
public static function ppnBlockValid():Boolean
{
ppnIslands = [];
ppnAddNewIsland = [];
ppnAddToExistingIsland = [];
if (ppnCountSetCells() > 1)
{
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row] == true)
{
var addedToIsland = false;
// Check if we are connected to another set square
var validNeighbours:int = 0;
// Check North
if (row > 0)
{
if (ppnColumnArray[col][row - 1] == true)
{
validNeighbours++;
}
//----------------------------------
//ISLAND CHECK
if (ppnColumnArray[col][row - 1])
{
ppnAddToExistingIsland.push([col,row - 1],[col,row]);
addedToIsland = true;
}
}
// Check South
if (row < 3)
{
if (ppnColumnArray[col][row + 1] == true)
{
validNeighbours++;
}
}
// Check West
if (col > 0)
{
if (ppnColumnArray[col - 1][row] == true)
{
validNeighbours++;
}
//----------------------------------
//ISLAND CHECK
if (ppnColumnArray[col - 1][row])
{
ppnAddToExistingIsland.push([col - 1,row],[col,row]);
addedToIsland = true;
}
}
//-----------------------------------------------------------------------------------------
// Check East
if (col < 3)
{
if (ppnColumnArray[col + 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------
if (! addedToIsland)
{
ppnIslands.push([col,row]);
}
//-----------------------------------------------------------------------
if (ppnIslands.length >= 2 && addOrRemove == "remove")
{
trace("TWO ISLANDS HAVE BEEN FORMED AND AN ERROR SHOULD BE OUTPUT");
validNeighbours--;
}
/**/
//return (ppnIslands.length<=1);// 0 islands is valid also!
//-----------------------------------------------------------------------
if (validNeighbours < 1)
{
return false;
}
//-----------------------------------------------------------------------
}
}
}
}
return true;
}
//---------------------------------------------------------------------
我一直在使用以下形状作为我的代码实验:
根据上面的代码和示例形状,我当前的跟踪输出是:
ppnIsland = |0,0|,0,2
ppnAddNewIsland =
ppnAddToExistingIsland = 0,0, 1,0, 1,0, 2,0, 2,0, 3,0, 1,0, 1,1, 1,1, 1,2, 0,2, 1,2, 1,2, 2,2, 2,2, 3,2
看起来,尽管形状是连续的,我试过从你那里解释的代码是找到一个额外的岛,在这种情况下'Col:0,Row:2',甚至在删除块之前?这是对的吗?
如果我尝试删除中间(红色)块,这个代码当然会输出错误,因为'ppnIsland'数组包含&gt; 1岛,但我不认为它检测到正确的输出?
我是否需要使用indexOf命令交叉引用'ppnIsland'和'ppnAddToExistingIsland'数组来检查这两个元素是否属于现有岛?
乔尔
答案 0 :(得分:0)
您可以在处理时将“岛屿”跟踪为单独的列表(在ppnBlockValid中)。所以,例如(上限是选定的图块): 的 强>
a B c d e F g H i J k L m n o p
当您处理第一行时,为B创建一个岛。当您处理第2行时,您会发现B连接到F,因此该岛变为[B,F]。然后,当你遇到没有连接的H时,你有两个岛:[B,F],[H]。在第3行,您的岛屿看起来像[B,F,J],[H,L]。如果选择了K,你会发现J和L已连接,你可以将它们合并到一个岛上。您只需要检查当前行之间的岛屿之间的连接,因此在这种情况下您只需要检查J和L.
如果你最终得到一个岛屿,你就没事了,否则没有。不幸的是,这是一个订单n ** 2搜索,但你的网格很小,所以它可能没有多大意义。
<小时/> 这样的事情(警告:未调试的代码):
private var islands : Array;
public function ppnBlockValid():Boolean {
islands = [];
if (ppnCountSetCells() > 1) {
for (var row=0; row<=3; row++) {
for (var col=0; col<=3; col++) {
if (ppnColumnArray[col][row]) {
var addedToIsland = false;
// Check if we are connected to another set square
// Check North
if (row > 0) {
if (ppnColumnArray[col][row-1]) {
addToExistingIsland([col,row-1],[col,row]);
addedToIsland = true;
}
}
// Check South - not needed since next row will catch this on North
// Check West
if (col > 0) {
if (ppnColumnArray[col-1][row]) {
addToExistingIsland([col-1,row],[col,row]);
addedToIsland = true;
}
}
// Check East - not needed since next col will catch this on West
if (!addedToIsland) { addNewIsland([col,row]); }
}
}
}
}
return (islands.length<=1); // 0 islands is valid also!
}
您只需要实现“addNewIsland”和“addToExistingIsland”。 addNewIsland很简单:只需在islands数组中添加一个新元素即可。您可能希望使用字符串ID而不是数组(例如“01”而不是[0,1]),因为它可以更容易地检查现有元素(例如,您可以使用indexOf在岛中查找图块)。
addToExistingIsland有点棘手:您必须检查其中一个元素是否属于现有岛屿,如果是,则合并这些岛屿。如果没有,新的瓷砖就会附加到岛上。
<小时/> 你不需要维护3个数组,只需要一个岛数组,在ppnBlockValid的末尾,它将是> 1(无效)或更少(有效)。
你不能只填充“ppnAddNewIsland”和“ppnAddToExistingIsland”数组 - 这些应该是函数。如果ppnIslands是一个类变量,那么你的addNewIsland函数可能如下所示:
private function addNewIsland(who) {
ppnIslands.push([who]);
}
...我可能做的唯一优化是将who(作为数组[col,row]传递)转换为字符串,如我所提到的,以便更容易找到某个区域中是否存在一个区块。
然后,你需要一个像:
这样的功能private function addToExistingIsland( existing_island_tile, new_tile ) {
}
此功能必须: