How do I optimize checking adjacency within a matrix (including diagonals)? [Gamemaker Studio]

How I was checking adjacency before:


if (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y-1)
|| obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y+1)
|| obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x-1)
|| obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x+1))
{
//do stuff
}


The Problem with that:

This only checks if the object's matrix location is within an adjacent row or column, not simply if it's directly adjacent to the object. Thus, it doesn't need to actually be adjacent to the last_link. That's a problem.

The Long solution:

I could individually check for each and every individual square adjacent to the object clicked on. However, this is rather inefficient (taking a minimum of 2 checks, and up to 8, if I don't include diagonals), at least if I use matrix location x/y. And if I include diagonals, that doubles the number of checks again, and makes the if statement really long.

The Question:

How do I efficiently and with as little code as possible, and make is as easily understandable as possible? Comments are obvious inclusions for that last bit, but aside from that.

Graphical Example of how the map looks

format: x,y


0,0  1,0  2,0  3,0
0,1  1,1  2,1  3,1
0,2  1,2  2,2  3,2
0,3  1,3  2,3  3,3


Below is the requested, relevant code

obj_Handle_Links create event


Match_Length = 0;

Link_Stack = ds_stack_create();


obj_Board_Generator create event


//hardcoded height and width. could change later
Large_Width = 6
Large_Height = 6

var i = Large_Width-1
var j = Large_Height-1

repeat(Large_Width)
{
repeat(Large_Height)
{
//initialize the board by generating the objects
//later, need to randomize.
BoardGems[i, j]  = instance_create((i-1)*36, (j-1)*36, obj_Parent)
BoardGems[i, j].Matrix_Location_x = i
BoardGems[i, j].Matrix_Location_y = j
j -= 1;
}
j = Large_Height-1;
i -= 1;
}



obj_Parent Create event


image_speed = 0
Linked = false
Type = "Parent"

//Matrix_Location_y = 0
//Matrix_Location_x = 0


obj_Parent left click event


if (obj_Handle_Links.Match_Length = 0) //if this would be the first in the link
{
show_message("first to link");
obj_Handle_Links.Match_Length +=1; //because we're increasing the length
image_index = 1; //this should highlight
Linked = true;
ds_stack_push(obj_Handle_Links.Link_Stack, id) //adds the instance to the stack
obj_Handle_Links.Last_Link = id; //makes it so this is what's seen as last link
}
else
{
// show_message("first else");
//check if the target is the same type as the last Link's type
if(obj_Handle_Links.Last_Link.Type = Type &&
//check if it's already been linked
(Linked = false) &&
//check if the last link in the chain is adjacent to the target link
//includes diagonals
((obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y-1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x)) //checks up
|| (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y-1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x-1)) //checks up, left
|| (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y-1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x+1)) //checks up, right
|| (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y+1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x)) //checks down
|| (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y+1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x-1)) //checks down, left
|| (obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y+1) && obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x+1)) //checks down, right
|| (obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x-1) && obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y)) //checks left
|| (obj_Handle_Links.Last_Link.Matrix_Location_x = (Matrix_Location_x+1) && obj_Handle_Links.Last_Link.Matrix_Location_y = (Matrix_Location_y)) //checks right
) //parenthesis to enclose the adjacency check
) //parenthesis closes conditional statement
{
show_message("did link");
obj_Handle_Links.Match_Length +=1; //because we're increasing the length
image_index = 1; //this should highlight
Linked = true;
ds_stack_push(obj_Handle_Links.Link_Stack, id) //adds the instance to the stack
obj_Handle_Links.Last_Link = id; //makes it so this is what's seen as last link
}
else{

show_message("didn't link");
//play sound that link failed
}
}

• If the code above is related to an if statement, please add such along with brackets and a placeholder comment to better locate its role. E.G. if (cond) { //DoStuff }. Jun 15, 2016 at 9:15
• OK. Thanks. Done. Of course, it's just a condition. It works in anything that uses a condition. Jun 15, 2016 at 11:26

2 Answers

You can construct an efficient test of whether a point lies within an axis-aligned rectangle with well-understood algorithms. Try this answer.

• I think that'd work. Once I confirm that I got it to work for me, I'll mark this as my answer. Jun 16, 2016 at 4:48

You can find many articles and repos online related to this topic. User dgkanatsios on GitHub created his MatchThreeGame and included an article on his site in which he explains how to make such a game in Unity step by step. As well, did rembound with his Match-3-Game-HTML5 which was developed in JavaScript and run in a browser.

Although you're working with GM:Studio, you can still read their guide and extrapolate the algorithms they use to accomplish the various tasks to make their respective games work. The earlier article also shows a DFA state chart representing the main operations performed by the game loop routine while the game is running.

Anyway, we can't help you as much as we could, until you show us some more code or fully explain how your current algorithm works, what's the data structure you're using to deal with the game status, and so on.

• OK. I'll add more details on the code. I just generally don't get responses unless I streamline the questions. Jun 15, 2016 at 12:38