Wednesday, July 16, 2025

Where Again is Arkansas? A Geography Location Game, Part 2: Determining Which State the Player Has Clicked

 

I ended my previous post having developed a mileage matrix of distances between states. In this post, I focus on how to integrate that mileage matrix into the game. When the player clicks on the wrong state, the distance in miles between the center point of both states will be used as a type of accuracy score. For example, it is one thing to confuse Georgia and Alabama, given that they share a border, but quite another to confuse Georgia with Oregon. This would clearly show that the player really has no clue where Georgia is located. 

In order to use mileage matrix, I obviously had to know which two states were being compared. Although I already know the target state given that it was chosen at random by the computer, I needed a way to figure out which state the player clicked on. How to do this was not immediately clear to me. I mentioned in my previous post about I could have created individual images for each of the lower 48 states, which would have allowed me to use LiveCode's intersect function. Although I may revert to that strategy at some point, I wanted to find another way based on the general x and y coordinates of each state. After trying one approach that was good, but not great, it occurred to me to compare of the sum of the distances on the x and y axes between the clicked location and the pair of coordinates for each state. The state that had the lowest sum would be the state clicked on by the player.

I created a new card to test out the approach. Here's a screen shot:


So, why use the sum of the x and y coordinates. Notice how some of the states line up nicely on the vertical axis (e.g., North Dakota, South Dakota, Nebraska, Kansas, Oklahoma, and Texas) and others line up on the horizontal axis (e.g., Tennessee and North Carolina). By summing up the x and y coordinates of the player's click, then comparing this to the absolute distance between all of the states, the state with the lowest difference has the highest probability of being the correct state. Error only creeps in when the player clicks on a spot that is far from the state's middle. The error is less when the state is relatively symmetrical, like Colorado, and more when the state has a non-symmetrical shape, such as Louisiana, Florida, or Michigan (geez, what a weird geography for a state having an upper and lower peninsula configuration). Similarly, the error rate is higher for the smallest states, like Rhode Island and Connecticut. 

Here's the code for the button "What state am I clicking" that does the work:

1:  on mouseup  
2:      
3:    wait until the mouseclick  
4:    put the location of image "USA with labels.png" into varLocationUSA  
5:    put the mouseloc into field "clicked spot"  
6:    put (item 1 of the mouseloc - item 1 of varLocationUSA) into varStateLocationx  
7:    put (item 2 of the mouseloc - item 2 of varLocationUSA) into varStateLocationy  
8:      
9:    //Compute the absolute x and y distance from the mouse click and each of the lower 48 states  
10:    put the number of lines in field "coordinates" into L  
11:    put empty into field "state xy differences"  
12:    repeat with i = 1 to L  
13:     put item 1 of line i of field "coordinates" into varX  
14:     put item 2 of line i of field "coordinates" into varY  
15:     put abs(varStateLocationx - varX) into varTemp1  
16:     put abs(varStateLocationy - varY) into varTemp2  
17:     put item 3 of line i of field "coordinates" into varTemp3  
18:     put varTemp1&comma&varTemp2&comma&varTemp3 into varTemp4  
19:     put varTemp4 after field "state xy differences"  
20:     put return after field "state xy differences"  
21:     sort field "state xy differences" ascending numeric by first item of each  
22:    end repeat  
23:      
24:    //Compare the sum of the absolute values of the x and y and use lowest value to determine the state  
25:    put empty into field "xy sum"  
26:    put the number of lines in field "state xy differences" into L  
27:    repeat with i = 1 to L  
28:     put item 1 of line i of field "state xy differences" into varX  
29:     put item 2 of line i of field "state xy differences" into varY  
30:     put varX + varY into varZ  
31:     put varz&comma&item 3 of line i of field "state xy differences"&return after field "xy sum"  
32:    end repeat  
33:    sort field "xy sum" ascending numeric by item 1 of each  
34:    put item 2 of line 1 of field "xy sum" into varYouFoundTheState  
35:    put varYouFoundTheState into field "target state"  
36:    
37:  end mouseup  

Lines 4-7 note the location of the USA map and then record the x and y of the player's click relative to the USA map's center. (This was explained more fully in my previous post.) The x and y location of the player's click are stored in the variables varStateLocationx and varStateLocationy.

Lines 9-22 compare the x and y location of the player's click to each of the 48 states. Since we are interested in the raw distance between the two points, lines 15 and 16 compute the absolute value of this distance. The results of these comparisons are neatly put into the field "state xy differences." Lines 24-35 take the data in the field "state xy differences" and sums the first two items in line 30, which are the x and y distances from the player's click to each of the states. The results of this simple arithmetic is put into another field - "xy sum" (line 31) - which is then sorted from low to high (line 33). The "winning" state is therefore the one that is found at the top of this field. Line 34 puts the name of this state into the field "target state," thus revealing the identity of the clicked state on the screen.

The reason why I need to sum both the absolute values of x and y is clearly shown if I click on Oklahoma, but a little left of center (just left of the "OK"). This is exactly where I clicked when I captured the screen shot above. The x coordinate of this click could be identifying a bunch of states. In fact, Oklahoma is the sixth state in the list. The margin of error is just too great when using just the x axis. However, when you add the x and y coordinates together, Oklahoma is the clear winner with a sum of 24. Kansas comes in second with a sum of 71, which is not even close.

As always, I use fields to place all of these values so that I can see what is going on with the algorithm even though I know doing so dramatically slows down the processing speed. When I go to integrate this approach into the game's engine, I'll convert the fields into variables just by changing the names. For example, I'll change field "state xy differences" to something like variable "varStateXYDifferences."

Saturday, July 12, 2025

Where Again is Arkansas? A Geography Location Game, Part 1: Initial Design and Build

In the building where I work at the University of Georgia, there is a fairly large map of Georgia hung on a wall in one of the hallways. I often find myself standing and staring in front of it. I do love maps and this one, with an edition date of 1967, is particularly well designed. It seems to strike the right balance of visual appeal and information. It shows all of the counties, cities, and even small communities not commonly found on your mobile phone's map app. I'm particularly fond of checking out all of the 159 counties. Only Texas has more counties than Georgia with 254. Some counties have some amusing names, such as the side-by-side counties of Bacon and Coffee (named after people, not the breakfast items). Some, if not outright controversial, at least raise an eyebrow or two to non-Georgians, such as Jeff Davis county, named after Jefferson Davis, the president of the confederacy during the American Civil War. Of course, quite a few Georgia counties are named after confederate leaders, but naming one after the confederate president seems a bit brash. But, the county was created in 1905 and the era of the Jim Crow south and the narrative of the South's "lost cause" (aka War for Southern Independence or War of Northern Aggression) was in full force. I originally thought the county was named after Davis because he was captured in Georgia after his and his cabinet's escape in 1865 from Richmond, Virginia, but apparently he never touched foot on the land that now occupies the county. (Davis was captured in Irwinville, Georgia.) Anyhow, it is an excellent map and I always enjoy studying it while taking a short break.

I sometimes wonder how well I would do if I were given a quiz on the location of each county. I can generally locate the general region of many of the counties - southwest, far east half way down, etc. - but I know I would fail miserably if 100% accuracy was required. The thought occurred to me that it would be interesting to design a simple game to teach the identification of the counties, but using general, not pinpoint accuracy as the score. And so this project was born.

Rather than focus on the counties of Georgia, I instead settled on USA's 48 contiguous states given that 48 is far fewer than 159 and I suspect learning the location of the "lower 48" would appeal to more people. My apologies to the citizens of the great states of Alaska and Hawaii, but no one seems to have a hard time finding them on a map of the USA, though unfortunately they are usually shown cut away from their natural geography and placed in the general area of northern Mexico. Talk about confusing 4th graders!

The Goal of the Game and How to Measure Success

The goal of the game is simply to locate a given state on a map. Besides being either right or wrong, the game tells you how far off you are in miles if you are wrong as measured from the center point of each state (more about that calculation later). It is this measure of how far off your guess is that I consider to be the most important measure of learning. I've even designed the game so that it chooses just a handful of states (5 is the default for now) for you to locate and the game only ends when you finally identify the location of each. If you are wrong, your score increases by the error mileage plus that state is put back into the queue for you to try again a little later. I keep track of the total number of tries as another measure of success. But, I would consider a low error mileage score with a high number of tries to be evidence of more learning than a high mileage score and a lower number of tries. The reason is that you are demonstrating good awareness of the nation's regions which I take is akin to good estimation skills. For example, knowing that Vermont is somewhere in the New England area and not out west somewhere is what the game is emphasizing.

Creating Helper Apps

Before I could work on the game itself, I needed to build the various elements the game would need to work. Here is a screen shot of a card in my stack that uses several helper apps for these tasks:

Of course, in the final version I will need to delete each state's abbreviation from the map. To create the game, I obviously needed to identify where each state was located on a map. How to do this? One way would be to create individual maps of each state and arrange them jigsaw puzzle-like to form the 48 as a whole. LiveCode has a very useful message handler - MouseWithin - that can detect if the mouse is currently located within the rectangular boundaries of an object. There are also ways to detect collisions between objects on the screen using the intersect function. However, I didn't want to have to create or find 48 separate images of states. I may come back to one of these options later if I'm motivated to refine the game, but for now I'm using a different strategy. I created a helper app to log the screen locations of the approximate center point of each state on a single USA map. 

Thinking Ahead - What If I Need to Move the USA Map to a Different Location on the Screen

Yes, it occurred to me right at the start of the possibility that I would need to move the state map to a different location on the card. I almost never finalize the screen design until the very end of the project. So, logging the screen locations of each state would have to be redone if I moved the USA map. In anticipation of this, I used the center point of the image of the USA map as a calibration point. That is, when I logged the location of each state, I offset the raw screen location by the x and y coordinates of the map's center point. That way, I can move the map to any location on the screen later to line up each state's location perfectly. Here's the code for a button that does the logging:

1:  on mouseup  
2:    wait until the mouseclick  
3:    put the location of image "USA with labels.png" into varLocationUSA  
4:    put (item 1 of the mouseloc - item 1 of varLocationUSA)&comma after field "coordinates"  
5:    put (item 2 of the mouseloc - item 2 of varLocationUSA)&comma after field "coordinates"  
6:  end mouseup   

The image of the USA is titled "USA with labels.png." I put its current location (i.e., the x and y coordinates of its center) in the variable varLocationUSA. I then click on any state and the x and y screen locations of that state are logged by the mouseloc function. I then subtract the x and y coordinates of the map's center point. The resulting x and y of each state is then displayed in the field "coordinates." I then manually typed in the name of the state at the end. The result is a list of the state's coordinates aligned to the map's center point.

Did I Miss Any States?

I obviously had to do this logging of screen coordinates 48 times. In order to make sure I wasn't skipping any states along the way, I created another helper app that compared the names of states I had logged with a list of all 48 states. It then showed me the names of the missing states. Here is the code:

1:  on mouseup  
2:    put empty into the field "missing states"  
3:    put the number of lines in field "all states" into L  
4:    put the number of lines in field "coordinates" into M  
5:      
6:    repeat with i = 1 to L  
7:     put line i of field "all states" into varTarget  
8:     put false into varFoundState  
9:       
10:     repeat with j = 1 to M  
11:       put item 3 of line j of field "coordinates" into varStatesDone  
12:       if varStatesDone = varTarget then  
13:        put true into varFoundState  
14:        exit repeat  
15:       end if  
16:     end repeat  
17:     if varFoundState is true then  
18:       next repeat  
19:     end if  
20:     put line i of field "all states"&return after field "missing states"  
21:    end repeat  
22:      
23:  end mouseup  

Besides the field "coordinates" already mentioned above, the field "all states" has just that, a list of all 48 states. The code compares each line in the field "all states" to the list of states already logged (item 3) in the field "coordinates" (the first two items are the coordinates). I set the variable varStateFound to false by default. If a match is found, varFoundState is set to true, which then triggers a new search with the next item in the field "all states." If no matches are found, varFoundState remains false and that state from the field "all states" is added to the field "missing states." This allowed me to plow through all of the states one-by-one as if I was on some magical car ride, checking now and then to see which states I've missed along the way.

Calculating the Distance Between Any Two States

The task of accurately calculating the distance between any two states is not easy, but it is straightforward. A good approach is to compile the GPS coordinates of the geographic center of each state, then create a distance matrix showing the distance between each state. I also learned about the Haversine formula, which takes into account the curvature of the earth. I decided this was a task perfectly suited for artificial intelligence, so I asked ChatGPT to create such a matrix. It did so, but in kilometers. Of course, despite the rest of the world, we in the USA compute these sorts of distances in miles. So, I asked ChatGPT to do it again, but in miles, and it did so without complaint. (Yes, when it comes to converting to the metric system, the USA is "miles and miles" behind the rest of the world. For some reason, we are fine measuring most soft drinks and wine in liters.) 

I will need to figure out how to efficiently integrate this matrix in my game, but that is a task for the next version of the game.

Appendix

Here are three prompts I used in my conversation with ChatGPT to create the matrix of distances between the states (the first matrix it created was in kilometers):

Calculate a matrix containing the distance between the geographic center coordinates of all of the 48 continental united states using the Haversine formula.

Create a version of this matrix for exporting into Excel.

Create a new version of the matrix in miles that can export to Excel.

Next, I asked ChatGPT for some help with the coding:

Me: How do I import an excel spreadsheet into livecode.

ChatGPT

answer file "Choose a CSV file:" 
if it is empty then exit to top
put it into tFilePath
put URL ("file:" & tFilePath) into tCSVData

Me: Show me an example of how I can find the value of a particular cell in the variable tCSVData and put that value into a variable.

ChatGPT: 

put tCSVData into tData
put line 3 of tData into tLine
put item 2 of tLine into tCellValue
answer "The value in row 3, column 2 is:" && tCellValue

I then put all of this mileage data into a field on a separate card "mileage matrix" (I always prefer fields to variables in the development of a project because it allows me to actually see the data). I then added code that would read the state name from the first item in each identified row and the name of the state in the identified column, then put this information in the field "distance between states". This allowed me to verify that everything was working properly. Below is the code. I'll adapt and integrate this code into the next version of the game.

on mouseup

   put field "mileage matrix" on card "mileage matrix" into varCSV
   put field "dRow" into varRow
   put field "dColumn" into varColumn
   put line varRow of varCSV into tLine //row
   put item varColumn of tLine into tCellValue //column
   put item 1 of line varRow of varCSV into varState1
   put item varColumn of line 1 of varCSV into varState2
   put "The value in row "&varRow&", column "&varColumn&" is:" && tCellValue into line 1 of field
      "distance between states"
   put "This is the distance between these states: "&varState1&" and "&varState2 into line 2 of field
      "distance between states"

end mouseup

Final Note: There is a new version of LiveCode that is AI-enhanced. I don't yet have access to this version of the application.