g | x | w | all
Bytes Lang Time Link
04605AB1E250620T134608ZKevin Cr
051oK250620T122123Zzgrep
317Befunge93171125T143250ZJo King
015MATL171123T174331ZLuis Men
181JavaScript ES6171124T015900Zyetirs
247Python 2171124T094349ZTFeld
114JavaScript ES6171124T082901ZArnauld
066J171124T051413ZJonah
096Wolfram Language Mathematica171124T025604ZMisha La

05AB1E, 46 bytes

˜εQ©˜ƶ®gäΔ4F¬ašøí}2Fø€ü3}®*εε˜ŽqÆSèà]ε˜Ù0Kg}PΘ

Input as a matrix of characters.
Outputs 1/0 for truthy/falsey respectively. Could be -1 byte if the default truthy/falsey wasn't overwritten, with 1 for truthy and \$\geq2\$ for falsey.

Try it online or verify all test cases.

Explanation:

The flood-fill section ˜ƶ®gäΔ4F¬ašøí}2Fø€ü3}®*εε˜ŽqÆSèà] is similar as I've done in multiple other challenges (e.g. this answer for the Max Island Area challenge).

˜             # Flatten the (implicit) input-matrix to a list of characters
 ε            # Map over each character:
  Q           #  Equals check with the values in the (implicit) input-matrix;
              #  will mark all locations of the character as 1, and other characters as 0
   ©          #  Store this matrix of bits in variable `®` (without popping)
    ˜         #  Flatten it
     ƶ        #  Multiply each value by its 1-based index
      ®g      #  Push the length (amount of rows) of matrix `®`
        ä     #  Convert the list back to a matrix with that many rows
  Δ           #  Loop until the result no longer changes to flood-fill the matrix:
              #   Add a border of 0s around the matrix:
   4F     }   #    Loop 4 times:
     ¬        #     Push the first row of the current matrix (without popping)
      a       #     Convert all values to 0s (with an is_letter check)
       š      #     Prepend that row of 0s to the matrix
        øí    #     Rotate once clockwise:
        ø     #      Zip/transpose; swapping rows/columns
         í    #      Reverse each inner list
   2Fø€ü3}    #   Then get all overlapping 3x3 blocks:
   2F    }    #    Loop 2 times:
     ø        #     Zip/transpose; swapping rows/columns
      €       #     Map over each inner row:
       ü3     #      Get all overlapping triplets
   ®*         #   Multiply this matrix of 3x3 blocks by bit-matrix `®` to fix the 0s
   εε         #   Nested map over each 3x3 block:
     ˜        #     Flatten the 3x3 block to a list of 9 values
      ŽqÆ     #     Push compressed integer 13457
         S    #     Convert it to a list of digits: [1,3,4,5,7]
          è   #     Get the values at those indices
           à  #     Pop and push the maximum
]             # Close the nested map; changes-loop; and outer map at once
 ε            # Open a new map again:
  ˜           #  Flatten the now flood-filled matrix
   Ù          #  Uniquify this list
    0K        #  Remove all 0s
      g       #  Pop and push the length (the amount of connected groups)
 }P           # After the map: take the product of this list
   Θ          # Distinct the falsey results with an ==1 check (1 if 1; 0 otherwise)
              # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why ŽqÆ is 13457.

oK, 51 bytes

{&/3>{#?,/(4(+|{(y%y)*x|y}\')/)/x*+\'+\x}'x=/:?,/x}

Try it online!


{                                                 } /function of x:
                                          x=/:?,/x  / binary matrices per letter
     {                                  }'          / for each matrix x:
                                  +\'+\x            /  choose non-decreasing
                                x*                  /  numbers where non-zero
          (                   )/                    /  repeat until fixed-point:
           4(+|             )/                      /   for each direction:
               {         }\'                        /    scan along direction
                      x|y                           /    with max function
                (y%y)*                              /    zero or nan -> nan
      #?,/                                          /  count unique entries
 &/3>                                               / all(less than 3)

Befunge-93, 317 bytes

Edit: Fixed for proper byte-count. Also could be golfed further

93+:10pv  +93p01+1g01_  v@.1<
gp00g1+>00p~1+:93+`!#^_1-00g10
50p93+:vv_v#!:gg03:p02:<>40p#
!`g01: <>\ 1+:vvp05:+<@^p03_^#
v93$_v# !- g00<4v04g<^1<vp06:<
>+\!\>\ 3v> 40v0>g-v^<.g>:70vp
07_v#:<^ >#+0# g#\<  10\v4gg<^
!#v _$^  g03p <\ v1_#:^5>0g  -
   <    ^ g02p1< >-:#^_^#:g05
-1<   ^p\g06\0\+1:\g06\-1:\g06:\+1g06:g07

Prints 1 as the truthy, 0 as the falsey

Try It Online

Here's a visualisation of the path the pointer takes

Fancy Colours!

Note: this is for an old version


How it works

Here's some quick and dirty pseudocode

a = 2Darray() # from 12,12 down and to the right
arrayLocation = 12
x = arrayLocation #stored at 0,0
y = arrayLocation #stored at 1,0
i = input()       #stored in the stack
while (i != 0):
    if (i == 10):
        y++
        x = init
    else
        a[x][y] = i
        x++
    i = input

new.x = init    #stored at 2,0
new.y = init    #stored at 3,0

currentChar = 0    #stored at 4,0
chars = array()    #stored at 1,1 onwards
charnum = 0        #stored 5,0
ToCheck = array()  #stored in the stack

current.x = null   #stored at 6,0
current.y = null   #stored at 7,0

while (new.y < y):
    if (a[new] != 0)
        currentChar = a[new]
        toCheck[] = new
        while (toCheck)
            current = toCheck.pop()
            if (a[current] == currentChar)
                toCheck.append(adjacent(current))
                a[current] = 0
        foreach (chars as char)
            if (char == currentChar)
                return 0
        charNum++
        chars[charNum] = char
    new.x++
    if (new.x > x)
        new.x = init
        new.y++

return 1

Basically, after storing the input, it goes through the whole thing, checking each space. When it finds a space with a character in it it adds the coordinates to the stack. Then it checks the spaces around it for the same character recursively, setting each space to 0. When it has exhausted that character's section, it checks whether that character has already had a section. If so, return 0. If not, add it to the array of characters. Once it has gone through the whole grid with no duplicates, it returns 1.

For people familiar with Befunge, here's a spaced out version of the code

96+:10p    v    +69p01+1g01_v
`+96:+1~p00<+1g00pg01g00-1_^#
v                           <
>40p50p96+:v                ^
v    @.1<  >
>:10g `#^_30p:20p:30gg:#v_$>1+:00g-!#v_0   >30g+
v                       <  ^         >$96+1^
>40p30gv                   ^
       >:!#v_70p:60p:70gg40 g-!#v_$>
           v               ^     > ^
1:\g06\+1:g 07\g07\-1:\g07\ +1: <^p\g06\0\-
v          <               ^
>50gv   >5\g1+:50p40g\1p20g^
    >:!#^_:1g40g-!#v_1-
                   >0.@

MATL, 16 15 bytes

1e"G@=4&1ZI1>vzg

Input is a 2D char array (with rows separated by ;). Output is 0 if input qualifies, or 1 otherwise.

Try it online! Or verify all test cases.

Explanation

The code essentialy checks if each char in the input has only one connected component, considering 4-connectivity (that is, no diagonals).

Repeated chars are processed repeatedly (which is golfier than deduplicating).

1e       % Implicit input. Reshape into a row vector of chars
"        % For each char
  G      %   Push input again
  @      %   Push current char
  =      %   Equal (element-wise)? Gives a matrix of zeros and ones, where one
         %   represents the presence of the current char
  4      %   Push 4. This will indicate 4-connectivity
  &1ZI   %   Matrix with labels of connected componnents. Inputs are a number (4)
         %   to indicate connectivity, and a binary matrix. The output is a matrix
         %   the same size as the input where each connected componnent of ones
         %   in the input is replaced by a different integer starting at 1
  1>     %   Greater than 1 (element-wise)? The result is a matrix. If the result 
         %   is true for some entry the input doesn't qualify
  v      %   Concatenate vertically with results from previous iterations
  z      %   Number of nonzero/true values
  g      %   Logical. Converts nonzero to true
         % Implicit end. Implicit display. False / true are displayed as 0 / 1

JavaScript (ES6), 181 bytes

(d,o={})=>{f=(i,j,c,l=d[i])=>{if(c&&l&&l[j]==c){l[j]='';f(i-1,j,c);f(i+1,j,c);f(i,j-1,c);f(i,j+1,c);o[c]=1}};d.map((e,i)=>e.map((c,j)=>o[c]||f(i,j,c)));return!d.some(e=>e.join(''))}

Whenever a new color tile is found, fill the connected ones with empty strings. If the mat is properly grouped by colors, all tiles should be filled with empty strings.

Test Code

const t =
(d,o={})=>{f=(i,j,c,l=d[i])=>{if(c&&l&&l[j]==c){l[j]='';f(i-1,j,c);f(i+1,j,c);f(i,j-1,c);f(i,j+1,c);o[c]=1}};d.map((e,i)=>e.map((c,j)=>o[c]||f(i,j,c)));return!d.some(e=>e.join(''))}
;

const mat = s=>s.split('\n').filter(l=>l).map(l=>l.split(''));
console.log('true?', t(mat(`
A
`)));
console.log('true?', t(mat(`
AB
AB
`)));
console.log('false?', t(mat(`
AB
BA
`)));
console.log('true?', t(mat(`
ABCDE
`)));
console.log('false?', t(mat(`
ABCDC
`)));
console.log('true?', t(mat(`
**::dd22
***:d222
*:::::22
`)));
console.log('false?', t(mat(`
$$$%%%&&
$$%%&&&&
&&$$$%&&
`)));
console.log('true?', t(mat(`
AABBCDDDE
ABBCCCDEE
ABCCCCDDE
AACCCDDEE
AAAACCCCE
AAAAAACCC
`)));
console.log('true?', t(mat(`
AABB
ABBA
AAAA
`)));
console.log('true?', t(mat(`
AAAB
AAAA
AAAA
`)));

Python 2, 247 bytes

def f(a):
 b=map(list,a.split('\n'));l=len(b[0])
 for c in set(a):i=a.find(c);g(b,i/l,i%l,c)
 print all(set(l)<={0}for l in b)
def g(a,i,j,c):
 if len(a)>i>-1<j<len(a[0])and a[i][j]==c:
	for x,y in(0,1),(0,-1),(1,0),(-1,0):g(a,i+x,j+y,c);a[i][j]=0

Try it online!

JavaScript (ES6), 114 bytes

Takes input as an array of strings. Returns 0 or 1.

a=>(C={},F=x=>!C[c=a[y][x]]|(g=v=>(a[y+v]||[])[x]==c)(-1)|g(1)|g(0,x--)|g(0,x+=2)?a[y+=!c]?F(C[c]=c?x:0):1:0)(y=0)

Test cases

let f =

a=>(C={},F=x=>!C[c=a[y][x]]|(g=v=>(a[y+v]||[])[x]==c)(-1)|g(1)|g(0,x--)|g(0,x+=2)?a[y+=!c]?F(C[c]=c?x:0):1:0)(y=0)

console.log(f([ // 1
  "A"
]))

console.log(f([ // 1
  "AB",
  "AB"
]))

console.log(f([ // 0
  "AB",
  "BA"
]))

console.log(f([ // 1
  "ABCDE"
]))

console.log(f([ // 0
  "ABCDC"
]))

console.log(f([ // 1
  "**::dd22",
  "***:d222",
  "*:::::22"
]))

console.log(f([ // 0
  "$$$%%%&&",
  "$$%%&&&&",
  "&&$$$%&&"
]))

console.log(f([ // 1
  "AABBCDDDE",
  "ABBCCCDEE",
  "ABCCCCDDE",
  "AACCCDDEE",
  "AAAACCCCE",
  "AAAAAACCC"
]))

console.log(f([ // 1
  "AABB",
  "ABBA",
  "AAAA"
]))

console.log(f([ // 1
  "AAAB",
  "AAAA",
  "AAAA"
]))

Formatted and commented

a => (                            // given an array of strings a
  C = {},                         // C = object holding encountered characters
  F = x =>                        // F = recursive function taking x:
    !C[c = a[y][x]]               //   c = current character; is it a new one?
    | (g = v =>                   //   g = helper function taking v
        (a[y + v] || [])[x] == c  //       and testing whether a[y + v][x] == c
      )(-1)                       //   test a[y - 1][x]
    | g(1)                        //   test a[y + 1][x]
    | g(0, x--)                   //   test a[y][x - 1]
    | g(0, x += 2) ?              //   test a[y][x + 1]; if at least one test passes:
      a[y += !c] ?                //     increment y if c is undefined; if a[y] exists:
        F(C[c] = c ? x : 0)       //       update C, update x and do a recursive call
      :                           //     else:
        1                         //       all characters have been processed -> success
    :                             //   else:
      0                           //     invalid character detected -> failure
)(y = 0)                          // initial call to F, starting with x = y = 0

J, 66 bytes

c=.1=+/@,+.]-:]*[:*@+/((,|."1)0,.1 _1)&(|.!.0)
[:*/[:c"2[="_ 0~.@,

c defines a verb that tells you if a matrix of ones and zeros is connected. It treats singleton ones as a special case of true. Otherwise it takes an orthogonal neighbor count of every cell, then the signum of that count, then multiplies that with the original matrix: if that product equals the original matrix, then it's connected.

The neighbor count is achieved by shifting in all 4 directions, then summing. The 4 direction shift is achieved using the "x-arg can by a table" feature of rotate/shift |.

Finally, the answer itself achieved by creating a ones/zeros matrix for every unique ~. element of the input, and then ensuring that all of those matrices are connected. This is the verb in the second line.

Try it online!

Wolfram Language (Mathematica), 96 bytes

And@@(ConnectedGraphQ@Subgraph[GridGraph@Dimensions[t],Tr/@Position[c,#]]&/@(c=Join@@(t=#)))&

Try it online!

Takes input as a 2D list of characters: for example, {{"A","B"},{"C","D"}}.

The character is \[Transpose].

How it works

For each character c in the input, takes the Subgraph of the GridGraph of the same Dimensions as the input which corresponds to every Position in which c occurs, and checks if it's a ConnectedGraphQ.