The key point from the previous section is that everything in AI code is essentially a number, and if your AI code uses non-numeric stuff in its commands then the AI engine has to know how to translate them into numbers. This is why the AI engine will give your AI script an "Invalid Identifier" error if you ever make a spelling mistake, because it doesn't know how to translate the word into a number. There are many words and phrases, like "archer" and "any-enemy" that are internally defined in the AI engine, meaning they have been pre-assigned a number by the AI engine that it knows it can translate the words into.
So, does this mean you can only use words and symbols that have been defined internally in the AI engine? No, and that's where defconsts come in. Defconsts are like a way to add a word or phrase to the AI engine's dictionary, though it only applies for your AI script. "defconst" is short for "defined constant." The constant part of the word comes from the programming world, which refers to a constant variable, a variable assigned a name by the programmer whose value remains constant and can never change (yes, "constant variable" is an oxymoron, and don't ask me why programmers called it that). Just like how "archer" always means "4" to the AI engine, any defconsts you make will always be translated into the same value by the AI engine. Once you have created a defconst, you can use the name of that defconst anywhere you like later on in the script.
Time for an example. In conjunction with our earlier example, we could create a defconst like this to specify the number of enemy archers that our AI will consider a threat: (defconst ARCHER-THREAT-AMOUNT 5). Defconsts are always defined outside of rules, preferably at the start of your AI. The syntax starts in parentheses with the word "defconst," followed by the name you want to call the defconst (the uppercase name is just an optional programming convention), followed by the value you want the AI script to translate the name into when the script is compiled. So, this defconst tells the AI compiler to always translate every instance of "ARCHER-THREAT-AMOUNT" in the AI script to the value 5 when the script is compiled. This means that (players-unit-type-count any-enemy archer < 5) and (players-unit-type-count any-enemy archer < ARCHER-THREAT-AMOUNT) are treated identically by the AI engine.
You can even do something nonsensical like this following example, but the AI engine will still treat it as valid: (players-unit-type-count ARCHER-THREAT-AMOUNT archer < ARCHER-THREAT-AMOUNT). Since the players-unit-type-count command expects the first parameter to be a player number, the command will treat the first instance of ARCHER-THREAT-AMOUNT in the command as the player number 5. So, this command will check if player 5 has less than five archers. The AI engine doesn't "know" that you want to use ARCHER-THREAT-AMOUNT as a value that represents the number of enemy archers that constitute a threat, it just knows that ARCHER-THREAT-AMOUNT == 5, so it will just blindly convert the defconst to 5 wherever it sees it used.
One advantage of using a defconst is that if you use (players-unit-type-count any-enemy archer < ARCHER-THREAT-AMOUNT) in several locations in your AI, but you want to increase the number of archers your AI considers to be a threat from 5 to 7, all you have to do is update your defconst command to (defconst ARCHER-THREAT-AMOUNT 7). If you had instead used (players-unit-type-count any-enemy archer < 5) without the defconst, you'd have to update each instance of this command in your script (and who knows, you might even forget about one of the places you used the command and fail to update it, and now your AI's code is inconsistent).
So, defconsts have two main uses. First, it can make your AI code easier to update and modify. Second, it can also make your AI more readable. This readability aspect is the main reason why defconsts are often used with goals, and we'll get into goals next.