g | x | w | all
Bytes Lang Time Link
nanScala230724T133033Z138 Aspe
065Scala 3230729T103649Zcorvus_1
006Nibbles230727T144927Zxigoi
007Jelly230727T145403Zxigoi
038Ruby nl230724T230812ZValue In
055Python230724T122803ZGáb
008Jelly230725T065857ZUnrelate
028Perl 5 pl230724T222049ZXcali
011Pyth230724T182230ZCursorCo
095Swift 5.7 enablebareslashregex230724T131904ZBbrk24
006Thunno 2230724T130755ZThe Thon
00605AB1E legacy230724T115511ZKevin Cr
080Excel230724T112910ZJos Wool
117JavaScript ES6230724T110018ZW D
005Vyxal230724T093554Zlyxal
021Dyalog APL230724T100754ZRubenVer
019Charcoal230724T094730ZNeil

Scala, 139 61 bytes

Port of @Gábor Fekete's Python answer in Scala.


Golfed version. Attempt This Online!

Saved 78 bytes thanks to the comment of @corvus_192

var c="";def f(i:Any)={c+=i;(c+c(0))sliding 2 count(_=="AB")}

Ungolfed version. Attempt This Online!

import scala.collection.mutable.ArrayBuffer

object Main {

  var c: ArrayBuffer[String] = ArrayBuffer()

  def f(i: String): Int = {
    if (c.isEmpty) {
      c += i
    }
    else {
      c = ArrayBuffer(c.head + i)
    }
    (c.head + c.head(0)).sliding(2).count(_ == "AB")
  }

  def main(args: Array[String]): Unit = {
    val cases = Array(
      ("ABABA", 2),
      ("ABABA", 4),
      ("//", 0),
      ("BA", 1),
      ("BABA", 3),
      ("BB", 3),
      ("BAAAAB", 4),
      ("//", 0),
      ("AB", 1),
      ("AAA", 1),
      ("B", 2),
      ("AB", 3),
      ("//", 0),
      ("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB", 1),
      ("A", 2),
      ("B", 2),
      ("A", 3),
      ("A", 3),
      ("B", 3),
      ("//", 0),
      ("BABABABABABAB", 6),
      ("A", 7)
    )

    for (caseValue <- cases) {
      caseValue._1 match {
        case "//" => 
          println("=" * 15)
          c = ArrayBuffer()
        case _ => 
          val t = f(caseValue._1)
          println(caseValue._1 + " " + caseValue._2 + " ; result: " + t)
      }
    }
  }
}

Scala 3, 65 bytes

_.scanLeft("")(_+_).tail.map(s=>(s+s(0))sliding 2 count(_=="AB"))

Attempt This Online!

Nibbles, 6 bytes

`\$:/,`=+$$~

Attempt This Online!

Works with any two distinct characters.

`\$:/,`=+$$~
             For each p in
`\ :          prefixes of
  $            the input
     ,        length of
      `=  $    group runs of identical elements in
        +$      p concatenated
    /      ~  floor-divided by 2

Jelly, 7 bytes

;\ŒgẈ:2

Attempt This Online!

Port of my Nibbles answer.

;\ŒgẈ:2
;\      Concatenate all prefixes
        For each concatenated prefix:
  Œg     Group runs of equal elements
    Ẉ    Length
     :2  Floor divide by two

Ruby -nl, 40 38 bytes

a="#{a}#$_"
p (a+a[0]).scan('AB').size

Attempt This Online!

ruby -nl                     # -n loops program over each line of input
                             # -l automatically trims trailing newlines

a="       "                  # Set a to...
   #{a}                      #  a, if already set (empty string otherwise)
       #$_                   #  plus most recent line of input
  (a+a[0])                   # Get a plus its first character
          .scan('AB').size   #  and count all instances of AB
p                            # Print that number

Python, 67 65 55 bytes

lambda i,c=[]:c.extend(i)or''.join(c+c[:1]).count('AB')

Attempt This Online!

Using the default list argument to memorize the previous inputs.

edit: changed extend to append to save 2 bytes

edit: with the help of @Albert.Lang and @Jonathan Allan golfed an additional 10 bytes

Jelly, 9 8 bytes

;\µṙ1<)§

Try it online!

Something cleverer still feels possible. Takes input as shown in the test cases, since counting substring occurrences is actually pretty expensive anyways.

;\          Scan by concatenate, creating a list of each cumulative necklace.
  µ   )     For each:
   ṙ1       rotate left once, and
       §    count how many
     <      are less than in the corresponding original positions.

Perl 5 -pl, 28 bytes

$,.=$_;$_=chop.$,;$_=s/AB//g

Try it online!

Pyth, 11 bytes

m/shBsd`T._

Try it online!

Uses characters "1" and "0" for "A" and "B" respectively.

Explanation

m/shBsd`T._Q    # implicitly add Q
                # implicitly assign Q = eval(input())
         ._Q    # prefixes of Q
m               # map over lambda d
     sd         #   concatenate list of strings
   hB           #   bifurcate into [str, first_char(str)]
  s             #   concatenate list of strings
 /     `T       #   count occurrences of "10"

Swift 5.7 -enable-bare-slash-regex, 95 bytes

{var x=""
return $0.map{x+=$0
return x.ranges(of:/AB/).count+("B"==x.first&&"A"==x.last ?1:0)}}

Try it on SwiftFiddle! Without the -enable-bare-slash-regex flag, the regex literal /AB/ would be spelled #/AB/# on macOS, or try!Regex("AB") on Linux, so the flag is obvious. SwiftFiddle enables it by default on Swift 5.7 and later.

The code should be fairly straightforward: append the new element to what's been seen so far, then count the ranges that match /AB/, and check whether it starts with "B" and ends with "A".

Thunno 2, 6 bytes

ƒıJẹTc

Attempt This Online!

Uses 1 and 0, and checks for the substring 10, like Vyxal and 05AB1E.

Explanation

ƒıJẹTc  # Implicit input
ƒı      # Map over prefixes
  Jẹ    #  Join and append first character
    Tc  #  Count occurrences of "10"
        # Implicit output

05AB1E (legacy), 6 bytes

ηJεĆT¢

I/O as a list. Uses characters 1 and 0 for A and B respectively.

Uses the legacy version of 05AB1E, because the new version of 05AB1E has a bug with multi-digit integers and the count builtin ¢, so it would require an additional § after the T.

Try it online! or verify all test cases.

Explanation:

η       # Get the prefixes of the (implicit) input-list
 J      # Join each inner list together to a single string
  ε     # Map over each string:
   Ć    #  Enclose; append its first character at the end
    T¢  #  Count how many times "10" occurs in this string
        # (after which the list of counts is output implicitly as result)

Excel, 80 bytes

=MAP(SCAN("",A1#,LAMBDA(a,b,a&b)),LAMBDA(c,ROWS(TEXTSPLIT(RIGHT(c)&c,,"AB"))-1))

Input is vertical spilled range #A1.

JavaScript (ES6), 117 bytes

k=>{for(let i=1;i<=k.length;i++)console.log(((s=k.slice(0,i).join('')).match(/01/g)||[]).length+!(+s.at(-1)-~-s[0]))}

Uses 0 instead of A and 1 instead of B.

I could probably get rid of the first/last character special case by appending the first character at the end like Vyxal did using (k.slice(0,i).join('')+k[0][0]).match(/01/g) instead of (s=k.slice(0,i).join('')).match(/01/g) but I can't be bothered to rewrite my terrible explanation

Explained

// Take k ['01010', '01010']
// Convert it to s '01010'
// Then in the next loop s='0101001010'
// In s, count the occurences of 01
// Then count special case of first/last characters

// k has length N
k=>{for(let i=1;i<=k.length;i++) // Loop 'i' from 1 to N inclusive
console.log( // Output:

  (
    (s=k.slice(0,i).join('')) // Get bracelet up to current 'i'
    .match(/01/g)             // List of occurences of '01'
      ||[]                    // Default to empty list
  ).length                    // Get length
+
  !(+s.at(-1)-~-s[0]) // Is +s.at(-1)-~-s[0] equal to 0?
                      // (implicitly) convert to number

)}

But what is !(+s.at(-1)-~-s[0])?

s.at(-1) is the last element of s, and for the rest... well... I just threw a bunch of random stuff in there until it worked; please don't tell my coding teacher

With test cases

const f=

k=>{for(let i=1;i<=k.length;i++)console.log(((s=k.slice(0,i).join('')).match(/01/g)||[]).length+!(+s.at(-1)-~-s[0]))}

`
ABABA => 2
ABABA => 4
//
BA => 1
BABA => 3
BB => 3
BAAAAB => 4
//
ABABA => 2
ABABA => 4
//
BA => 1
BABA => 3
BB => 3
BAAAAB => 4
//
AB => 1
AAA => 1
B => 2
AB => 3
//
BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB => 1
A => 2
B => 2
A => 3
A => 3
B => 3
//
BABABABABABAB => 6
A => 7
`.slice(1,-1).replaceAll('A','0').replaceAll('B','1').split('\n//\n').forEach(testCase => {
    const parts = testCase.split('\n').map(x=>x.split(' => '));
    const input_ = parts.map(x=>x[0]);
    console.log('\n\nInput:',input_,'\nExpected output:');
    parts.forEach(x=>console.log(+x[1]));
    console.log('Output:');
    f(input_);
});

Vyxal, 5 bytes

¦ƛǏ₀O

Try it Online!

Uses the characters 1 and 0, checks for substring 10.

Explained

¦ƛǏ₀O­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌­
¦ƛ     # ‎⁡To each prefix of the input:
  Ǐ    # ‎⁢  Append the first character to the end
   ₀O  # ‎⁣  And count the number of instances of "10" in that
💎

Created with the help of Luminespire.

Dyalog APL, 21 bytes

{∇⍵,⍞⊣⎕←+/'AB'⍷⍵,⊃⍵}⍞­⁡​‎‎⁡⁠⁢⁢⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏⁠‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏⁠‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁤⁣‏⁠⁠⁠⁠‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏⁠‎⁡⁠⁢⁡⁢‏⁠‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁢⁣​‎‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢⁤​‎‎⁡⁠⁢‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌­
                    ⍞  # ‎⁡Take a line from standard input, and pass it to the following function:
      ⎕←               # ‎⁢  print
        +/             # ‎⁣  how many times
          'AB'         # ‎⁤  the string AB
              ⍷        # ‎⁢⁡  appears in
               ⍵,⊃⍵    # ‎⁢⁢  the string formed by concatenating the input and its first element
     ⊣                 # ‎⁢⁣  , then,
 ∇                     # ‎⁢⁤  call the same function
  ⍵,⍞                  # ‎⁣⁡  passing the input concatenated with another line from standard input
💎

Created with the help of Luminespire.

Charcoal, 19 bytes

WS«≔⁺ωιωI№⁺ω§ω⁰ABD⎚

Try it online! Link is to verbose version of code. Fully interactive version, so when run from the command line it will prompt for the next piece of necklace and output the count of ABs so far. Explanation:

WS«

Keep accepting pieces but stop when an empty piece is entered.

≔⁺ωιω

Concatenate the piece to the necklace so far.

I№⁺ω§ω⁰ABD⎚

Output the number of ABs so far.