# Landmine Number V

## Background

You have again x4 been given the task of calculating the number of landmines in a field. But this time, the field is not a number field... it's a field of letters. Our landmine letter operator is sick and requires you to cover for them. They left you the following note:

Things work a little differently with regards to identifying landmines here. They'll give you pairs of capital letters, I call letter flags, to look out for.

If a pair of letters exist in the landscape, in the given order (not necessarily adjacent), it's a bad sign. If a letter appears between the two given letter flags, which does exist between the two letters in alphabetical order, you've got yourself a landmine.

Count the number of landmines and send 'em to the boss.

Here's an example:

Say you've got AADCRTEBASDVZ, and the letter flags are AE, DE, and FZ Then the landmines would be:

AE: D in AA[D]CRTE - I highlighted the relevant letters for you with brackets.
D again, in A[D]CRTE, because there are two As in the beginning so we have to account for both
C again, in AD[C]RTE see above DE: has no letters between them, so I know I can skip this one
FZ: there's no F in the landscape, so I ignore this one


That's a total of 4 landmines. Send off 4, and you're done.

Oh right, I know you've got some fancy automation robo thingy you use for your own thing. I'm an old guy, don't do too well with tech. Maybe you can come up with something for me while I'm gone?

I owe you one.

• R

• Sample Input: The letter landscape, which will only contain letters, and a list of two-letter letter flags. It is given that everything is in capital letters, and that the letter flags are already in alphabetical order.

• Output: Return the landmine score (number of landmines)

Explained Examples

Input => Output
ABABEBE AE => 8

The landmine letters are:
A[B]ABEBE
ABA[B]EBE
ABABE[B]E
A[B]EBE
ABE[B]E
A[B]ABE
ABA[B]E
A[B]E

Input => Output
BASCOOSDJE AC AE DE BC => 2

The possible landmine letters are:
AS[C]OOSDJE
ASCOOS[D]JE

Input => Output
ABCDEFGHIJKLMNOPQRSTUWXYZ HO => 6

The landmine letters are:
H[I]JKLMNO
HI[J]KLMNO
HIJ[K]LMNO
HIJK[L]MNO
HIJKL[M]NO
HIJKLM[N]O

Input => Output
HSBEBAIWBVWISUDVWJYZGXUEUWJVEEUH AB CD EF GH IJ KL MN OP QR ST UV WZ  => 3

The landmine letters are:
WBVWISUDVWJ[Y]Z
WISUDVWJ[Y]Z
WJ[Y]Z


Test Cases

Input => Output
ABABEBE AE => 8
BASCOOSDJE AC AE DE BC => 2
ABCDEFGHIJKLMNOPQRSTUWXYZ HO => 6
HSBEBAIWBVWISUDVWJYZGXUEUWJVEEUH AB CD EF GH IJ KL MN OP QR ST UV WZ  => 3

XKCDONENINESIXZERO DN AR NO DE XZ  => 3
HTMLISAPROGRAMMINGLANGUAGE LR HJ HM => 7
THEREAREZEROLANDMINESINTHISSENTEN CE => 0
DAQUICKBROWNFOXJUMPSOVERTHELAZYDOGZ HZ => 4
QWERTYUIOPASDFGHJKLZXCVBNMNBVCXZLKJHGFDSAPOIUYTREWQ AC DF GI JL => 6


This is , so shortest answer wins.

• Could you set the letter off with a blockquote rather than a code block? As written, you have to scroll horizontally to read the longer paragraphs. Commented Jul 14, 2023 at 11:49
• @Bbrk24 Sure, on it. Commented Jul 14, 2023 at 11:58
• About DZ in the sample, why do you only account for DVZ in AADCRTEBASDVZ? Isn;t there also DCRTEBASDVZ? Wouldn't there be a total of 10 mines in the sample then?
– JvdV
Commented Jul 14, 2023 at 12:41
• Same problem with other samples you have given. For example DAQUICKBROWNFOXJUMPSOVERTHELAZYDOGZ contains HELAZ and HELAZYDOGZ for a key of HZ. Meaning there would be 4 landmines. Right? Please clarify how you calculated, because in the "note" it's clear that multiple occurences of the left/right character in a key (double A) would reset the substring.
– JvdV
Commented Jul 14, 2023 at 12:48
• I get 3 for XKCDONENINESIXZERO DN AR NO DE XZ and 6 for the last test case. Just out of curiosity, were the test cases made by hand in all your landmine challenges? Despite the (relatively) simple rules, it's very easy to make mistakes. Maybe you should consider using a script for the future ones. Commented Jul 14, 2023 at 13:59

# Python 3, 88 85 bytes

lambda l,f:sum(x+z in(x<y<z)*f for x,y,z in combinations(l,3))
from itertools import*


Try it online!

-3 bytes thanks to @tsh

## Explanation

Just uses itertools.combinations to iterate over all combinations of three characters in the landscape and counts those corresponding to landmines.

• Wow that's actually really nifty that this challenge can be reduced to filtering a list of combinations without replacement. That's so much easier than trying to figure out all sorts of arcane rules to filter substrings :p Commented Jul 15, 2023 at 2:04
• lambda l,f:sum(x+z in(x<y<z)*f for x,y,z in combinations(l,3)) is 85.
– tsh
Commented Jul 17, 2023 at 6:42
• Nice trick, I'll have to keep that in mind! Commented Jul 17, 2023 at 13:40

# JavaScript (ES6), 69 bytes

Expects (set)(string).

s=>g=([c,...b],o='',[p,,q]=o)=>q?s.has(q+p):c?g(b,o)+(c>o)*g(b,c+o):0


Try it online!

### Commented

s =>            // s = set of letter flags
g = (           // g is a recursive function taking:
[ c,          //   c = next character from the landscape
...b ],   //   b[] = array of remaining characters
o = '',       //   o = string of selected letters, in reverse order
[ p,,         //   p = 1st character of o
q ] = o //   q = 3rd character of o
) =>            //
q ?             // if q is defined:
s.has(q + p)  //   increment the result if q + p exists in s
:               // else:
c ?           //   if c is defined:
g(b, o) +   //     do a recursive call with o unchanged
(c > o) *   //     the 2nd call is valid only if c > o
g(b, c + o) //     do a recursive call with c + o
:             //   else:
0           //     stop the recursion


# Python 3.8, 85 bytes

I was curious to see if a port in Python could compete with user1609012's answer.

Thanks to @tsh who managed to save 4 bytes.

f=lambda s,a,o="":o[::-2]in a or s>""==o[2:]and(s[0]>o)*f(q:=s[1:],a,s[0]+o)+f(q,a,o)


Try it online!

• f=lambda s,a,o="":o[::-2]in a or s>""==o[2:]and(s[0]>o)*f(q:=s[1:],a,s[0]+o)+f(q,a,o) (do we really need ==o[2:]?)
– tsh
Commented Jul 17, 2023 at 4:33
• @tsh Nice! It may work without ==o[2:] but will time out on most test cases. Commented Jul 17, 2023 at 7:35
• But seems that the other answer may also be stripped to 85 bytes. :)
– tsh
Commented Jul 17, 2023 at 7:53
• Fair enough! ;) Commented Jul 17, 2023 at 8:22
• maybe 84: f=lambda s,a,o="":s>""==o[2:]and(s[0]>o)*f(q:=s[1:],a,s[0]+o)+f(q,a,o)or o[::-2]in a
– tsh
Commented Jul 18, 2023 at 2:08

Assuming OP made some mistakes in their samples (see comment section):

# Excel (ms365), 168 bytes

Formula in C1:

=SUM(IFERROR(MAP(B1:B4,LAMBDA(f,LET(x,SEQUENCE(LEN(A1)),s,TOROW(x),l,LEFT(f),r,RIGHT(f),y,TOCOL(TEXTBEFORE(TEXTAFTER(A1,l,x),r,s),2),z,MID(y,s,1),SUM((z>l)*(z<r))))),))


# Husk, 7 bytes

Σ×¤=…Ṗ3


Try it online!

Makes good use of the … range operator, which given a list of characters fills in all the missing characters to leave no gaps in the alphabet. For example:

…"CF" => "CDEF"

…"ADB" => "ABCDCB"

The key here is realising that a three-letters subsequence from the landscape will match the flag IFF the two are equal when … is applied to both of them.

## Explanation

Σ×¤=…Ṗ3
Ṗ3    Get a list of all (ordered) 3-letter subsequences from the landscape
×         For each of these subsequences and each flag:
¤=…       check if they are equal when … is applied to both (returns 1 or 0)
Σ          Sum all the results


# Wolfram Language(Mathematica), 97 bytes

Golfed version. Try it online!

g[l_,f_]:=Count[Subsets[Characters@l,{3}],{x_,y_,z_}/;x~Order~y>0&&y~Order~z>0&&f~MemberQ~(x<>z)]


Ungolfed version. Try it online!

g[l_, f_] := Count[Subsets[Characters@l, {3}], {x_, y_, z_} /; Order[x,y]==1 && Order[y,z]==1 && MemberQ[f, x <> z]]

testCases = {
{"ABABEBE", {"AE"}, 8},
{"BASCOOSDJE", {"AC", "AE", "DE", "BC"}, 2},
{"ABCDEFGHIJKLMNOPQRSTUWXYZ", {"HO"}, 6},
{"HSBEBAIWBVWISUDVWJYZGXUEUWJVEEUH", {"AB", "CD", "EF", "GH", "IJ", "KL", "MN", "OP", "QR", "ST", "UV", "WZ"}, 3},
{"XKCDONENINESIXZERO", {"DN", "AR", "NO", "DE", "XZ"}, 3},
{"HTMLISAPROGRAMMINGLANGUAGE", {"LR", "HJ", "HM"}, 7},
{"THEREAREZEROLANDMINESINTHISSENTEN", {"CE"}, 0},
{"DAQUICKBROWNFOXJUMPSOVERTHELAZYDOGZ", {"HZ"}, 4},
{"QWERTYUIOPASDFGHJKLZXCVBNMNBVCXZLKJHGFDSAPOIUYTREWQ", {"AC", "DF", "GI", "JL"}, 6}
};

(actualOutputResults = Table[g @@ testCase[[1 ;; -2]],{testCase, testCases}] ) //Print
If[AllTrue[testCases, g@@(#[[1 ;; -2]]) == #[[3]] &]
, Print["All tests passed"],
Print["Some test failed"]]


# Charcoal, 38 32 bytes

ＳθＷＳ⊞υιＩΣ⭆θ⭆…θκ⭆…θμ∧№υ⁺νι∧‹νλ‹λι


Try it online! Link is to verbose version of code. Takes the landscape and a list of newline-terminated pairs as input. Explanation: Saved 6 bytes by porting @user1609012's Python answer.

ＳθＷＳ⊞υι


Input the landscape and the pairs.

ＩΣ⭆θ⭆…θκ⭆…θμ∧№υ⁺νι∧‹νλ‹λι


For each prefix of each prefix of each prefix of the string, which corresponds to taking combinations of three characters without replacement, count those that correspond to landmines.

# 05AB1E, 22 14 bytes

3.ÆεÐêQ×ιнJ}åO


-8 bytes by porting user1609012's Python answer, so make sure to upvote that answer as well!

Inputs in the order landscape, flags, where flags is a list of 2-char strings.

ŒʒÀIíÅ¿à}εÇDÁ2£Ÿ¦¨¢O}O


Explanation:

3.Æ           # Get all triple char-combination of the first (implicit) input-string
ε          # Map over each triplet of characters:
Ð         #  Triplicate the current triplet
ê        #  Sorted-uniquify the top list
Q       #  Check if it's still the same
×      #  Repeat the strings in the remaining triplet that many (0 or 1) times
ι     #  Uninterleave it into two parts: [a,b,c] → [[a,c],[b]]
н    #  Pop and keep just the first pair
J   #  Join them together to a string
}          # After the map:
å         # Check for each string whether it's in the second (implicit) input-list
O        # Sum the truthy values together
# (which is output implicitly as result)

Œ             # Get all substrings of the first (implicit) input-string
ʒ            # Filter these substrings by:
À           #  Rotate its characters once towards the left
I          #  Push the second input-list of pairs
í         #  Reverse each inner pair
Å¿       #  Check for each reversed pair whether the rotated string ends with it
à      #  Pop and leave the maximum to check whether any is truthy
}ε           # After the filter: map over each remaining substring:
Ç          #  Convert the substring to a list of codepoint-integers
D         #  Duplicate this list of integers
Á        #  Rotate the copy once towards the right
2£      #  Pop and leave just the first two integers
Ÿ     #  Convert it to a ranged list
¦¨   #  Remove the first and last items itself
¢  #  Count how many times each inner codepoint-integer occurs
O #  Sum those counts for the current substring together
}O          # After the map: sum the list of sums together
# (which is output implicitly as result)


# Scala, 153 bytes

Golfed version. Try it online!

(l,f)=>{var c=0;for(i<-0 to l.length-1;j<-i+1 to l.length-1;k<-j+1 to l.length-1)if(l(i)<l(j)&&l(j)<l(k)&&f.contains(l(i).toString+l(k).toString))c+=1;c}


Ungolfed version. Try it online!

import scala.collection.mutable

object Main {
def g(l: String, f: Array[String]): Int = {
var count = 0
for(i <- 0 until l.length) {
for(j <- i+1 until l.length) {
for(k <- j+1 until l.length) {
val x = l(i)
val y = l(j)
val z = l(k)
if(x < y && y < z && f.contains(x.toString + z.toString)) {
count += 1
}
}
}
}
count
}

def main(args: Array[String]): Unit = {
val testLines = List(
("ABABEBE", Array("AE"), 8),
("BASCOOSDJE", Array("AC", "AE", "DE", "BC"), 2),
("ABCDEFGHIJKLMNOPQRSTUWXYZ", Array("HO"), 6),
("HSBEBAIWBVWISUDVWJYZGXUEUWJVEEUH", Array("AB", "CD", "EF", "GH", "IJ", "KL", "MN", "OP", "QR", "ST", "UV", "WZ"), 3),
("XKCDONENINESIXZERO", Array("DN", "AR", "NO", "DE", "XZ"), 3),
("HTMLISAPROGRAMMINGLANGUAGE", Array("LR", "HJ", "HM"), 7),
("THEREAREZEROLANDMINESINTHISSENTEN", Array("CE"), 0),
("DAQUICKBROWNFOXJUMPSOVERTHELAZYDOGZ", Array("HZ"), 4),
("QWERTYUIOPASDFGHJKLZXCVBNMNBVCXZLKJHGFDSAPOIUYTREWQ", Array("AC", "DF", "GI", "JL"), 6)
)

for ((l, f, expected) <- testLines) {
assert(g(l, f) == expected)
}

println("All tests passed")
}
}



# Retina, 59 bytes

~["Lw"|'|L$¶(.)(.)$1.+$2 /.+/_~L$(.).+(.)
[A-$1$2-Z]¶
.


Try it online! Takes the landscape on the first line and the letter pairs on subsequent lines but link is to test suite that splits on spaces for convenience. Explanation:

~["Lw"|'|L$¶(.)(.)$1.+$2  Get all overlapping substrings of the landscape for each pair of letters. /.+/_~L$(.).+(.)
[A-$1$2-Z]¶


For each substring, remove letters that are not landmines.

.


Count the landmines.

Example: For the input IPLEADTHEFIFTH, DF, AE, the first stage generates the following command:

LwD.+F|A.+E


The ~ then causes this to be evaluated on the original input producing the list of overlapping substrings ADTHE, DTHEF, DTHEFIF. For each of these, the second stage generates a replacement stage to delete the non-landmines, so for example the last substring DTHEFIF produces the following command:

[A-DF-Z]



This is then executed on the string DTHEFIF producing the landmine E. The /.+/ guard on the second stage ensures that it does not execute if there were no substrings.

# J, 46 bytes

+/@(e.~[:>@,((#~]<{:)\{@;"1(#~]>{.)\.))&(3&u:)


Try it online!

• Convert to ascii codes
• For each element in the main input, find all elements to the left that are less, and all to the right that are greater, and create the cartesian product of these. Each of these is a "candidate pair".
• In J, we do this by zipping the prefix lists (filtered as described above) with the postfixed lists (also filtered).
• Return the number of candidate pairs appearing in the given pairs list

# m68k assembly, 72 bytes

20 6f 00 04 48 e7 30 20 70 00 22 6f 00 14 12 18 67 30 14 18 4a 11 67 f2 b2 19
66 f8 76 00 24 49 4a 12 67 08 b4 1a 66 f8 52 83 60 f4 24 49 b2 12 64 0a b4 12
56 cb 00 06 65 02 d0 43 4a 1a 66 ee 60 d2 4c df 04 0c 4e 75


Follows the standard Linux/SysV abi.

This loops over all flag pairs individually. For each start flag found, we count the number of end flags coming later in the input. Then we just iterate over all the bytes from the start flag to the end, adding the number of start-end pairs that the byte is contained within to the result.

Or as a demonstration:

{A}BABEBE (Find start flag)

{A}BAB[E]B[E] Res = 0, Eflags = 2 (Sum # of end flags (2))

{A}BAB[E]B[E] Res = 4, Eflags = 2 (Add # of end flags to result for every byte between start and end)
¯ ¯
{A}BAB(E)B[E] Res = 4, Eflags = 1 (When you hit an end flag, decrement # of eflags)

{A}BAB(E)B[E] Res = 5, Eflags = 0 (Repeat step 3 & 4 until the end)
¯
{A}BEBE Res = 5, Eflags = 0 (Start again at step 1 until the end)


Here's the code, tested on a TI-89 Titanium:

| definition: unsigned short lm5(const char *flag_pairs, const char *input);
.text
.even
.globl lm5
lm5:
movea.l 4(%sp), %a0;        | Load the flag pair string into %a0
movem.l %d2-%d3/%a2, -(%sp);
moveq #0, %d0;              | Zero the minefield counter
per_flag_pair_loop:
movea.l 20(%sp), %a1;       | Load the beginning of the input string.
| This is reloaded at the beginning of handling
| every flag pair.
move.b (%a0)+, %d1; | Load the first flag char.
beq end;            | If we're at the end of the flag string,
| then we're done.
move.b (%a0)+, %d2; | Load the second flag char.

find_start_flag_loop:       | Loop over all characters looking for the start
| flag. If found, compute the number of mines it
tst.b (%a1);
beq per_flag_pair_loop;
cmp.b (%a1)+, %d1;
bne find_start_flag_loop;

moveq #0, %d3;
movea.l %a1, %a2;

count_end_flag_loop:        | Loop over the input from the flag to the end,
| putting the number of end flags in %d3.
tst.b (%a2);
beq count_end_flag_loop_end;
cmp.b (%a2)+, %d2;
bne count_end_flag_loop;
bra count_end_flag_loop;

count_end_flag_loop_end:
movea.l %a1, %a2;   | We had to overwrite %a2, so reload it before
| looping again.

per_start_flag_loop:
cmp.b (%a2), %d1;
bhs per_start_flag_is_null;     | The input is too small
cmp.b (%a2), %d2;
dbne.w %d3, per_start_flag_is_null; | If the input is the end flag,
| decrement the flag counter
| and jump. Else fallthrough.
blo per_start_flag_is_null;
add.w %d3, %d0;             | Increment the result once for
| each matching end flag.
per_start_flag_is_null:
tst.b (%a2)+;               | Null check and _the_ loop's increment.
bne per_start_flag_loop;
bra find_start_flag_loop;   | If null, find the next matching start
| flag.
end:
movem.l (%sp)+, %d2-%d3/%a2;
rts;                        | Output in %d0



(TIL that tabs don't work properly here)

# Perl 5, 83 bytes

eval"$F[0]=~/$1.*$2(?{$$\s+=\$$&=~y,$1-$2,,-\$&=~y,$1$2,,})^/"while/ (.)(.)/g;$_=$s|0


Try it online!

# Vyxal, 84 bitsv2, 10.5 bytes

3ḋ'1⋎⁰cnÞ⇧*;L


Try it Online!

Ports user1609012's python answer, so make sure you go upvote that. It's a much simpler answer than what I would have come up with.

## Explained

3ḋ'1⋎⁰cnÞ⇧*;L­⁡​‎‎⁪⁡⁪⁠⁪⁡⁪‏⁠‎⁪⁡⁪⁠⁪⁢⁪‏‏​⁡⁠⁡‌⁢​‎‎⁪⁡⁪⁠⁪⁣⁪‏⁠‎⁪⁡⁪⁠⁪⁣⁤⁪‏‏​⁡⁠⁡‌⁣​‎‎⁪⁡⁪⁠⁪⁤⁪‏⁠‎⁪⁡⁪⁠⁪⁢⁡⁪‏‏​⁡⁠⁡‌⁤​‎‎⁪⁡⁪⁠⁪⁢⁢⁪‏⁠‎⁪⁡⁪⁠⁪⁢⁣⁪‏‏​⁡⁠⁡‌⁢⁡​‎‎⁪⁡⁪⁠⁪⁣⁣⁪‏‏​⁡⁠⁡‌⁢⁢​‎‎⁪⁡⁪⁠⁪⁢⁤⁪‏⁠‎⁪⁡⁪⁠⁪⁣⁡⁪‏⁠‎⁪⁡⁪⁠⁪⁣⁢⁪‏‏​⁡⁠⁡‌⁢⁣​‎‎⁪⁡⁪⁠⁪⁤⁡⁪‏‏​⁡⁠⁡‌­
3ḋ             # ‎⁡Get all combinations without replacement of length 3 from the landscape
'        ;   # ‎⁢Keep only combinations n where:
1⋎          # ‎⁣  The combination with the middle letter removed
⁰c        # ‎⁤  Is in the list of landmine flags
*    # ‎⁢⁡  And
nÞ⇧     # ‎⁢⁢  n is sorted in strict ascending order
L  # ‎⁢⁣Get the length of the valid combinations
💎
`

Created with the help of Luminespire.