BF Joust strategies

BF Joust is more involved than its simple rules might suggest. This page details some of the major strategies which are used, and gives a short example for each.
== Attack ==
=== Rush ===
Rush-based programs focus entirely on attack, though they may use any attack strategy. They tend to be further divided into "slow rushes" that set large decoys, and "fast rushes" which try instead to reach the opponent before they can set up their own decoys.
=== The rule of nine ===
There is no purpose in attacking the first 9 cells, since the enemy's flag will never occupy one of them. For this reason, it is common to start fast rush programs with code similar to
 (>)*9
Slow rush programs will instead generally set up decoys and then move to the tenth cell of the tape and start attacking from there, in the hope of avoiding decoys that were set in the range of cells that cannot possibly contain the flag.
Many programs want to skip the first nine cells this way, and then do something (such as a clear) on each of the potential remaining 21 cells. In such cases, the simplest code puts 8 of the > commands into an initial repeat, and then the ninth inside a loop, in order to give nine > instructions but not run off the end of a length-30 tape if the "something" fails:
 (>)*8(>do something)*21
The only reason a rush program might want to not start at the tenth cell is if it's specifically trying to detect decoys, as in tripwire avoidance; even though the enemy flag cannot be in the first 9 cells, enemy decoys can be, and this can sometimes produce useful information.
Exploiting the fact that an opponent uses this tactic is difficult or impossible; in theory it can give away information about the tape length, but it's too easily confused by decoys and similar tactics.
=== Clear ===
The most obvious strategy is to look for any set cells and zero them as in Brainfuck.
 [-]
The canonical example of this strategy is
 (>)*9([-]>)*21
This is known as a "two-cycle clear", and is fast and common, but can often be exploited by defence programs. A slower "three-cycle clear" looks like this:
 [-.]
(or alternatively with the - and . reversed). Three-cycle clears are less generally exploitable by defence programs; sometimes programs use five-cycle clears to make absolutely sure. (Four-cycle clears are not useful as they are generally locked by the same code that locks two-cycle clears.)
The vast majority of programs use some kind of clear. A simple non-offset clear such as this one, though, is very vulnerable to decoys; a decoy with one polarity (positive or negative depending on whether the clear is based on [-] or [+]) will have almost no effect, but a decoy with the other polarity will cause the clear to take much longer, as it has to cycle through all the possible values until it reaches 0 from the other direction. Another method of exploiting an enemy clear is to lock it; this requires knowing or guessing the cycle length of the clear, and thus two-cycle clears, being the most common, are also the most vulnerable to this.
=== Offset clear ===
It is common to set values in several cells as decoys. The values of these decoys are usually very close to zero, often 255 (-1) or 1. As such, using a clear such as
 [-]
will result in the maximum cycles spent looping to clear a cell. This can be offset by first adding an expected decoy value.
 (+)*9[-]
The canonical example of an offset clear program (with offset 9) is
 (>)*9([(+)*9[-]]>)*21
Offset clears are less prone to decoys than regular clears, but can still be defeated by decoys larger than the offset. They are slower on average than typical clears, too, and almost as vulnerable to locking (unless the offset is large enough to throw off the timing of the lock). Additionally, offset clears have a distinctive pattern of zeroing on a small tripwire of the right polarity (first zeroing for one cycle, and then later zeroing for two cycles), meaning that a carefully placed tripwire can detect the presence, polarity, and offset of an offset clear, making locking it very easy unless it varies from one tape position to the next.
=== Wiggle clear ===
A further extension of the offset clear concept is to have nested loops in opposite directions, to catch small values quickly. For instance, the clearing algorithm
 ([-{ ([+{ [-] }])%8 }])%4
will finish quickly with values from -4 to 4. The inner clear algorithm can be anything, including a larger offset clear. Combining wiggle clear with offset clear yields the canonical program
 (>)*9 ( ([-{ ([+{ (+)*9[-] }])%8 }])%4 >)*21
One downside of the canonical wiggle clear is the part where it closes a lot of brackets in a row before moving on to the next cell. This renders it vulnerable to triplocks, which begin rebuilding a just-cleared decoy by the time the third closing bracket is reached, preventing the algorithm from ever being able to leave the triplocked cell. The most straightforward way to avoid this is to add an extra clear before every closing bracket in this row. A canonical offset wiggle clear algorithm with triplock avoidance might look like:
 (+)*4 ([-{ [(-)*15 [+]] }[-]])%8
Note that this algorithm will be stuck clearing the triplocked cell of a good triplocker for nine consecutive triplock phases, and this may be enough for the triplocker to win on short tapes. However, it typically takes more than 9 triplock phases to full clear a long tape, at which point this clear algorithm will finish and the program using it will move on the next cell. If the triplocker uses the tripwire method to wait for its opponent to clear its triplock, it will sit waiting forever while the program using this clear moves on to take out its flag.
Here is a direct incorporation of the above clear algorithm into an otherwise simple program defeating a sophisticated triplocker on all tape lengths and polarities:
=== Careless clear ===
The careless clear, also known as the turtle strategy, is a fast way of clearing cells which are equal to the value 128, the initial flag value. Rather than looping, the attacker simply adds or subtracts 128 from the cell, then waits one cycle in case the flag is zero. This saves one cycle per iteration (since there are no true iterations), but is expensive on small values.
 (-)*128.
This of course will only have the desired result if the flag is not changed by the opponent. The canonical example of this careless clear is
 (>)*9([(-)*128.>]>)*21
The careless clear can also be combined with the concept of the offset clear to support some range of values by waiting after a sequence of modifications rather than only the last one. For instance, to support values from 112 to 144:
 (-)*112(-.)*32
Although very fast against large decoys, careless clears can typically be tricked off the end of the tape simply by changing the value of your own flag (although the amount often has to be quite large); for much the same reason, they tend to be defeated by shudder-based programs, and often also by vibration-based programs. Setting a lot of decoys helps as well, as small and moderate-sized decoys can be set much faster than the careless clear can clear them.
=== Reverse offset clear ===
When you suspect you're on an opposing flag, but fear the opponent might have used anti-careless-clear tactics, it is possible to use an offset clear centered about 128, rather than 0; instead of a small offset then clearing in the opposite direction to the offset, it uses an offset just below 128 followed by a clear in the same direction. The following program does this, after first checking for decoys of size 1:
 >+>-(>)*6(>[-[++[(+)*120[+]]]])*21
The advantage of this over a careless clear that checks a range of values is that it's guaranteed to clear an undefended cell eventually even if it's been set to a very unusual value for a flag, rather than running off the tape like a careless clear would; and the advantage over a regular offset clear is that for flags near 128, it's almost twice as fast. The disadvantage is that if the cell isn't actually a flag, it can take much longer than a typical offset clear would, leaving it vulnerable to being outraced. It's thus mostly useful only if you have a good idea that the current cell is a flag.
=== Anti-shudder clear ===
Due to the danger of stepping beyond the opponent's flag and losing when the opponent changes their own flag to zero and back again, it is now necessary to make sure to close at least two brackets before moving to the next cell. Generally speaking, this consists of a simple clear like a two-cycle clear, followed by a clear with a much large cycle length in order to beat defenders and shudderers. This following example does this, with a two-cycle offset clear followed by an eleven-cycle clear, and in addition ensures that the canonical shudder program will die in as few cycles as possible:
 (>)*8(>[(+)*9[-].[.++-------]])*21
Such clears are only slightly slower than typical clears (and likewise, an offset anti-shudder clear is comparable and slightly slower than a straight offset clear), and are hard to take advantage of via defensive programs. Lock-based programs can sometimes lock such clears on their first, simple clear, though, although generally only if they know their polarity (the lock will break eventually otherwise, but can sometimes take a very long time to do so, sometimes long enough for the lock-based program to clear three or four tape cells even via the slow full-tape clear method).
More recently, locks have been developed specifically to lock anti-shudder clears in their second, slower loop, generally via the use of a variation on a probabilistic lock or triplock (which can often work on an anti-shudder clear even if it only has two closing brackets because the triplocker will often notice the cell zeroing before the anti-shudder loop does), so some programs use modified anti-shudder clears that assume they are being locked if they see the cell become zero suspiciously many times (meaning that the probability of the current cell being a shuddered flag is low) and move onwards. The simplest implementation of this just places a > after the slow clear loop, meaning that the program will move on after zeroing the cell once with the fast clear and once with the slow clear, but more complicated versions exist.
=== Timer clear ===
One interesting way to evade locks is to simply stop clearing after a while and move onto a different strategy; this allows fast two-cycle clears to be used to defeat rush programs, whilst still not being trivially locked by defence-based programs. Here's a simple example, showing a program that changes clear direction and period after 500 clear attempts, and running it against a trivial lock-based program that tries to lock the sort of clear that the program starts with into an infinite loop and a draw (in practice, lock-based programs would probably be trying to win, but the same principle applies):
 (>)*8(>([-{[+.]}>])%500)*21
The major issue with timer clears is their inflexibility; although it is relatively easy to make an offset and/or anti-shudder timer clear, most other modifications are difficult or impossible. (For instance, they cannot check to see if a cell is 0 before offsetting it, like most offset clear algorithms do.)
=== Flexible timer clear ===
The inflexibility of timer clears can be effectively worked around simply by embedding multiple timer clears inside each other, putting each inside timer clear just after the > of the one immediately afterwards. This allows each of the individual clears to be on a separate timer; it also allows pretty much arbitrary modifications to the clear algorithm, which can even be different for differently positioned decoys. Here's an example using offset clears with multiple different offsets:
 (>)*8(>(+)*24([-{[+.]}>(+)*23
 ([-{[+.]}>(+)*22
 ([-{[+.]}>(+)*21
 ([-{[+.]}>(+)*20
(etc...)
 )%500])%500])%500])%500)*-1
It works as a drop-in replacement for standard sorts of clear, as it works identically before the timer expires; the main disadvantage is its length, which can make it hard to fit into more control-heavy programs. Unlike regular timer clears, it cannot reasonably be nested, and so can be locked if the defending program finds a lock pattern that works on both the inside and the outside clear loops.
=== Full-tape clear ===
If the opponent does not do anything, it is possible to definitively clear the opposing flag in constant time by setting every element on the tape to each of its 256 possible values and waiting a turn. Naive code to do that looks something like this:
 (>)*8(>(+.)*255)*21
Such an approach is both incredibly slow and prone to locking, and thus rarely if ever seen in successful rush programs. However, its fixed-cycle and easily interruptible nature makes it incredibly valuable in programs that use locks themselves; if the opponent is successfully locked, a defensive program can alternate between maintaining the lock and continuing its full-tape clear. As such, this is considered a very defensive form of attack, generally used only by defense programs to finish off their opponent.
To beat a full-tape clear, all that is necessary is to be able to act freely, rather than stuck in a lock; almost any aggressive technique will outrace it, and many defensive techniques will beat it too, although often with a tape length dependency.
=== Poke ===
A slow rusher can usually win by having more decoys than its opponent, and there are two ways to do that: by making your opponent have fewer decoys, and by building yourself more decoys. Poking is a strategy that makes both of these things possible. The idea is to find out where your opponent is before building any of your own decoys, and then adjusting your decoy line forward so as to make room for more of your own decoys, and also possibly to identify a safe location behind your opponent's decoys, depending on how they build them. Here is an example:
 (>)*8(>[(<)*8(-)*33(>)*8([-[++[(+)*9[-]]]]>)*21])*21
Pokes can be made less effective by racing to a point far from the flag early on in order to set a decoy there, in order to cause them to think the tape is shorter than it is; this is rarely fatal to the opposing program, but will often slow it down. Additionally, rushing forwards quickly gives a chance to get behind the opponent's decoys before they are set up, making the enemy flag very easy to find. Thus, poke-based programs normally need a separate countermeasure against fast rush programs.
Poke can be combined with the wiggle clear to produce a deep poke. This strategy was first used in Gregor_furry_furry_strapon_pegging_girls, see its behavior against Deewiant_pendolino for a good example: 
=== Tripwire avoidance ===
Any program that assumes the first nonzero cell it sees is probably a decoy and keeps searching. Here is an example:
 (>)*8(>[(>[(+)*9[-]]>)*21])*21
Note that it will suicide against any opponent that doesn't make decoys. Or, that doesn't make them fast enough for it to see them. (Tripwire avoiders will sometimes wait deliberately, and change the Rule of Nine to a Rule of Seven or whatever, in order to make sure that if the opponent makes decoys, it spots them. However, this removes some of their speed advantage.)
Tripwire avoidance can be defeated by setting up no decoys, but this is often a bad idea due to the huge disadvantage it gives against other sorts of programs. Alternatively, setting up an extra small decoy is often all that is needed to neutralize the tactic.
An effective way to avoid tripwires but not necessarily lose to fast rushers, is to check for decoys once per two cells. This will only lose to no decoys half the time, while still being fairly good at tripwire avoidance. Here's a simple program that does this:
 >>+>>>>>(>>[(-)*7[+]++>])*-1
The obvious countermeasure against such programs is to only set decoys an even distance from your flag.
=== Reverse tripwire avoidance ===
For small reverse tripwires, it is possible to avoid triggering them by restoring them to their original value before moving away from them, such as the following example that restores all size 1 decoys: (Warning: untested)
 (>)*8((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]_>((>[-[{(++[(+)*9[-]]_>
 ((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->
 ((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->
 ((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->
 ((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->((>[-[{(++[(+)*9[-]]->
 ((>[-[{(++[(+)*9[-]]->[-]{}])}]]+)%1)*2{}])}]]+)%2)*2{}])}]]+)%3)*3{}])}]]+)%4)*4
 {}])}]]+)%5)*5{}])}]]+)%6)*6{}])}]]+)%7)*7{}])}]]+)%8)*8{}])}]]+)%9)*9{}])}]]+)%10)*10{}])}]]+)%11)*11
 {}])}]]+)%12)*12{}])}]]+)%13)*13{}])}]]+)%14)*14{}])}]]+)%15)*15{}])}]]+)%16)*16{}])}]]+)%17)*17
 {}])}]]+)%18)*18{}])}]]+)%19)*19{}])}]]+)%20)*20{}])}]]+)%21)*21
As you can see, it is not very compact or flexible. Futhermore, this only works if the program using them does not check them constantly, as in this case, it would check them before you had a chance to restore them. However, the primary benefit of reverse tripwires is their ability to allow a program to go do other things before determining if the tripwire has been tripped, so most programs that use them will not check them immediately. However, in the age of larger reverse tripwires, it may become prohibitively expensive to restore their value.
In the case of programs that use small reverse tripwires and check them incessantly, just checking several times in a row if a cell is nonzero before attempting to modify it can avoid them in many timings/tape lengths (at the cost of slowing down your decoy clear by a few cycles):
 (>)*8(>[[[[+[--[(+)*9[-]]++]-]]]])*21
=== Reverse decoy avoidance ===
If you assume that the opponent uses a reverse decoy setup, you can look for a nonzero cell, assume it's the first of a series of reverse decoys, then keep moving until you find an empty cell, then move again until you find a nonempty cell, asssume it's a flag, and clear it (e.g. with a reverse offset clear, wiggled to avoid small decoys, as shown in the example below):
 >>>>(>[[>]((>++++[-[-[-[-[-[-[-[-[(-)*120[-]{}]]]]]]]]])%29)*-1])*-1
As written, the strategy is trivially defeated by a trail or forward decoy setup, making it a very fast risky rushing strategy. (Some protection against trails can be added either by looking for small values on cells, which has problems of its own, or more plausibly deciding that a reverse decoy setup is probably not in use after seeing a suspiciously large number of decoys.) It also tends to be quite sensitive to the details of the opposing programs (the details of decoy setups tend to vary wildly).
=== Interrupted rush ===
On short tape lengths, rushers benefit from rushing as quickly as possible to prevent the enemy taking a lot of time to build more and larger decoys, or at least to tear through their decoys nearly as fast as they can be built. However, since decoy building is always faster than decoy clearing, on longer tapes it benefits one to slow down the opponent by having a lot of decoys. Thus, a very effective strategy is to rush for a while, then go back and build more decoys when you believe your initial set of decoys has almost been destroyed, then go back and rush some more. Examine Deewiant_pendolino in the Major Programs section for an example of this strategy. One might also wish to interrupt a rush to do other things, like switch to a defense strategy, or repair your own flag a little bit. These sorts of ideas are advanced strategies that have not yet been thoroughly explored.
== Defense ==
Primarily defensive programs that aim to win via flag fall generally have to be quite complex in order to be able to attack while defending, and as such the examples used here are generally ineffectual on their own and sometimes not very short. They are presented simply to give the gist of a particular strategy, without being a good program in and of themselves. Defensive tactics can sometimes also be useful even for rush programs, in order to buy more time for their rush.
=== Decoy ===
The most fundamental defensive strategy is the decoy. Since it is impossible for an attacker to distinguish the flag from any other non-zero cell, filling a section of the tape with various non-zero values can slow down or even foil an attack. It is important to use both positive and negative decoys, so that your decoys slow down your opponent equally in either polarity.
 (>+>-)*4
Decoys can be further split into "small decoys" that are less than the range of a typical offset clear (or in the case of a wiggle clear, the offset of the wiggle) and serve only to trick the opposing program into thinking that something is there (in order to defeat tripwire-avoiders, confuse pokes, etc.); and "large decoys" that are designed to be large enough to force even offset clears with the wrong polarity to clear the cell in the wrong direction. It is also common to refer to "medium decoys", which are larger than the wiggle offset of a typical wiggle clear, but smaller than the much larger offset that follows the wiggle.
Since decoys are unlikely to cause an opponent to lose on their own, they are almost always combined with other strategies. They are common in all sorts of programs to buy time to perform their strategies (in rush programs, to try to buy time with an undefended flag in order to zero the enemy flag first; in defence programs, in order to set up tripwires and adjust cells on which locks will be performed to sane starting values).
A few programs may benefit from not setting up decoys. This normally happens with bad programs, where setting up decoys may not aid their strategy because it was a bad idea in the first place, whereas not setting up decoys can trick tripwire avoiders off the end of the tape; this is not particularly useful, though, as it won't correct the fundamental flaws in the original program. Alternatively, not using decoys can benefit defence programs that don't use tripwires either, in order to make the likely timings of the opponent a little more consistent, and aid them in setting up a successful lock or shudder.
Small decoys are typically avoided via offset clears. For large decoys, using a fast clear is one possible method to avoid them. However, techniques like tripwire avoidance and careless clears work better by entirely neutralising the decoy's effect, and defensive programs, especially those that use tripwires for synchronization, generally care nothing for opposing decoys, either due to not attacking at all, or due to using full-tape clears that are unaffected by decoy values.
=== Reverse decoy setup ===
When setting a large number of decoys, it is often a good idea to set the ones nearer the enemy flag first, in order that the first few decoys might buy time to set up the last few against faster rush programs.
 >>>>>(-)*64<(+)*64<(-)*64<(+)*64(>)*7(>[-])*21
Here's a comparison (decoy setups versus a simple rush program):
* Forward decoy setup: 
* Reverse decoy setup: 
The major disadvantage of a reverse decoy setup is on shorter tapes, where instead of some of a large number of decoys working, none do (assuming that the opponent skips them via the Rule of Nine), and the program is defeated trivially. Therefore, it is often a good idea to gain an idea of what the tape length is before embarking upon such a system. Unless the first few decoys are small and set up quickly, reverse decoy setups also often lose to tripwire avoidance, as the first decoys are skipped before the later decoys are set up. If it's suspected that the opponent is using a reverse decoy setup, it's also possible to skip cells until a zero cell is found, but doing so is incredibly risky as it will suicide against other sorts of programs.
=== Interrupted decoy setup ===
Just as building the decoys furthest from your flag can give you more time to build more decoys behind it, one can also use the time afforded by the building of a decoy to do other things. Most commonly, this is used to check a reverse tripwire (gaining information about which cells the opponent has visited, and thus which locations may be fruitful to place decoys on). It is also common to pause a decoy setup in order to repair the flag. Other actions are possible, although rarer: for example, some programs will rush after setting some of their decoys, and go back to add more if the rush does not find a flag early on, and at least one program alternates between building decoys and maintaining a lock.
A related, increasingly common, strategy is to move back and forth between decoys while setting them up, i.e. instead of taking a decoy to its full height immediately, the program interrupts the build of one decoy to build another, and then eventually returns to the original decoy. Doing this helps to create a decoy setup that works against both fast rushes and offset clears: setting lots of decoys quickly can "catch" a fast rush that jumped over outer decoys using the rule of nine, buying time to raise the decoys large enough to defeat an offset; and a medium-sized outer decoy will slow down an offset clear by forcing it into the offset, buying time to make some or most of the decoys large enough to defeat the offset.
=== Breadcrumb decoys ===
By making a series of very small decoys as a trail, then reversing to the beginning of the tape and building them further, it is possible to build decoys precisely until the opponent is encountered. This is done by using the small decoys as reverse tripwires to see if the opponent has come this far already. The idea is to check a reverse tripwire immediately before each decoy is built and interrupt the build as soon as the opponent has been detected, changing strategies based on when and where the opponent was last seen. This is a special type of interrupted decoy build.
Here is a small example program that uses this strategy:
 >-(>[<<<(+)*10(<+[{}(+)*23>(--[(>)*7(>[(-)*15[+]])*21](-)*23>)*24])*24]+)*10
 <<<(+)*10(<+[{}(+)*23>(--[(>)*8(>[(-)*15[+]])*21](-)*23>)*24])*24
Also, compare the early-game behavior (immediately after the deep poke) of Gregor_furry_furry_strapon_pegging_girls, the program that introduced it, with quintopia_a, a later champion that uses it, as they compete: 
=== Trail ===
Any attacker which zeroes cells may also choose to change that value before moving on to the next cell. That changed value can effectively be a decoy. For instance, the below program combines a simple clear with a trail.
 (>+>-)*4>([-]+>[-]->)*11
Leaving a trail generally helps against slowly rushing enemies, as it effectively gives you a lot of free decoys. It hurts against fast rush programs, though, which will generally have overtaken you before the trail is even set, and in such cases a trail will just slow you down. (Not to mention, that offset clears can easily avoid a typical trail.) Trails can be surprisingly useful against advanced defensive programs (although simple defensive programs likely won't notice); such programs often use reverse tripwires to determine whether you have escaped a lock, and if the size of your trail happens to exactly match the size of their tripwire, they will not notice that the lock has been escaped, making it possible to attack an undefended flag. As such, it is fairly common for programs to place trails on cells that they cleared, but not on cells that were already zero (thus forcing the opponents to spend cycles checking the exact size of cells if they want to determine which cells have been cleared).
=== Lock ===
Upon somehow deducing the location of the enemy data pointer (e.g. via a tripwire), and its clear mechanism (e.g. guessing a two-cycle clear or two-cycle offset clear), it is possible to turn the cell in question in the other direction at much the same rate, thus forcing the opponent into an infinite loop. Locking can also be done less reliably by turning the cell in the same direction, such that the cell never becomes zero for two cycles; the risk in this is that the opponent can detect that it's happening and take countermeasures. If a defense program is lucky, the opponent will respond by falling off the tape, but rush programs rarely fall for such tactics nowadays. Here is possibly the simplest lock-based program:
 >+[]<(.)*90
 ((+)*256 (>)*9 (+.)*119 (<)*9)*3
 ((+)*256 (>)*10 (+.)*118 (<)*10)*3
 ((+)*256 (>)*11 (+.)*117 (<)*11)*3
 ((+)*256 (>)*12 (+.)*116 (<)*12)*3
 ((+)*256 (>)*13 (+.)*115 (<)*13)*3
 ((+)*256 (>)*14 (+.)*114 (<)*14)*3
 ((+)*256 (>)*15 (+.)*113 (<)*15)*3
 ((+)*256 (>)*16 (+.)*112 (<)*16)*3
 ((+)*256 (>)*17 (+.)*111 (<)*17)*3
 ((+)*256 (>)*18 (+.)*110 (<)*18)*3
 ((+)*256 (>)*19 (+.)*109 (<)*19)*3
 ((+)*256 (>)*20 (+.)*108 (<)*20)*3
 ((+)*256 (>)*21 (+.)*107 (<)*21)*3
 ((+)*256 (>)*22 (+.)*106 (<)*22)*3
 ((+)*256 (>)*23 (+.)*105 (<)*23)*3
 ((+)*256 (>)*24 (+.)*104 (<)*24)*3
 ((+)*256 (>)*25 (+.)*103 (<)*25)*3
 ((+)*256 (>)*26 (+.)*102 (<)*26)*3
 ((+)*256 (>)*27 (+.)*101 (<)*27)*3
 ((+)*256 (>)*28 (+.)*100 (<)*28)*3
 ((+)*256 (>)*29 (+.)*99 (<)*29)*3
Locks can be broken by using a different clear algorithm from the one they expect; using a three-cycle clear is typically enough for this, and a five-cycle clear nearly always escapes locks perfectly. Varying clear algorithms from tape cell to tape cell makes it much harder for a lock to guess what you are doing. Locks are also incapable of trapping careless clears and full-tape clears on any particular cell, but often beat them anyway by incidentally tricking them off the end of the tape, so they cannot be seen as sensible countermeasures.
Another way to break free from a lock is to change strategy after a while, either based on time, or on observing a zero cell for one cycle but not two (a giveaway that you are either being locked, or facing a vibration or shudder program). The anti-shudder clear exploits this by dropping through into something crazy, like an eleven-cycle clear, that no program could be expected to have an appropriate lock algorithm for, or to figure out that that clear algorithm was being used even if it did.
=== Probabilistic lock ===
The invention of the timer clear meant that new defensive strategies were needed for defence programs to be able to maintain their locks. The probabilistic lock abandons any attempt to synchronize with an opponent; rather, it resigns itself to the fact that it will only get a lock some proportion of the time.
The basic idea is to pick a length of time that's a small power of 2 (such as 128 cycles), then throughout most of that time, increase then decrease the cell you're locking on. Here's an example from ais523_preparation (which increases and decreases the cell by 56.5 cycles, alternating the rounding between iterations):
 (+)*56(-)*57(.)*15
 (+)*57(-)*56(.)*15
Because the lock's repeat rate is a power of two and makes no net change to the lock cell, the sequence of values on the lock cell will have the same repeat rate as the opponent's clear loop would naturally; in particular, this means that the lock loop and the opposing clear loop will always be at the same point whenever the lock cell hits zero. Almost half the time, the lock is working with the opponent; almost half the time, it's working against. However, the value of the lock cell moves faster when the two loops are moving it in the same direction, than when they're moving it in opposite directions. Thus, the odds are in favour of both loops pushing in the same direction as the lock cell crosses zero, which is the most important condition for a lock to hold.
This sort of lock thus gives a chance to defeat timer clears. Because it does not care that much about the details of the enemy's clear loop, there is a good chance that, having changed clear loop upon the timer expiry, the new loop will immediately be locked again by the probabilistic lock.
The huge downside is that this sort of lock only leaves a very small window to do anything other than maintain the lock. The above example gives fifteen cycles of freedom each time round the lock; this is enough to (very slowly) check or adjust cells within seven cells of the lock, but does not allow any sort of full-tape clear. Typical uses of this time would be to set up very strong decoys, and/or to check tripwires to see if the lock had broken (which can happen by chance, due to the lack of any meaningful sort of synchronization).
=== Triplock ===
A triplock is a different sort of lock, which targets a different part of the opponent's program. While ordinary locks are almost exclusively aimed at the opponent's clear loop, a triplock instead tries to lock the opponent in its control flow; to be precise, it locks programs that contain three or more ] commands in a row, which is very common in constructs such as [+[--[-]]], and can appear in programs for other reasons. (To be precise, it locks programs that contain three ] commands with no < or > in between immediately after a clear (with the first ] possibly part of the clear loop), and also certain other control flow patterns.)
The basic idea is to wait until a decoy (that cannot be the flag, unlike an ordinary lock) becomes zeroed, then immediately set it up to a large nonzero value again, using tripwire code such as [](+)*128. In order to actually win with the lock, it needs to be combined with a clear. A full-tape clear can be used, as typically is with locks; but a triplock (and no other known defensive construct, at the moment) also allows a much shorter "inline clear", allowing for a complete program that looks much like this:
 >(+)*128[](+)*128>(+)*15[-]<[](+)*128>>(+)*15[-]<<[[](+)*128>>[>]->([-{[<+]}])%10<[<]<]
 (warning: can be very slow to load on several browsers)
(The inline clear works by using the tape itself as working space to remember how far through its clear algorithm it is; but because it takes a variable rather than fixed amount of time like a full-tape clear does, it cannot be combined with an ordinary lock.) Other clears can also be used, such as 2-cycle clears or offset clears, but run quite a risk of the opponent breaking the lock if clearing one cell takes too long.
The simplest way to beat a triplock is merely to avoid the sort of control flow structures it is vulnerable to, but this can often cripple a program for other reasons (inability to use complex control flow is quite serious). Alternatively, certain types of clear algorithms can avoid triplocks by breaking the lock faster than it can complete its clear (reverse offset clears tend to do this, often on only one polarity depending on the details of the triplock). It may also be possible for a program to detect that it has been triplocked, although ordinary locks pushing in the wrong direction look much the same from the point of view of a program, so programs need to experiment further to determine exactly how the opponent is trying to lock them.
There is an interesting symmetry between triplock and shudder programs, incidentally; shudder programs tend to beat programs that check the value of the tape cell they are on once before moving on, whereas triplock programs tend to beat programs that check the value three or more times before moving on. Two would thus seem to be the optimal number, in a program that can afford the control flow restrictions that come with it.
=== Flag repair ===
Flag repair is a defensive technique used in situations where the opponent is known to have reached your flag before you have started to clear theirs (thus meaning that you would likely lose if you attempted to outrace them), but have a good idea of where their flag is already (e.g. the tape is short, or the opponent appears to be a fast rush program). The basic idea is to make a large adjustment (between 64 and 128) to your own flag at top speed (e.g. (+)*120 on your flag) – if the opponent's clear loop goes in the other direction to the adjustment you have delayed them by twice that many cycles (thus catching up in the flag-clearing race by that many cycles), and if it is in the same direction you will probably push the flag past zero and force them to clear it again (unless they manage to observe it at zero, and use the information to reverse the direction of the clear loop). Repairing the flag buys a little extra time which is often sufficient to defeat fast rush programs or to win on short tapes; it also defeats careless clears (something that is also possible by adjusting your flag while the opponent isn't clearing it, but doing it while the opponent is clearing is better against non-careless-clear strategies).
Repeatedly repairing the flag is, in effect, a lock algorithm, and as such, it is possible for a flag repair to serve as the first part of a lock.
=== Shudder ===
Shuddering is cycling the value of the flag through increments and decrements in order to cause attack loops to fail to put the flag at 0 for two cycles. The reversal of direction is key to this strategy. It usually results in a net increase/decrease over time, differentiating it from a "vibrator" below. Although moderately good as a defensive strategy, it tends to lose at random on certain tape lengths, and it renders its user entirely incapable of attacking as the shudder needs to be kept up constantly. Shudder programs thus can only win by tricking the opponent off the end of the tape. Canonical example:
 (++-)*100000
As shuddering can only win by tricking its opponent off the end of the tape, waiting for two zero cycles in a row before moving on guarantees at least a draw against it, and often a win. Clears designed to exploit this property are known as anti-shudder clears.
=== Vibrator ===
A vibrator vibrates its own flag between zero and nonzero constantly, thus making it very dangerous to assume a flag is cleared just because it hit zero. However, it is very easy to defeat by using a clear that is out of phase with its vibration. Canonical example:
 (-)*127(-+)*100000
If you fear falling off the tape due to missing a vibrator, you can check two cycles in a row before moving on (the difference between this and counter-shudder tactics is that it must be done at the start of the loop, rather than the end).
=== Abandoning a defensive strategy ===
Defensive programs sometimes have to face other defensive programs. Some defensive programs cannot gain information about what the opponent is doing while they are actively defending, e.g. programs that shudder or vibrate the flag usually need to do so continuously to avoid losing. However, many defensive techniques offer spare cycles; many of these may be used to clear decoys (or to bolster your own decoys) and eventually the opponent's flag, but some of them can typically be spared to check reverse tripwires, or even the zeroness/nonzeroness of the cell that the program is trying to lock the opponent on. For these programs, it is usually possible for them to detect situations in which the opponent is being purely passive and has not even reached the lock cell, either via checking whether tripwires (regular or reverse) have been tripped, or by checking to see whether the lock cell is 0 on cycles where it would be 0 if the opponent did nothing.
If the opponent does appear to be passive, it is generally a good idea to switch to a rush strategy tuned specifically to defeat defensive programs, rather than continuing to defend. If done correctly, this gives you wins rather than draws against programs that defend forever, and gives you a chance of a win rather than a loss against a program that switches to anti-defense rush after noticing that you are passively defending.
== Reconnaissance ==
Although a program that entirely ignores its opponent's attacks (and in some cases, even the opponent's defences) can be effective, many programs will want to discover information about their opponent's strategy, the opponent's current actions (e.g. to synchronize a lock), the tape length, or some combination of these.
=== Tripwire ===
A tripwire is one of the simplest reconnaissance and synchronization devices, detecting an enemy clear loop.
An ordinary tripwire looks like this:
 +[]
What it does is obvious, as it causes you to wait for your opponent to clear it. Using one is guaranteed to make you draw with any non-attacking program.
A variation is the two-cycle tripwire:
 +
which waits for a cell to be zeroed for two cycles before you can continue. (The similarity of this to BF Joust's main victory condition means that all but careless clears are likely to do this, and probably just before moving to the next cell, rather than as part of an offset clear).
Sometimes tripwires will have a value larger than 1 or -1; this is typically for the purpose of causing the length of time it takes to zero them to provide more information about the opponent's strategy.
Tripwire avoidance allows obvious tripwires to be skipped altogether, giving an easy win, but is itself fooled by decoys. Careless clears will not trip an ordinary tripwire at one polarity, nor a two-cycle tripwire at either polarity, meaning that they can often beat tripwire-based programs too. (However, tripwire-based programs that change the value of their flag can exploit this effect in reverse, to beat careless clears by tricking them off the end of the tape!)
=== Timer tripwire ===
A normal tripwire represents a significant commitment; the program will not leave its tripwire until it is tripped, and if the tripwire is never tripped, the warrior cannot win. But a quality defense program is afraid of commitment, and wants to be able to change its mind if it thinks the tripwire will never get tripped. If it also cannot tolerate the synchronization inaccuracies associated with a reverse tripwire, it can use a timer tripwire, wherein it stops monitoring the tripwire after a preset number of cycles:
 ++++++([{give up and switch strategies}][handle careless or offset clear]synchronization achieved)%1000
=== Reverse tripwire ===
An alternative sort of tripwire, that allows other operations to be done at the same time.
 +go do some other processing-[tripped]not tripped
This allows you to go do other things like building decoys or deciding whether you want to attack instead of wait any longer. As long as you check it often enough, you can get almost as close to being in sync with your opponent as you could be using a regular tripwire, and yet still be able to change your mind about defending, perhaps due to a belief that the opponent is also a defender.
The reverse tripwire has three major weaknesses: an opponent can set it back to its previous value (generally 1 or -1) upon clearing it; if the opponent encounters it while its value happens to be 0, they may miss its existence entirely and skip past it; and a cautious opponent can observe that its value becomes 0 every now and then (a giveaway for a reverse tripwire or a vibrated flag) and choose not to clear it. (Also, they aren't cycle-accurate with respect to timing like regular tripwires are; for some defensive programs, this matters, for most it won't.) Sometimes values greater than 1 or -1 are used for reverse tripwires in order to reduce the risks, but that also means they take longer to check. Tripwire avoidance also works almost as well against reverse tripwires as it does against regular tripwires. Using multiple reverse tripwires is common in programs that use any, as a method of increasing the chance that at least one spots the opponent, and helping to defeat countermeasures.
=== Cleared decoy detection ===
Some programs set up their decoys in multiple stages – first setting up a fraction of the decoy's height, and then later increasing the decoy to its full height. A program that does this can check to see if the decoy cell is 0 immediately before the later increase; if it is, then the opponent must have changed the decoy, almost certainly by clearing it (the other possibility is that they set a decoy of their own with the same size and opposite polarity, but this is unlikely). As such, this provides two important pieces of information: that the opponent has moved beyond the decoy cell (thus decoys at and beyond that point are no longer helpful), and that the opponent was attempting to clear the decoy cell (so their flag is probably at least nine cells away, otherwise it would not have been a useful cell to clear). The check is also very cheap (just one cycle to run a [ command).
The standard solution to defeat cleared decoy detection is to leave a trail (preventing cleared cells having a suspicious value of 0). However, cleared decoy detection can be generalised to detect trails half the time; instead of only checking before the decoy is increased, it's possible to also check after the first increase (or first two, first three, etc.). This will detect a small-valued trail as long as it has the opposite polarity from the decoy (which normally happens about half the time), and is still very cheap in cycles. As such, programs that are trying to beat cleared-decoy-detectors sometimes try to match the polarity of their trail to the polarity of the decoy (e.g. by timing how long the cell took to clear).
Cleared decoy detection can be used as a program's primary strategy (e.g. ais523.growth2 spends most of its time gradually increasing its decoys in multiple stages, until it detects that a decoy has been cleared), but more commonly sees use as a supplement to a program's main strategy, allowing it to attack and defend more accurately when the opponent gets partially inside the decoy setup.
=== Decoy detection ===
Most programs will not change a tape element that's already set to zero, even if they encounter it during a clear loop; and even if they do (e.g. as part of a trail), if a program changes a tape element, that's a sure sign that it at least knows that the tape is long enough to contain that element. As such, decoys beyond that point are not helpful.
You can detect enemy decoys simply by doing a [ on an element before setting a decoy there. If you discover it to be nonzero, there is no point in placing a decoy there or anywhere beyond that point. Lymia_nyuroki was the first program to exploit this in a reverse decoy setup, to detect clashing decoy patterns. An earlier and more common use involves placing decoys up to the first enemy decoy detected (e.g. via using a large trail); this is often wasteful against aggressive programs who set few decoys (as they will rule-of-nine past some), but helps against programs that set a lot of decoys (because the rule of nine is less useful for those programs), and against defensive programs (where the time wasted setting up unused decoys is not very costly, and thus setting up possibly-useful-possibly-useless decoys is worthwhile as the upside outweighs the downside).
=== Tape length estimation ===
The most important value in all of BF Joust is the tape length, and thus it's very helpful for programs to get some idea of what it is.
One sure sign of a short tape is if you see an opponent's decoy early, before there would be enough time for a program to move there from the other side of a long tape and set a decoy there. In order to defend against pokes, it is common for programs to start by running forwards, leaving a small trail as they go – if both programs do that, and the tape is short, it is quite likely that they will encounter each others' decoys early on.
Not 100%, but still fairly reliable, is noticing that the opponent has somehow skipped past some of your decoys and tripwires (e.g. via observing a reverse tripwire having been tripped even though there was no time to clear a decoy in front of it); although there are various possible explanations, the most likely is that they were skipped using the rule of nine. Depending on where the opponent was first observed, you can estimate that the tape length is probably somewhere around 9 cells away from there. This test works in reverse, too – if an opponent seems to be spending time clearing a particular decoy, the end of the tape is probably at least nine cells away from there (although you may need to verify that the opponent is indeed clearing it, rather than setting a decoy there!)
Generally speaking, it is important nowadays for programs to attempt to determine whether the tape is particularly short – tactics that work well on long tapes, such as setting large numbers of decoys, tend to do badly on short tapes. Some strategies that work well on short tapes are fast rushes, careless clears, and lock-based defence (because you may win before the opponent can break the lock, and because it is good against careless clears). It is also possible for programs to optimise for longer tapes if they see no evidence of a short tape (e.g. by upgrading the rule of nine to a rule of ten or rule of eleven).
== See also ==
* BF Joust champions
Category:Programming techniques
Category:Programming games