g | x | w | all
Bytes Lang Time Link
nanPython241023T112529Z138 Aspe
nanRust241026T092412Z138 Aspe
093C GCC241110T170718Zmatteo_c
102AWK241025T213334Zxrs
017Jelly241027T191109ZUnrelate
027APL Dyalog Unicode241023T094958ZVen
036x8664 machine code241026T191340Zm90
088Python 2241024T003518ZLucenapo
02205AB1E241024T141446ZKevin Cr
075Python241025T044945ZAlbert.L
033Charcoal241023T212312ZNeil
020Vyxal241023T211325Zemanresu
021Jelly241023T184442ZJonathan
079Perl 5 n241023T175351ZXcali
060JavaScript ES10241023T092926ZArnauld
043Retina241023T091329ZNeil
043Uiua241023T103638Zmousetai

Python, 398 183 168 128 126 124 bytes

Saved 230 bytes thanks to @Malo

Saved 40 bytes thanks to @Dingus

Saved (2+2=4) bytes thanks to @ceilingcat


Golfed version. Attempt This Online!

def p(b):
 a=[];b=[0,0]+b+[0]
 for i,v in enumerate(b[2:-1]):
  n=b[i+3];p=b[i+1]
  if[~p^n,(p|n)//2,i][v]&1:a+=i,
 return a

Ungolfed version. Attempt This Online!

def process_array(input_array):
    # Use list comprehension with conditional filtering (similar to flatMap)
    result = []
    for current_index, current_value in enumerate(input_array):
        # Get the next value in the array (None if beyond array bounds)
        next_value = input_array[current_index + 1] if current_index + 1 < len(input_array) else None
        
        # Store the previous value for the next iteration
        previous_value = 0 if current_index == 0 else input_array[current_index - 1]
        
        # Determine which operation to perform based on current value
        if current_value == 0:
            # NOT of previous value XOR with next value
            # Using bitwise operators and handling None case
            next_val = 0 if next_value is None else next_value
            computed_result = (~previous_value ^ next_val)
        elif current_value == 1:
            # (previous value OR next value) divided by 2
            next_val = 0 if next_value is None else next_value
            computed_result = (previous_value | next_val) // 2
        elif current_value == 2:
            # Just return the current index
            computed_result = current_index
        else:
            computed_result = 0
        
        # Check if the least significant bit is set (result is odd)
        if computed_result & 1:
            result.append(current_index)
            
    return result

# Test cases
test_cases = [
    {"input": "101", "expected": [1]},
    {"input": "201102", "expected": [5]},
    {"input": "1012", "expected": [1, 2, 3]},
    {"input": "0", "expected": [0]},
    {"input": "20101010002", "expected": [3, 5, 8, 9]},
    {"input": "111020100102", "expected": [11]},
    {"input": "20110010201", "expected": []},
    {"input": "01102011100111100111", "expected": []},
    {"input": "20111100102011102010011", "expected": []}
]

# Run test cases
for case in test_cases:
    # Convert string to array of numbers
    input_array = [int(x) for x in case["input"]]
    
    # Process the array
    result = process_array(input_array)
    
    # Compare with expected result
    is_correct = result == case["expected"]
    
    # Output result and validation
    print(f"{result} {'✔️' if is_correct else '❌'}")

Rust, 223 220 208 200 199 194 bytes

Saved 3+12+8+1+5=29 bytes thanks to @ceilingcat

Tips:


Golfed version. Attempt This Online!

fn p(i:&[i32])->Vec<usize>{let mut r=vec![];for(x,&v)in(0..).zip(i){let(n,p)=(i.get(x+1).copied().unwrap_or(0),if x<1{0}else{i[x-1]});if match v{0=>!p^n,1=>(p|n)/2,_=>x as i32}&1>0{r.push(x)}}r}

Ungolfed version. Attempt This Online!

#![allow(warnings)]


fn process_array(input_array: &[i32]) -> Vec<usize> {
    let mut result = Vec::new();
    
    for (current_index, &current_value) in input_array.iter().enumerate() {
        // Get the next value in the array (0 if beyond array bounds)
        let next_value = input_array.get(current_index + 1).copied().unwrap_or(0);
        
        // Store the previous value for the next iteration
        let previous_value = if current_index == 0 { 0 } else { input_array[current_index - 1] };
        
        // Determine which operation to perform based on current value
        let computed_result = match current_value {
            0 => {
                // NOT of previous value XOR with next value
                (!previous_value ^ next_value)
            },
            1 => {
                // (previous value OR next value) divided by 2
                (previous_value | next_value) / 2
            },
            2 => {
                // Just return the current index
                current_index as i32
            },
            _ => 0
        };
        
        // Check if the least significant bit is set (result is odd)
        if computed_result & 1 == 1 {
            result.push(current_index);
        }
    }
    
    result
}

fn main() {
    // Define test cases as a vector of tuples (input string, expected result)
    let test_cases = vec![
        ("101", vec![1]),
        ("201102", vec![5]),
        ("1012", vec![1, 2, 3]),
        ("0", vec![0]),
        ("20101010002", vec![3, 5, 8, 9]),
        ("111020100102", vec![11]),
        ("20110010201", vec![]),
        ("01102011100111100111", vec![]),
        ("20111100102011102010011", vec![])
    ];
    
    // Run test cases
    for (input_str, expected) in test_cases {
        // Convert string to vector of numbers
        let input_array: Vec<i32> = input_str
            .chars()
            .map(|c| c.to_digit(10).unwrap() as i32)
            .collect();
        
        // Process the array
        let result = process_array(&input_array);
        
        // Compare with expected result
        let is_correct = result == expected;
        
        // Output result and validation
        println!("{:?} {}", result, if is_correct { "✔️" } else { "❌" });
    }
}

// Add tests module
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_cases() {
        let test_cases = vec![
            (vec![1, 0, 1], vec![1]),
            (vec![2, 0, 1, 1, 0, 2], vec![5]),
            (vec![1, 0, 1, 2], vec![1, 2, 3]),
            (vec![0], vec![0])
        ];

        for (input, expected) in test_cases {
            assert_eq!(process_array(&input), expected);
        }
    }

    #[test]
    fn test_empty_result_cases() {
        let test_cases = vec![
            "20110010201",
            "01102011100111100111",
            "20111100102011102010011"
        ];

        for input_str in test_cases {
            let input: Vec<i32> = input_str
                .chars()
                .map(|c| c.to_digit(10).unwrap() as i32)
                .collect();
            assert_eq!(process_array(&input), Vec::<usize>::new());
        }
    }
}

C (GCC), 98 93 bytes

f(char*x){for(int i=0,p=8;*x;p=*x++,i++)(*x&1?(x[1]|p)/2:*x&2?i:x[1]-~p)%2&&printf("%d ",i);}

Attempt This Online!

AWK, 123 117 115 102 bytes

{$0=0$0;for(i=1;i++<NF;)printf(!$i&&0~($(i-1)+$(i+1))%2||1~$i&&(2~$(i-1)||2~$(i+1))||2~$i&&i%2)?i-2:x}


BEGIN{FS=X}{$0=0$0;for(i=2;i<=NF;i++)printf(!$i&&0~($(i-1)+$(i+1))%2||1~$i&&(2~$(i-1)||2~$(i+1))||2~$i&&i%2)?i-2:x}

Try it online!

{for(i=2;i<=split(0$0,a,X);i++)printf(!a[i]&&0~(a[i-1]+a[i+1])%2||1~a[i]&&(2~a[i-1]||2~a[i+1])||2~a[i]&&i%2)?i-2FS:x}


{for(i=2;i<=split(0$0,a,X);i++)printf(!a[i]&&0~(a[i-1]+a[i+1])%2||1~a[i]&&(2~a[i-1]||2~a[i+1])||2~a[i]&&0~(i-1)%2)?i-2FS:x}

Thank you, emanresu A!

Jelly, 19 17 bytes

ŻṖ»Ịż+ʋḊj"J⁸ị"ḂCT

Try it online!

Program or function taking a list of [0,1,2] blocks and outputting a list of 1-indices. (The test harness converts to 0-indices for convenience.)

 Ṗ                  With the input without its last element
Ż                   and with a zero prepended
      ʋ             on the left
       Ḋ            and the input without its first element on the right,
    ż               pair corresponding
  »Ị                maxima-not-being-2
     +              and sums.
  »  + Ḋ            (Both give the last element off the end unchanged.)
       j"J          Insert each pair's 1-index between its elements.
          ⁸ị"       Modular 1-index each input element into its triple:
    ż+ j" ⁸ị"       0 maps to the last element, the sum;
  »Ịż  j" ⁸ị"       1 maps to the first element, the lack of 2;
    ż  j"J⁸ị"       2 maps to the second/middle element, the 1-index.
               T    Return the 1-indices of
             ḂC     even results. 

Since Jelly natively uses 1-indexing, the legal positions for a 2 are actually odd indices, so they can be checked uniformly with the sums for 0, as well as the Boolean result of each 1's neighborhood containing a 2.

APL (Dyalog Unicode), 47 43 27 bytesSBCS

⍸⊢∘(⊃2∘⌷↓2|+/,⌈/)⌺3<⊢≤2∨⍳∘⍴

Creates a 3-cases stencil around each elements (those get padded with zeroes). Index into an array computing whether the sum of the 3 is odd (0 being the identity element here) for 0, and for 1 checks if any element is 2 (we know the middle one is 1). No check done for 2 at this stage (index not available at point). Then a second checks is ORed with the first one, we compute a range of the indices, and keep those for positions of 2.

Once we have a boolean vector, use ⍸ to get the truthy positions.

-4 thanks to @asherbhs. -16 thanks to @att

Try it online!

x86-64 machine code, 36 bytes

31 C0 99 EB 18 34 01 8D 0C 90 32 4E 01 24 02 08 C1 AC 66 0F A3 C1 73 03 89 17 AF FF C2 38 26 75 E4 57 58 C3

Try it online!

Following the standard calling convention for Unix-like systems (from the System V AMD64 ABI), this takes

and returns in RAX the address of the end of the output.

In assembly:

f:  xor eax, eax; cdq    # Initialise EAX and EDX to 0.
                 # EAX will hold the previous material, EDX the current index.
    jmp c        # Jump to the loop test, to handle length-0 input correctly.
r:  xor al, 1    # Invert the low bit of EAX. (AL is its low byte.)
    lea ecx, [rdx*4+rax] # Set ECX to this value.
     # (RDX and RAX are the 64-bit versions of EDX and EAX.)
     # The goal is to construct a value in ECX such that
     #  its nth bit is 1 iff material n is unstable here.
     # Multiplying the index by 4 puts its low bit at position 2.
    xor cl, [rsi+1]      # Exclusive-or the next material into that value.
     # Now, bit 0 is the XOR of both low bits and 1, which is correct.
     # Bit 1 is the XOR of both materials' bit 1 (which is 1 only for 2),
     #  which is close, but it should be the inclusive or.
    and al, 2    # Mask the previous material to leave only bit 1.
    or cl, al    # OR in that value, fixing the case of both having bit 1.
    lodsb        # Load a byte from the string into AL, advancing the pointer.
    bt cx, ax    # Set CF to the bit in CX indexed by its low 4 bits.
     # (CX is the 16-bit version of ECX, so that only 4 bits of EAX are used;
     #  the next bit is a 1, as ASCII digits begin at 48=0x30.)
    jnc s        # Jump if CF=0.
    mov [rdi], edx   # Put the index into the output array.
    scasd            # Advance the output pointer with an unused comparison.
s:  inc edx      # Add 1 to the index.
c:  cmp [rsi], ah    # Compare the next input byte with AH,
                     #  which is the second-lowest byte of EAX, which is 0.
    jne r            # Jump back, to repeat, if they are not equal.
    push rdi; pop rax    # Put the final output pointer into RAX for returning.
    ret              # Return.

Python 2, 104 88 bytes

b=input()+[4]
for i,j in enumerate(b):l=b[i-(i>0):i+2];print`i`*[~sum(l)&1,2in l,i&1][j]

Try it online!

The program terminates with an error after giving the correct output.

05AB1E, 22 bytes

0.øü3εOÈy2åNÉ)yÅsè}ƶ0K

Input as a list of digits; output as a list of 1-based indices.

Try it online or verify all test cases.

Or alternatively:

õªćsv©y)DOÈs2åNÉ)®è–®y

Input can be a string or a list of digits; prints the invalid 0-based indices on separated newlines.

Try it online or verify all test cases.

Explanation:

0.ø             # Surround the (implicit) input-list with leading/trailing 0
   ü3           # Pop and get all overlapping triplets of this list
     ε          # Map over each triplet:
      O         #  Sum the triplet
       È        #  Check whether this sum is even
      y         #  Push the triplet again
       2å       #  Pop and check whether it contains a 2
      N         #  Push the 0-based map-index
       É        #  Check whether this index is odd
         )      #  Wrap all three checks into a list
          y     #  Push the triplet again
           Ås   #  Pop and leave its middle
             è  #  Use that to 0-based index into the earlier list
     }ƶ         # After the map: multiple all checks by their 1-based index
       0K       # Then remove all 0s
                # (after which this is output implicitly as result)
õª              # Append an empty string "" to the (implicit) input
                # (which also converts it to a list if it wasn't already)
  ć             # Extract head; push remainder-list and first item separately to
                # the stack
   s            # Swap so the remainder-list is at the top of the stack
    v           # Pop and loop over each of its values `y`:
     ©          #  Store the top of the stack in variable `®` (without popping)
      y         #  Push the current loop-value `y`
       )        #  Wrap all items on the stack into a list
                #  (2 items in the first iteration; 3 in later iterations)
        D       #  Duplicate this pair or triplet
         O      #  Sum it together
          È     #  Check whether this sum is even
        s       #  Swap so the pair/triplet is at the top again
         2å     #  Pop and check whether it contains a 2
        N       #  Push the 0-based map-index
         É      #  Check whether this index is odd
           )    #  Wrap all three checks into a list
            ®è  #  Use `®` to 0-based index into this triplet
              – #  If it's truthy: print the current loop-index with newline
     ®y         #  Push values `®` and `y` for the next iteration
                # (if the input-list is valid and no indices were printed at the
                # end of the loop, it'll implicitly print the first pushed value
                # with trailing newline instead, which is the empty string "")

Python, 75 bytes

-2 thanks to @Jonathan Allan.

lambda l:[j for j,c in enumerate(l)if[~sum(L:=[0,*l][j:j+3]),2in L,j][c]%2]

Attempt This Online!

Python, 77 bytes

lambda l:[j for j,c in enumerate(l)if[~sum(L:=[0,*l][j:j+4:2]),2in L,j][c]%2]

Attempt This Online!

Charcoal, 33 bytes

I⌕AEEθ✂⪫00θκ⁺³κ¹&¹§⟦⊕Σι⁼2⌈ικ⟧§θκ¹

Try it online! Link is to verbose version of code. Explanation: Port of @Arnauld's JavaScript answer.

     θ                              Input string
    E                               Map over characters
        00                          Literal string `00`
       ⪫                            Joined with
          θ                         Input string
      ✂        ¹                    Sliced from
           κ                        Current index to
              κ                     Current index
            ⁺                       Plus
             ³                      Literal integer `3`
   E                                Map over windows
                      ι             Current window
                     Σ              Sum of digits
                    ⊕               Incremented
                          ι         Current window
                         ⌈          Maximum
                       ⁼            Equals
                        2           Literal string `2`
                           κ        Current index
                   ⟦        ⟧       Make into list
                  §                 Indexed by
                              θ     Input string
                             §      Indexed by
                               κ    Current index
                &                   Bitwise And
                 ¹                  Literal integer `1`
 ⌕A                                 Find indices of
                                ¹   Literal integer `1`
I                                   Cast to string
                                    Implicitly print

Vyxal, 20 bytes

0pǏ3lƛ∑₂n2c¥&¬W;¨£iT

Try it Online!

0pǏ                  # Prepend and append a 0
   3lƛ         ;     # Over the subarrays of length 3...
              W      # Construct a list of
      ∑₂             # 0 -> Sum even
        n2c          # 1 -> Contains a 2
           ¥&¬       # 2 -> Whether the current index is even
                ¨£i  # Index the original values into each list
                   T # And get the truthy indices of this.

Jelly, 21 bytes

2e;SḂj0Ḋƭ
Ø0jÇ3Ƥ⁸ịƑ"T

A full program that accepts the list of blocks (integers from \$\{0,1,2\}\$) and prints the list of 1-indexed indices of erroneous blocks.

Try it online!

Or see the test-suite. (This calls the code twice for each input just to ensure that the ƭ is in the right state after an odd-length input (hence the "full program" qualification above))

How?

2e;SḂj0Ḋƭ - Helper link: three-slice of blocks, T
2e        - does two exist in {T}?
   S      - sum {T}
  ;       - concatenate -> [2 in T?, sum T]
    Ḃ     - mod two -> [2 in T? % 2, sum T % 2]  (Note: 2 in T? % 2 = 2 in T)
        ƭ - on successive calls alternate between:
      0   -   zero
       Ḋ  -   dequeue {T}
     j    - join -> [2 in T?, 0 / 2nd element, ...junk...,  Sum T % 2]
                       ^        ^                             ^
                    (1-case   2-case                        0-case)

Ø0jÇ3Ƥ⁸ịƑ"T - Main Link: list of {0,1,2}, Blocks
Ø0          - [0,0]
  j         - join with {Blocks} -> 0-padded-blocks
    3Ƥ      - for each three-slice, from left to right:
   Ç        -   call the helper link -> LookupArray
      ⁸     - chain's left argument -> Blocks
         "  - zip with - f(Block, respective LookupArray):
        Ƒ   -   is {Block} invariant under?:
       ị    -     {Block} index into {LookupArray} (1-indexed & modular)
          T - truthy indices

Perl 5 -n, 79 bytes

($&-2||pos()%2)&&say pos while /2\K1|1(?=2)|([02]|^\K)0(?=[20]|$)|1\K0(?=1)|2/g

Try it online!

Output is 1-indexed

JavaScript (ES10), 60 bytes

Expects an array of digits.

a=>a.flatMap(p=(v,i)=>[~p^(q=a[i+1]),(p|q)/2,i][p=v]&1?i:[])

Try it online!

Commented

a =>                // a[] = input array
a.flatMap(p =       // initialize p to a zero'ish value
(v, i) =>           // for each value v at index i:
  [                 //   lookup array:
    ~p ^            //     0: (NOT predecessor) XOR
    (q = a[i + 1]), //        successor
    (p | q) / 2,    //     1: (predecessor OR successor) / 2
    i               //     2: just use i
  ][p = v]          //   get the result at index v and copy v to p
  & 1               //   test the LSB
  ?                 //   if it's set:
    i               //     return the position
  :                 //   else:
    []              //     discard this entry
)                   // end of flatMap()

Retina, 55 48 43 bytes

^|$
0
Iv`101|[02]0[02]|21|.12|(?<!^(..)*).2

Try it online! Outputs unstable positions on separate lines but link is to test suite that joins on commas for convenience. Explanation: The skyscraper is wrapped in 0s for convenience, then I command automatically lists the positions of the matches, while the v modifier allows the matches to overlap, thus avoiding forward lookahead, so it just remains to match the unstable positions, starting at the now previous character, which is at the desired position.

Uiua, 43 chars

⊚↥⊃(≡(⨬(¬◿2/+|/↥⌕2|0)⊸⊡1)◫3↻1⊂0_0|↧◿2⇡⧻⤙=2)

Pad Link