text:
Remove duplicates from a String
Inspired by this unassuming StackOverflow question.
The idea is simple; given a String and an array of Strings, remove any instances of words in the array (ignoring case) from the input String other than the first, along with any additional whitespace this may leave. The words must match entire words in the input String, and not parts of words.
e.g. "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", ["cat", "mat"] should output "A cat called matt sat on a mat and wore a hat A called matt sat on a and wore a hat"
Input

Input can be taken as either a String, and an array of Strings or an array of Strings where the input String is the first element. These parameters can be in either order.
The input String may not be taken as a list of space-delimited Strings.
The input String will have no leading, trailing or consecutive spaces.
All input will only contain characters [A-Za-z0-9] with the exception of the input String also including spaces.
The input array may be empty or contain words not in the input String.

Output

The output can either be the return value from a function, or printed to STDOUT
The output must be in the same case as the original String

Test cases
the blue frog lived in a blue house, [blue] -> the blue frog lived in a house
he liked to read but was filled with dread wherever he would tread while he read, [read] -> he liked to read but was filled with dread wherever he would tread while he
this sentence has no matches, [ten, cheese] -> this sentence has no matches
this one will also stay intact, [] -> this one will also stay intact
All the faith he had had had had no effect on the outcome of his life, [had] -> All the faith he had no effect on the outcome of his life
5 times 5 is 25, [5, 6] -> 5 times is 25
Case for different case, [case] -> Case for different
the letters in the array are in a different case, [In] -> the letters in the array are a different case
This is a test Will this be correct Both will be removed, [this,will] -> This is a test Will be correct Both be removed

As this is code golf, lowest byte count wins!

R, 84 bytes
function(s,w,S=el(strsplit(s," ")),t=tolower)cat(S[!duplicated(x<-t(S))|!x%in%t(w)])

Try it online!
Less than 100 bytes on a string challenge that's not also kolmogorov-complexity?
Explanation:
After we break up the string into words, we need to exclude those that are

duplicates and
in w

or alternatively, turning that on its head, keeping those that are

the first occurrence of a word OR
not in w.

duplicated neatly returns logical indices of those that are not the first occurrence, so !duplicated() returns indices of those which are first occurrences, and x%in%w returns logical indices for x of those which are in w. Neat.

Java 8, 117 110 bytes
a->s->{for(String x:a)for(x="(?i)(.*"+x+".* )"+x+"( |$)(.*)";s.matches(x);s=s.replaceAll(x,"$1$3"));return s;}

Explanation:
Try it online.
a->s->{                // Method with String-array and String parameters and String return
  for(String x:a)      //  Loop over the input-array
    for(x="(?i)(.*"+x+".* )"+x+"( |$)(.*)";
                       //   Regex to match
        s.matches(x);  //   Inner loop as long as the input matches this regex
      s=s.replaceAll(x,"$1$3"));
                       //    Replace the regex-match with the 1st and 3rd capture groups
  return s;}           //  Return the modified input-String

Additional explanation for the regex:
(?i)(.*"+x+".* )"+x+"( |$)(.*)   // Main regex to match:
(?i)                             //  Enable case insensitivity
    (                            //  Open capture group 1
     .*                          //   Zero or more characters
       "+x+"                     //   The input-String
            .*                   //   Zero or more characters, followed by a space
               )                 //  End of capture group 1
                "+x+"            //  The input-String again
                     (           //  Open capture group 2
                       |$        //   Either a space or the end of the String
                         )       //  End of capture group 2
                          (      //  Open capture group 3
                           .*    //   Zero or more characters
                             )   //  End of capture group 3

$1$3                             // Replace the entire match with:
$1                               //  The match of capture group 1
  $3                             //  concatted with the match of capture group 3

MATL, 19 18 bytes
"Ybtk@kmFyfX<(~)Zc

Inputs are: a cell array of strings, then a string.
Try it online! Or verify all test cases.
How it works
"        % Take 1st input (implicit): cell array of strings. For each
  Yb     %   Take 2nd input (implicit) in the first iteration: string; or
         %   use the string from previous iteration. Split on spaces. Gives
         %   a cell array of strings
  tk     %   Duplicate. Make lowercase
  @k     %   Push current string from the array taken as 1st input. Make
         %   lowercase
  m      %   Membership: gives true-false array containing true for strings
         %   in the first input argument that equal the string in the second
         %   input argument
  F      %   Push false
  y      %   Duplicate from below: pushes the true-false array again
  f      %   Find: integer indices of true entries (may be empty)
  X<     %   Minimum (may be empty)
  (      %   Assignment indexing: write false in the true-false array at that
         %   position. So this replaces the first true (if any) by false
  ~      %   Logical negate: false becomes true, true becomes false
  )      %   Reference indexing: in the array of (sub)strings that was
         %   obtained from the second input, keep only those indicated by the
         %   (negated) true-false array
  Zc     %   Join strings in the resulting array, with a space between them
         % End (implicit). Display (implicit)

Perl 5, 49 bytes
@B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F

Try it online!
Saved 9 (!!) bytes thanks to @TonHospel!

This seems to fail for This is a test Will this be correct Both will be removed + this will. The second two words are correctly removed, but it also removed the be after the second will for some reason.

@KevinCruijssen Hmmm, I can see why that's happening at the moment. I'll try and take s proper look at lunch tomorrow, but I've fixed for now at a cost of +4. Thanks for letting me know!

For 49: @B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F

@TonHospel Ahh, spent a while trying to get lc being called without parens. Awesome! And using a regex against the array is much better, Thank you! I struggle to remember all your tips!

Pyth, 27 bytes
jdeMf!}r0eT@mr0dQmr0dPT._cz

Try it online
Explanation
jdeMf!}r0eT@mr0dQmr0dPT._cz
                          z  Take the string input.
                       ._c   Get all the prefixes...
    f    eT@                 ... which end with something...
     !}         Q    PT      ... which is not in the input and the prefix...
       r0   mr0d mr0d        ... case insensitive.
jdeM                         Join the ends of each valid prefix.

I'm sure the 10 bytes for case insensitive check can be reduced, but I don't see how.

Stax, 21 bytesCP437
åìøΓ²¬$M¥øHΘQä~╥ôtΔ♫╟

25 bytes when unpacked,
vjcm[]Ii<;e{vm_]IU>*Ciyj@

The result is an array. The convenient output for Stax is one element per line.
Run and debug online!
Explanation
vj                           Convert 1st input to lowercase and split at spaces,
  c                          Duplicate at the main stack
   m                         Map array with the rest of the program
                                 Implicitly output
    []I                      Get the first index of the current array element in the array
       i<                    Test 1: The first index is smaller than the iteration index
                                 i.e. not the first appearance
         ;                   2nd input
          {vm                Lowercase all elements
             _]I             Index of the current element in the 2nd input (-1 if not found)
                U>           Test 2: The index is non-negative
                                 i.e. current element is a member of the 2nd input
                  *C         If test 1 and test 2, drop the current element
                                 and go on mapping the next
                    iyj@     Fetch the corresponding element in the original input and return it as the mapped result
                                 This preserves the original case

Perl 6, 49 bytes
->$_,+w{~.words.grep:{.lc∉w».lc||!(%){.lc}++}}

Test it
Expanded:
->              # pointy block lambda
  $_,           # first param ｢$_｣ (string)
  +w            # slurpy second param ｢w｣ (words)
{

  ~             # stringify the following (joins with spaces)

  .words        # split into words (implicit method call on ｢$_｣)

  .grep:        # take only the words we want

   {
     .lc        # lowercase the word being tested
     ∉          # is it not an element of
     w».lc      # the list of words, lowercased

     ||         # if it was one of the words we need to do a secondary check

     !          # Boolean invert the following
                # (returns true the first time the word was found)

     (
       %        # anonymous state Hash variable
     ){ .lc }++ # look up with the lowercase of the current word, and increment
   }
}

Perl 5, 50 48 bytes
Includes +1 for -p
Give the target string followed by each filter word on separate lines on STDIN:
perl -pe '$"="|";s%\b(@{[<>]})\s%$&x!$v{lc$1}++%iegx;chop';echo
This is a test Will this be correct Both will be removed
this
will
^D
^D

The chop is only needed to fix the trailing space in case the last word gets removed
Just the code:
$"="|";s%\b(@{[<>]})\s%$&x!$v{lc$1}++%iegx;chop

Try it online!

JavaScript (ES6), 98 bytes
s=>a=>s.split` `.filter(q=x=>(q[x=x.toLowerCase()]=eval(`/\\b${x}\\b/i`).test(a)<<q[x])<2).join` `

K4, 41 bytes
Solution:
{" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}

Examples:
q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat";("cat";"mat")]
"A cat called matt sat on a mat and wore a hat A called matt sat on a and wore a hat"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["Case for different case";enlist "case"]
"Case for different"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["the letters in the array are in a different case";enlist "In"]
"the letters in the array are a different case"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["5 times 5 is 25";(1#"5";1#"6")]
"5 times is 25"

Explanation:
Split on whitespace, lowercase both inputs, look for matches, remove all but the first occurrence, join the string back together.
{" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x} / the solution
{                                       } / lambda with implicit x & y args
                                  " "\:x  / split (\:) on whitespace " "
                                x:        / save result as x
                               _          / lowercase x
                          ~/:\:           / match (~) each right (/:), each left (\:)
                      (_y)                / lowercase y
                   &:'                    / where (&:) each ('), ie indices of matches
                1_'                       / drop first of each result
              ,/                          / flatten
            y:                            / save result as y
         y@>                              / descending indices (>) apply (@) to y
      x_/                                 / drop (_) from x
 " "/:                                    / join (/:) on whitespace " "

JavaScript ES6, 78 Bytes
f=(s,a,t={})=>s.split` `.filter(w=>a.find(e=>w==e)?(t[w]?0:t[w]=1):1).join` `

How it works:
f=(s,a,t={})=> // Function declaration; t is an empty object by default
s.split` ` // Split the string into an array of words
.filter(w=> // Declare a function that, if it returns false, will delete the word
  a.find(e=>w==e) // Returns undeclared (false) if the word isn't in the list
  ?(t[w]?0 // If it is in the list and t[w] exists, return 0 (false)
    :t[w]=1) // Else make t[w] exist and return 1 (true)
  :1) // If the word isn't in the array, return true (keep the word for sure)
.join` ` // Rejoin the string

Welcome to PPCG! Since you're not using the function name f for a recursive call, an unnamed function would also be a valid submission, so you can save two bytes by dropping the f=.

Welcome to PPCG! Sadly this fails when different cases are involved.

If it wasn't for that, you could get this down to 67 bytes

@MartinEnder Thanks for the tip!

@Shaggy using the input array as the object is an interesting idea I hadn't thought of. I'll try and fix the case problem.

JavaScript (Node.js), 75 bytes
f=(s,a)=>a.map(x=>s=s.replace(eval(`/\\b${x}\\b */ig`),s=>i++?"":s,i=0))&&s

Try it online!

As this is not a recursive function, you don't need to include the f= in your byte count. You can also save a byte by currying the parameters, replacing (s,a)=> with s=>a=> and then calling the function with f(s)(a).

@Shaggy yes, but i really mind about golfing the definition of the function because the main deal is golfing the body. but thx thats a good tip  :)

Red, 98 bytes
func[s w][foreach v w[parse s[thru[any" "v ahead" "]any[to remove[" "v ahead[" "| end]]| skip]]]s]

Try it online!
f: func [s w][
    foreach v w [                   ; for each string in the array
        parse s [                   ; parse the input string as follows:
            thru [                  ; keep everything thru:
                any " "             ; 0 or more spaces followed by
                v                   ; the current string from the array followed by
                ahead " "           ; look ahead for a space
            ]
            any [ to remove [       ; 0 or more: keep to here; then remove:
                " "                 ; a space followed by
                v                   ; the current string from the array
                ahead [" " | end]]  ; look ahead for a space or the end of the string
            | skip                  ; or advance the input by one
            ]
        ]
    ]
    s                               ; return the processed string
]

Husk, 13 bytes
wüöVËm_Ṗ3+⁰ew

Takes a list of strings and a single string as arguments, in this order.
Assumes that the list is duplicate-free.
Try it online!
Explanation
wüöVËm_Ṗ3+⁰ew  Inputs: list of strings L (explicit, accessed with ⁰), string S (implicit).
               For example, L = ["CASE","for"], s = "Case for a different case".
            w  Split S on spaces: ["Case","for","a","different","case"]
 ü             Remove duplicates wrt an equality predicate.
               This means that a function is called on each pair of strings,
               and if it returns a truthy value, the second one is removed.
  öVËm_Ṗ3+⁰e    The predicate. Arguments are two strings, say A = "Case", B = "case".
           e    Put A and B into a list: ["Case","case"]
         +⁰     Concatenate with L: ["CASE","for","Case","case"]
       Ṗ3       All 3-element subsets: [["CASE","for","Case"],["CASE","for","case"],
                                        ["CASE","Case","case"],["for","Case","case"]]
  öV            Does any of them satisfy this:
    Ë            All strings are equal
     m_          after converting each character to lowercase.
                In this case, ["CASE","Case","case"] satisfies the condition.
               Result: ["Case","for","a","different"]
w              Join with spaces, print implicitly.

Retina, 46 37 bytes
+i`(^|,)((.+),.*\3.* )\3( |$)
$2
.*,

-14 bytes thanks to @Neil, and +5 bytes for a bug-fix.
Input in the format word1,word2,word3,sentence, because I'm not sure how to have multi-line input (where the inputs are used differently)..
Explanation:
Try it online.
+i`(^|,)((.+),.*\3.* )\3( |$)   Main regex to match:
+i`                              Enable case insensitivity
   (^|,)                          Either the start of the string, or a comma
        (                         Open capture group 2
         (                         Open capture group 3
          .+                        1 or more characters
            )                      Close capture group 3
             ,                     A comma
              .*                   0 or more characters
                \3                 The match of capture group 3
                  .*               0 or more characters, followed by a space
                     )            Close capture group 2
                      \3          The match of capture group 2 again
                        ( |$)     Followed by either a space, or it's the end of the string
$2                              And replace everything with:
                                 The match of capture group 2

.*,                             Then get everything before the last comma (the list)
                                 and remove it (including the comma itself)

As written you can simplify the first line to +i`((.+),.*\2.* )\2( |$) and the second to $1 but I notice that your code fails on often,he intended to keep ten geese anyway.

@Neil Thanks for the -14 golf, and fixed the bug with +1.

... except that this now fails on one of the original test cases...

@Neil Ah oops.. Fixed again for +4 bytes.

Well, the good news is I think you can use \b instead of (^|,), but the bad news is I think you need \b\3\b (haven't devised a suitable test case yet though).

PowerShell v3 or later, 104 bytes
Param($s,$w)$w|?{$_-and$s-match($r="\b$_(?: |$)")}|%{$h,$t=$s-split$r;$s="$h$($Matches.0)$(-join$t)"};$s

At the cost of one byte, it can run in PS 2.0 by replacing $Matches.0 with $Matches[0].
Long version:
Param($s, $w)
$w | Where-Object {$_ -and $s -match ($r = "\b$_(?: |$)")} |    # Process each word in the word list, but only if it matches the RegEx (which will be saved in $r).
    ForEach-Object {                                            # \b - word boundary, followed by the word $_, and either a space or the end of the string ($)
        $h, $t = $s -split $r                                   # Split the string on all occurrences of the word; the first substring will end up in $h(ead), the rest in $t(ail) (might be an array)
        $s = "$h$($Matches.0)$(-join $t)"                       # Create a string from the head, the first match (can't use the word, because of the case), and the joined tail array
    }
$s                                                              # Return the result

Usage
Save as Whatever.ps1 and call with the string and the words as arguments.
If more than one word needs to be passed, the words need to be wrapped in @():
.\Whatever.ps1 -s "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat" -w @("cat", "mat")

Alternative without file (can be pasted directly into a PS console):
Save the script as ScriptBlock (inside curly braces) in a variable, then call its Invoke() method, or use it with Invoke-Command:
$f={Param($s,$w)$w|?{$_-and$s-match($r="\b$_(?: |$)")}|%{$h,$t=$s-split$r;$s="$h$($Matches.0)$(-join$t)"};$s}
$f.Invoke("A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", @("cat", "mat"))
Invoke-Command -ScriptBlock $f -ArgumentList "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", @("cat", "mat")

Javascript, 150 bytes
s=(x, y)=>{let z=new Array(y.length).fill(0);let w=[];for(f of x)(y.includes(f))?(!z[y.indexOf(f)])&&(z[y.indexOf(f)]=1,w.push(f)):w.push(f);return w}

Besides the issues with golfing (have a look at the other JS solutions for some tips there), this takes the first input as an array of words and outputs an array of words which isn't allowed by the challenge spec. It also fails when different cases are involved.

@Shaggy "The output can either be the return value from a function" This looks like it returns a value from the function?

Clean, 153 142 138 134 bytes
import StdEnv,StdLib,Text
@ =toUpperCase
$s w#s=split" "s
=join" "[u\\u<-s&j<-[0..]|and[i<>j\\e<-w,i<-drop 1(elemIndices(@e)(map@s))]]

Try it online!
Defines the function $ :: String [String] -> String, pretty much literally doing what the challenge describes. It finds and removes every occurrence after the first, for each target word.

Ruby, 63 61 60 59 bytes
->s,w{w.any?{|i|s.sub! /\b(#{i}\b.*) #{i}\b/i,'\1'}?redo:s}

Try it online!
A shorter version that's case sensitive and fails ~every 1015 times because of randomness (37 bytes)
->s,w{s.uniq{|i|w.member?(i)?i:rand}}

Python 3, 168 bytes
def f(s,W):
 s=s.split(" ");c={w:0for w in W}
 for w in W:
  for i,v in enumerate(s):
   if v.lower()==w.lower():
    c[w]+=1
    if c[w]>1:s.pop(i)
 return" ".join(s)

Try it online!

AWK, 120 bytes
NR%2{for(;r++<NF;)R[tolower($r)]=1}NR%2==0{for(;i++<NF;$i=$(i+s))while(R[x=tolower($(i+s))])U[x]++?++s:i++;NF-=s}NR%2==0

Try it online!
The "remove whitespace" part made this a bit more challenging than I first thought. Setting a field to "", removes a field, but leaves an extra separator.
The TIO link has 28 extra bytes to allow multiple entries.
Input is given over 2 lines. The first line is the list of words and the second is the "sentence". Note that "word" and "word," are not considered identical do to the attached punctuation. Having punctuation requirements would likely make this an even more fun problem.

Min, 125 bytes
=a () =b a 1 get =c a 0 get " " split
(:d (b d in?) ((c d in?) (d b append #b) unless) (d b append #b) if) foreach
b " " join

Input is quot on stack with input String as first element, and a quot of the duplicate strings as second element, i.e.
("this sentence has no matches" ("ten" "cheese"))

Python 2, 140 bytes
from re import*
p='\s?%s'
S,A=input()
for a in A:S=sub(p%a,lambda s:s.end()==search(p%a,S,flags=I).end()and s.group()or'',S,flags=I)
print S

Try it online!
Explanation:
re.sub(..) can take as argument a function instead of replacement string. So here we have some fancy lambda.
Function is called for each occurence of pattern and one object is passed to this function - matchobject. This object has information about founded occurence. I'm interested in index of this occurence, that can be retrieved by start() or end() function. Latter is shorter so it is used.
To exclude replacement of first occurence of word, I used another regex search function to get exactly firts one and then compare indexes, using same end()
Flag re.I is short version of re.IGNORECASES


text:
Code Golf: Your own horizontal pet ASCII snake
Very heavily inspired by this challenge Code Golf: Your own pet ASCII snake - I thought making it horizontal would add an extra layer of complexity.
An example horizontal snake:
            0 0
  0        0 0 000
00 0     00       000 0      0
    000 0            0 0   00
       0                000

And the rules are:

Exactly 5 lines of characters are printed
Each line is exactly 30 characters long, consisting of a combination of spaces and the character you choose to draw your snake with
Your snake starts on line 3
The next line to be used for drawing your snake must be randomly chosen from your current line, one line above (if you're not already on line 1) or one line below (if you're not already on line 5).

These choices must be equally weighted. So if you are on line 1, you have a 50% chance to stay on line 1 and a 50% chance to move to line 2. If you are on line 2, you have a 33% chance to move to line 1, a 33% chance to stay on line 2 or a 33% chance to move to line 3

Your snake does not need to visit every single line.

Welcome to PPCG! This is a good first challenge.

For clarification, if we're on the edge, do we have to uniformly pick (stay on the same line) and (go to a different line) or can we have non-uniform weights?

And off the edges, do we have to uniformly pick up/down/same line?

Mmm... at least the 5-line limitation stops people from stealing answers from the other one with a transpose appended.

Humm, I think it should be an even weight. I will clarify the question rules

Can we output an array of lines?

Also, must we use 0 for the snake or can we use any non-whitespace character?

@Shaggy "and the character you choose to draw your snake with"

Thanks, @Giuseppe; missed that scanning through it on my phone.

@Shaggy I feel like allowing that now would be unfair to the other answers

Does physically rotating the monitor by 90° count as a byte? :D

...this is snek

JavaScript (ES6), 98 bytes
Saved 7 bytes thanks to @KevinCruijssen
Returns an array of 5 strings.
f=(y=2,a=[...'  0  '])=>a[0][29]?a:f(y+=(Math.random()*(y%4?3:2)|0)-!!y,a.map((v,i)=>v+=i-y&&' '))

Try it online!
Commented
f = (                       // given:
  y = 2,                    //   y = current line (0-indexed)
  a = [...'  0  ']          //   a[] = array of 5 lines
) =>                        //
  a[0][29] ?                // if all columns have been processed:
    a                       //   stop recursion and return a[]
  :                         // else:
    f(                      //   do a recursive call with:
      y += (                //     the updated value of y, to which we add -1, 0 or 1:
        Math.random() *     //       pick a random value in [0,1)
        (y % 4 ?            //         if y is neither 0 or 4:
          3                 //             multiply it by 3
        :                   //           else:
          2                 //             multiply it by 2
        ) | 0               //       force an integer value
      ) - !!y,              //     subtract either 0 or 1
      a.map((v, i) =>       //     for each value v at position i in a[]:
        v += i - y && ' '   //       append either '0' if i = y or a space otherwise
      )                     //     end of map()
    )                       //   end of recursive call

You can drop the d and use ((y%4?3:2)|0)-(y>0) for -6 bytes. Try it online.

Correction: -7 bytes. The 1 in new Random(...) is implicit by default of course.. Try it online.

@KevinCruijssen Thanks! (!!y instead of (y>0) saves 2 more bytes.)

Charcoal, 28 bytes
Ｐ|   Ｆ³⁰«0≡ⅉ²Ｍ‽²↑±²Ｍ‽²↓Ｍ⊖‽³↓

Try it online! Link is to verbose version of code. Explanation:
Ｐ|

Print some padding to force 5 lines of output.
Ｆ³⁰«

Repeat 30 times.
0

Print a zero (and move horizontally).
≡ⅉ²Ｍ‽²↑

If the Y-coordinate is 2, move up randomly by 0 or 1.
±²Ｍ‽²↓

If it's -2, move down randomly by 0 or 1.
Ｍ⊖‽³↓

Otherwise move down randomly by -1, 0 or 1.

Perl, 68 bytes
perl -E '$%=2;s:$:$n++%5-$%&&$":emg,$%-=!!$%+rand!($%%4)-3for($_=$/x4)x30;say'

This doesn't feel optimal at all.

R, 138 bytes
m=matrix(" ",30,5)
m[1,3]=0
x=3
s=sample
for(i in 2:30)m[i,x<-x+(-1)^(x==5)*s(0:1,1)*x%in%c(1,5)+(s(3,1)-2)*x%in%2:4]=0
write(m,"",30,,"")

Try it online!
Handily outgolfed by plannapus

Python 3, 144 bytes
@Ruts, @Turksarama, and @mypetlion have been very helpful in reducing bytes
import random
m=[list(' '*30)for y in range(5)]
l=2
for i in range(1,30):
 m[l][i]=0
 l+=random.randint(~-(l<1),l<4)
for j in m:
  print(*j)

Will try and improve on this. Fun challenge!

Change l+=random.randint(-1,1)  l=0 if l<0 else l  l=4 if l>4 else l to l+=random.randint(~-(l<1),l<4) to save 31 bytes.

You should be able to remove a lot of spaces and newlines.

Change m=[[' 'for x in R(w)]for y in R(h)] to m=[list(' '*w)for y in R(h)] to save 7 bytes.

@mypetlion can you explain how l+=random.randint(~-(l<1),l<4) works?

In python, boolean a subclass of int. So False can be used in place of 0 and True can replace 1. The ~ is a unary operator for bitwise not and the - operator flips the sign (multiply by -1). So ~-(False) evaluates to -1 and ~-(True) evaluates to 0.

Assign your initial 0 inside your loop and set l after the assignment.  This saves you one whole line (m[2][0]=0 is gone) and 2 bytes on the for loop (for i in R(1,30): becomes for i in R(30):).
You will also need to recalculate l after you set the 0.  This should take you to 144 bytes.

I'm not very experienced, but I believe you can win 9 bytes by not introducing variables wand h. Remove line w,h=30,5 and change m=[list(' '*w)for y in R(h)] to m=[list(' '*30)for y in R(5)]. I hope I'm right.

Also tried to remove R=range and used function range twice in your code. This also seems to save 1 byte.

Thanks for the explanation, mypetlion. Also thanks Turksarama and Ruts for saving me some bytes!

Jelly, 24 bytes
3µ’o1r‘«5¥$Xµ30Ð¡Ṭ€o⁶z⁶Y

Try it online!
Explanation

3µ’o1r‘«5¥$Xµ30Ð¡Ṭ€o⁶z⁶Y || Niladic full program.
                         ||
3                        || Starting from 3...
 µ          µ30          || ... Execute 30 times...
               Ð¡        || ... And collect the results in a list.
  ’o1r‘«5¥$X             ||--| Monadic "Helper" function.
  ’o1                    ||--| The current integer, decremented OR 1.
     r     X             ||--| Grab a random item from the range from ^ to...
      ‘«5                ||--| ... The number incremented, capped to 5 (uses maximum).
         ¥$              ||--| Syntax elements. Used for grouping links.
                 Ṭ€      || Untruth each.
                   o⁶    || Logical OR with a single space.
                     z⁶  || Transpose with filler spaces.
                       Y || Join by newlines.

R, 120 114 bytes
m=matrix
r=m(" ",30,5)
x=3
for(i in 1:30){r[i,x]=0;x=x+sample(-1:1,1,,m(c(0,rep(1,13)),3)[,x])}
write(r,"",30,,"")

Thanks to @Giuseppe for the additional 6 bytes!
Uses a table of probabilities as follows:
> matrix(c(0,rep(1,13)),3)
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    1    1    1    1
[2,]    1    1    1    1    1
[3,]    1    1    1    1    0
Warning message:
In m(c(0, rep(1, 13)), 3) :
  data length [14] is not a sub-multiple or multiple of the number of rows [3]

where each columns corresponds to a case, i. e. column 1 is picked if the snake is in row 1, giving probabilities 0, 1/2 and 1/2 to pick respectively -1 [go down], 0 [stay still] and 1 [go up] (sample automatically normalize the probabilities to 1), column 2 for row 2 gives probabilities 1/3, 1/3 and 1/3, etc...
Try it online!

114 bytes

@Giuseppe Thanks! There was indeed no reason to alias it, and I forgot to use vector recycling for that extra 0.

SOGL V0.12, 22 21 bytes
3ā'∑∫⁵╗ž⁴H1ΧGI5χ⁴-ψ+;

Try it Here!
Explanation:
3                      push 3
 ā                     push an empty array - the canvas
  '∑∫                  30 times do, pushing counter            | stack = 3, [], 1
     ⁵                   duplicate the Y coordinate            | stack = 3, [], 1, 3
      ╗ž                 at those coordinates insert "+"       | stack = 3, ["","","+"]
        ⁴                duplicate from below                  | stack = 3, ["","","+"], 3
         H               decrease                              | stack = 3, [...], 2
          1Χ             maximum of that and 1                 | stack = 3, [...], 2
            G            get the item 3rd from top             | stack = [...], 2, 3
             I           increase it                           | stack = [...], 2, 4
              5χ         minimum of that and 5                 | stack = [...], 2, 4
                ⁴-       subtract from the larger a copy of the smaller value | stack = [...], 2, 2
                  ψ      random number from 0 to pop inclusive | stack = [...], 2, 2
                   +     add those                             | stack = [...], 4
                    ;    and get the array back ontop          | stack = 4, ["","","+"]

                         implicitly output the top item - the array, joined on newlines

Japt, 31 29 bytes
Returns an array of lines.
30ÆQùU±[2V=Jõ VVJò]mö i3 gUÃy

Test it

Japt, 26 bytes
30ÆQùU=U?5õ f_aU <2Ãö :3Ãy

Test it online!

Java 8, 177 170 bytes
v->{int a[][]=new int[5][30],c=0,r=2;for(;c<30;r+=Math.random()*(r%4>0?3:2)-(r>0?1:0))a[r][c++]=1;String R="";for(int[]y:a){for(int x:y)R+=x<1?" ":"~";R+="\n";}return R;}

-7 bytes thanks to @OlivierGrégoire.
Explanation:
Try it online.
v->{                // Method with empty unused parameter and String return-type
  int a[][]=new int[5][30],
                    //  Integer-matrix of size 5x30
      c=0,          //  Column, starting at index 0
      r=2;          //  Row, starting at index 2
  for(;c<30;        //  Loop `c` 30 times
      r+=Math.random()*(r%4>0?3:2)-(r>0?1:0))
                    //    After every iteration: change `r` with -1,0,1 randomly
                    //     If `r` is 0: random [0;2)-0 → 0,1
                    //     If `r` is 4: random [0;2)-1 → -1,0
                    //     If `r` is 1,2,3: random [0:3)-1 → -1,0,1
    a[r][c++]=1;    //   Fill the cell at indices `r,c` from 0 to 1
  String R="";      //  Result-String, starting empty
  for(int[]y:a){    //  Loop over the rows of the matrix
    for(int x:y)    //   Inner loop over the individual column-cells of the matrix
      R+=x<1?       //    If the value of the cell is still 0:
          " "       //     Append a space
         :          //    Else (it's 1):
          "~";      //     Append the character
    R+="\n";}       //   After every row, Append a new-line
  return R;}        //  Return the result-String

r+=Math.random()*(r%4>0?3:2)-(r>0?1:0) to save a few bytes.

@OlivierGrégoire I thought I had already done that, but apparently not. Maybe I did it in another answer recently.. :S Thanks!

Japt, 28 bytes
Saved 9 bytes thanks to ETHproductions
3k
29Æp5õ f_aUgY)<2Ãö
¡QùXÃy

Try it online!

SmileBASIC, 107 105 103 89 bytes
FOR I=0TO 29FOR J=0TO 5LOCATE I,J?" 0"[Y+2==J]NEXT
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT
NEXT

This answer is more interesting than the vertical one because of the (literal) edge cases.
64 bytes, without printing spaces:
FOR I=0TO 29LOCATE,Y+2?0;
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT

I also found a few variations of line 2 with the same length:
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT
Y=Y+RND(3)-1D%=Y/3Y=Y-D%-D%*RND(2)NEXT
Y=Y+RND(3)-1Y=Y-Y DIV 3*(RND(2)+1)NEXT
Y=Y+RND(3)-1Y=Y/3OR.Y=Y-D-D*RND(2)NEXT

The integer division of Y/3 is used to check if Y is outside the valid range, as well as getting the sign.

Python 2, 127 bytes
from random import*
s=['']*5
n=3
r=range(5)
exec"for i in r:s[i]+=' 0'[i==n]\nn=choice(r[n and~-n:n+2])\n"*30
print'\n'.join(s)

Try it online!

Octave with Statistics Package, 99 bytes
It also works in MATLAB with the Statistics Toolbox.
p=3;for k=1:29
p=[p;p(k)+fix(randsample(setdiff([1 pi 5],p(k)),1)-3)/2];end
disp(['' (p==1:5)'+32])

Try it online!

C (gcc), 134 130 bytes
r,x,y=3,a[31],m;f(){for(x=0;x<31;x++){m?putchar(x==30?10:a[x]-m?32:48):(a[x]=y);r=rand();y+=y==1?r%2:y==5?-r%2:1-r%3;}++m<6&&f();}

Try it online!

Welcome to PPCG!

Thanks! Using putchar instead of printf saves 4 bytes.

Perl 6, 85 bytes
.join.say for [Z] ((' ',' ',0,' ',' '),{.rotate(set(0,+?.[0],-?.[4]).pick)}...*)[^30]

Try it online!
The long parenthesized expression is a lazy sequence generated from the initial element (' ', ' ', 0, ' ', ' '), the first vertical strip of the output.  Each successive strip/list is generated from the preceding one by calling its rotate method, with the offset randomly chosen from a set containing 0, 1 (if the first element is nonzero), and -1 (if the fifth element is nonzero).
The matrix of horizontal strips is transposed with the [Z] operator, turning it into a list of vertical strips, each of which is then joined into a single string and output with say.

Perl, 83 101 bytes
perl -E '$l=3;map{map$s[$_-1].=/$l/?0:" ",1..5;$l-=1-int 3*rand;$l=~y/60/51/}1..30;say for@s'

New: Without probability issue at the borders:
perl -E '$l=3;map{map$s[$_-1].=/$l/?0:" ",1..5;$l=int($l<2?1+2*rand:$l>4?6-2*rand:$l-1+3*rand)}1..30;say for@s'

Ungolfed:
$l=3;                             #start line
map{
  map $s[$_-1].=/$l/?0:" ",1..5;  #0 at current char and line, space elsewhere
  $l-=1-int 3*rand;               #up, down or stay
  $l=int( $l<2 ? 1+2*rand
        : $l>4 ? 6-2*rand
        :        $l-1+3*rand )    #border patrol
}
1..30;                            #position
say for@s                         #output result strings/lines in @s

Your border patrol does not give the right probability of 50% for staying on the edge.

Scala, 207 Bytes
val b=Array.fill(150)('.')
def s(y:Int,x:Int)={val r=Random.nextInt(6)
val z=y+(if(y>3)-r%2
else if(y<1)r%2
else r/2-1)
b(z*30+x)='$'
z}
(3/:(0 to 28))(s(_,_))
b.mkString("").sliding(30,30).foreach(println)

sample:
...................$$$...$.$$.
.$$$..............$...$.$.$...
$...$$$..$...$$.$$.....$......
.......$$.$.$..$..............
...........$..................

degolfed:
val buf = List.fill(150)('.').toBuffer
def setRowCol (y:Int, x:Int): Int = {
  val r = Random.nextInt(6)
  val z = y + (
    if (y>3)
        -(r%2)
    else if (y<1)
        (r%2)
    else
        r/2-1
  )
  buf (z * 30 + x) = '$'
  z
}
(3 /: (0 to 28)(setRowCol (_, _))
println
buf.mkString ("").sliding(30,30).foreach(println)

My unique invention - well, I haven't read the other solutions so far, is, to generate a Random (6) which is implicitly two Randoms, (2*3). If away from the border, I use the values of r/2 (0,1,2) and → (-1,0,1) tell me, to go up or down. If at the border, I can avoid the character costly call of another random, and just take the modulo(2), to decide, should I stay or should I go.
Let's see the other solutions. :)

Yes, wrong sample image. It does. :)

scala rocks! oh .. code golf .. wrong use case it appears..  How in the heck did it get lapped by java ?

@javadba: Have you clicked the try it link? Kevin Cruijssen didn't include some boilerplate, needed to compile this code or to run it in JShell, but I guess that's according to the guidelines - there might be a meta discussion. If you like, you can try to reduce this code, by using a two-dim array too. A second idea is, to reduce the sliding code in the end.Some map method? The println is hidden by Kevin. - Yes, Array gives an improvement by 8.

Let scala infer the return type int: Saved 4 more character.

so it's getting into the ballpark for java now

A (0 to 4).map(y=>b(y*30+29)='\n');b foreach print is 2 characters longer than the last line, mkString ... sliding

As I was scrolling down the page, I was thinking about ways to use just one random number, and I thought of using random(6) right as I saw your answer.

Ruby, 98 77 bytes
->{a=(0..4).map{" "*30}
x=2
30.times{|i|a[x][i]=?@
x+=rand(3-17[x])-30[x]}
a}

Try it online!
A lambda returning an array of strings.
My initial impulse was to generate the columns and transpose them, but it's much easier to just avoid that step.
I would have liked to initialize a with [" "*30]*5, but that would make shallow copies of the strings, resulting in a very fat, non-slithery snake.
I could have used a constant like D as the increment (for the same byte count), but Ruby would have complained every time I assigned it. I decided I prefer decreasing readability by reusing i mid-loop to having a bunch of Debug warnings to ignore.
I also would have liked to save a few bytes with loop{x+=rand(3)-1;(0..4)===x&&break}, but that would have caused a bias on the edges: 1/3 chance to turn back inward, 1/3 chance to stay, and 1/3 chance to go out of bounds for a while before eventually random-walking back in (that is, "stay").
-20 bytes: Use Ruby's Integer#[] to create tiny conditionals, ensuring correct movement weightings for all 5 positions. This replaces a loop-break pattern (with a nonzero chance of failing to halt) for a huge savings. Thanks, Eric Duminil!
-1 byte: Initialize a with (0..4).map instead of 5.times, thanks again to Eric Duminil.
->{
  a = (0..4).map{ " " * 30 }      # a is the return array: 5 strings of 30 spaces
  x = 2                           # x is the snake position
  30.times{ |i|                   # For i from 0 to 29
    a[x][i] = ?@                  #   The ith position of the xth row is modified
    x += rand(3 - 17[x]) - 30[x]  #   Using bit logic, add rand(2 or 3) - (0 or 1)
  }
  a                               # Return the array of strings
}

Nice start. No need for an inner loop. You can calculate the increment with rand(2+14[x])-30[x] or rand -(30[x])..15[x]. There's probably a shorter version. Still, -20 bytes isn't bad! Try it online!

1 byte less with x,a=2,(0..4).map{" "*30}. Try it online!

Wow, 30[x] is a great trick! Thanks!

Python 3, 123 bytes
from random import*
i,*a=2,
exec("a+=i,;i+=randint(-(i>0),i<4);"*30)
for x in range(5):print(''.join(' 0'[x==i]for i in a))

Try it online!
Generate an array of integers, then convert it to each row.
Python 2, 120 bytes
from random import*
i=2;a=[]
exec"a+=i,;i+=randint(-(i>0),i<4);"*30
for x in range(5):print''.join(' 0'[x==i]for i in a)

Try it online!
For Py2, redundant parens for exec and print can be removed, but the syntax in the 2nd line is invalid.
Outgolfing both Py2 submission by Rod and Py3 submission by linemade.

PowerShell, 133 bytes
$a=(,' '*30),(,' '*30),(,' '*30),(,' '*30),(,' '*30);$l=2;0..29|%{$a[$l][$_]=0;$l+=0,(1,($x=1,-1),$x,$x,-1)[$l]|Random};$a|%{-join$_}

Try it online!
Constructs a 2D array of 30 spaces wide by 5 lines tall. (NB - if someone can come up with a better effective way to initialize this array, I'll <3 you forever.) Sets helper variable $l to 2 (this is used for what line the previous snake segment was on). Then loops from 0 to 29.
Each iteration, we set our snake element to 0. Then we index into a complicated array with Get-Random that selects out whether we go up or down or stay the same. That's added back into $l.
Finally, we loop through the five elements of $a and -join their inner elements into a single string each. Those five strings are left on the pipeline, and the implicit Write-Output gives us newlines for free.

Clojure, 123 bytes
Here come the parens:
(let[l(take 30(iterate #(max(min(+(-(rand-int 3)1)%)4)0)3))](doseq[y(range 5)](doseq[x l](print(if(= y x)0" ")))(println)))

Ungolfed version:
(let [l (take
       30
       (iterate
        #(max
          (min
           (+ (- (rand-int 3) 1) %)
           4)
          0)
        3))]
(doseq [y (range 5)]
  (doseq [x l]
    (print (if (= y x) 0 " ")))
  (println)))

Builds a list of the different heights of the snake body, then iterates from 0 to 4. Whenever a height matches the current row it prints a 0, otherwise a blank.
Not letting the heights exceed the boundary really costs bytes. Also recognizing when a new line is in order is more byte-intensive as it should be. One could easily write a single doseq, making a cartesian product of the x's  and y's but then one does not know when to print a new line.

Python3 +numpy, 137 132 bytes
Not the shortest python submission, not the longest, and definitely not the fastest.
from pylab import*
j=r_[2,:29]
while any(abs(diff(j))>1):j[1:]=randint(0,5,29)
for i in r_[:5]:print(''.join(' #'[c] for c in j==i))

update Using numpy's diff command saved 5 bytes for testing if the snake is a valid pattern, compared to calculating the difference manually with j[1:]-j[:-1].

05AB1E, 25 bytes
Y30F©ð5×0®ǝs<DÌŸ4ÝÃΩ}\)ζ»

Try it online!
Explanation
Y                           # push the initial value 2
 30F                        # 30 times do
    ©                       # store a copy of the current value in register
     ð5×                    # push 5 spaces: "     "
        0®ǝ                 # insert 0 at the position of the current value
           s<DÌŸ            # push the range [current-1 ... current-1+2]
                4ÝÃ         # keep only numbers in [0 ... 4]
                    Ω       # pick one at random
                     }\     # end loop and discard the final value
                       )ζ   # transpose the list
                         »  # join by newlines

C (gcc), 80 76 72 71 bytes
a[5][30],i,r;f(){for(r=2;i<30;r+=rand()%3-1)a[r=r>4?4:r<0?0:r][i++]=1;}

Try it online!

Suggest f(r) instead of r;f()

R, 95 bytes
x=3;l=1:5
write(t(replicate(30,{y=ifelse(x-l,' ',0);x<<-sample(l[abs(x-l)<2],1);y})),'',30,,'')

Next line x is always chosen from lines that are no more than 1 away from current line (l[abs(x-l)<2]). Using replicate instead of a for cycle saves some bytes needed for matrix initialization and manipulation and requires the use of the <<- operator when assigning to the global variable x.
Try it online!

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Collapse the antistring
In this challenge you will be given an alphabetic string as input.  We will define the "anti-string" of a given input to be the string with the case of all the letters inverted.  For example
AaBbbUy -> aAbBBuY

You should write a program that takes a string as input and searches for the longest contiguous substring whose anti-string is also a contiguous substring.  The two substrings should not overlap.
As an example if you were given the string
fAbbAcGfaBBagF
The bolded portions would be the longest string anti-string pair.
Your program should, once it has found the pair, collapse them into a single character each.  It should do this by removing all but the first character of each substring.  For example the string above
fAbbAcGfaBBagF
would become
fAcGfagF
Your program should then repeat the process until the longest string anti-string pair is a single character or shorter.
For example working with the same string the new longest pair after the collapse is
fAcGfagF
So we collapse the string again
fAcGag
Now the string cannot be collapsed further so we should output it.
In the case of a tie between candidate pairs (example AvaVA) you may make either reduction (AaA or AvV, but not Aa).
This is code-golf so answers will be scored in bytes with fewer bytes being better.
Test Cases
fAbbAcGfaBBagF  ->  fAcGag
AvaVA ->  AaA / AvV
QQQQQQQ -> QQQQQQQ
fAbbAcQQQQaBBacqqqqA -> fAbcQBcq
gaq -> gaq
fAbbAcGfaBBagFaBBa -> fcGaBBag

Motivations
While this problem may seem arbitrary it is actually a problem I encountered while making code to process fundamental polygons.  This process can be used to reduce a fundamental polygon to a smaller n-gon.  After I tried it I thought it would make a nice little golf.

If the largest substring with anti-string substrings has more than one anit-string substring, should all substrings be collapsed or only the first two?

@JonathanFrech Any two.  That is a case where there is a tie between candidate pairs.

So aaaAAAaaa -> aAaaa?

Something about a subset of this problem screams quine but I can't put my finger on it.

@MagicOctopusUrn Something like Write a two-cycle quine where the program's output is its antistring?

The case inversion is according to which locale? What is your input character set?

How should the case 'aAa' be resolved? It contains substrings 'aA' and 'Aa' which are antistrings; is the result then 'aA'? or must the strings be non-overlapping?

I came here hoping that "antistring" meant something that destroys a string (like antimatter). Inverted case is not near as satisfying.

@ChasBrown I covered an example like that.  The string and it's antistring must be non-overlapping.

Perl, 64 61 bytes
Includes +1 for p
perl -pE 's/(.\K.{$%})(.*)(?=(.))(??{$1^$"x$%.$"})/$2$3/ while$%=--pos' <<< fAbbAcGfaBBagFaBBa

JavaScript (ES6), 200 bytes
Uses arrays of characters for I/O.
f=a=>(m=M=C=>a.map((_,i)=>a.map((_,j)=>C(i,j-i+1))))(I=>M((i,j)=>a.slice(i,i+j).some((n,k)=>n[c='charCodeAt']()^(a[I+k]||'')[c]()^32)|I+j>i|j<m||(x=[i,I],m=j)))&&m-->1?f(a,x.map(p=>a.splice(p+1,m))):a

Try it online!

C (gcc), 240 238 227 225 222 216 bytes

Saved two bytes; removed a stray variable definition.
Saved eleven thirteen bytes; golfed b|=S[p+m]!=S[q+m]+32-(S[q+m]>90)*64 to b|=abs(S[p+m]-S[q+m])-32 to b|=32-S[p+m]+S[q+m]&63.
Saved three bytes; golfed for(...;...;p++)S[p+1]=S[p+L]; to for(...;...;S[++p]=S[p+L]);.
Saved six bytes thanks to ceilingcat.

p,P,q,Q,l,L,b,m;f(char*S){for(p=0;S[p];p++)for(l=0;S[l+++p];)for(q=0;b=S[q+~-l];!b&p+l<=q&l>L?L=l,P=p,Q=q:0,q++)for(b=0,m=l;m--;)b|=32-S[p+m]+S[q+m]&63;for(;b-2;)for(p=b++?-~Q-L:P;S[p];S[++p]=S[L+p]);~-L?L=0,f(S):0;}

Try it online!

Python 3, 189 181 bytes
Credit to Jonathan Frech for making it pure one-liner.
f=lambda s,x=set():any(u in s[j+i:]and(x.add(s[:j+1]+s[j+i:].replace(u,u[0],1))or 1)for i in range(len(s),1,-1)for j in range(len(s))for u in[s[j:j+i].swapcase()])and f(x.pop())or s

Try it online!
My own version, now obsolete (189 bytes):
x=set()
def f(s):
 while any(u in s[j+i:]and(x.add(s[:j+1]+s[j+i:].replace(u,u[0],1))or 1)for i in range(len(s),1,-1)for j in range(len(s))for u in[s[j:j+i].swapcase()]):s=x.pop()
 return s

Try it online!
any() to break out nested loops early, and set() for mutable global object usable in the comprehension. The rest is just the straightforward implementation of the requirements using str.swapcase.
Python 2, 160 bytes
def f(s):
 for i in range(len(s),1,-1):
	for j in range(len(s)):
	 u=s[j:j+i].swapcase()
	 if u in s[j+i:]:return f(s[:j+1]+s[j+i:].replace(u,u[0],1))
 return s

Try it online!
Turns out that regular nested for loop with early breaking through return is way shorter than the "clever" trick with any.

181 bytes; recursive approach. The mutable set as function default will not collide with further calls, as I think your code fully pops the set to be empty.

Sorry, I thought that x would be left behind being not empty. As you have it, I think it complies.

That's fine, and thanks for the improvement.

Retina, 119 bytes
.+
$&¶$&
T`Ll`lL`.*¶
/(.).*¶.*\1/^&0A`
¶&Lv$`(?<=(.)*)((.)(.)*).*¶(?>((?<-1>.)*.)(?<-4>.)*)(.*)\2
$5$6$3$'
N$`
$.&
}0G`

Try it online! Link includes test cases. Explanation:
.+
$&¶$&
T`Ll`lL`.*¶

Duplicate the input and flip the case of the first copy.
/(.).*¶.*\1/^&0A`

If there are no anti-strings at all then delete the flipped duplicate.
¶&Lv$`(?<=(.)*)((.)(.)*).*¶(?>((?<-1>.)*.)(?<-4>.)*)(.*)\2
$5$6$3$'

List all the possible collapsed anti-strings.
N$`
$.&
}0G`

Sort them in order of length, take the shortest (i.e. longest anti-string), and repeat until all the anti-strings have been collapsed.

Python 2, 180 bytes
def f(s):
 L=len(s)
 for x,y in[(i,i+j)for j in range(L,1,-1)for i in range(L-j)]:
	t=s[x:y];T=t.swapcase()
	if T in s[y:]:return f(s.replace(t,t[0],1).replace(T,T[0],1))
 return s

Try it online!

Stax, 30 bytes
î☼fúΩ§☺æ╒ºê@Ñ▀'╫Iqa{d]∟Sa5♦⌂─╚

Run and debug it
The corresponding ascii representation of the same program is this.
c%Dc:e{%orF..*:{_{32|^mY++_h.$1yh++R

It uses a regex approach.  It repeatedly regex string replacement.  It builds these from each contiguous substring of the current value.  For instance for the input fAbbAcGfaBBagF, one of the substrings is AbbA, in which case the regex AbbA(.*)aBBa will be replaced with A$1a.
c                                       get number of characters
 %D                                     repeat rest of program that many times
   c:e                                  get all substrings
      {%or                              order substrings longest to shortest
          F                             for each substring, execute the rest
           ..*:{                        build the string "(.*)"
                _{32|^m                 current substring with case inverted
                       Y                save the inverted case in register y
                        ++              concatenate search regex together
                                            e.g. "aBc(.*)AbC"
                          _h            first character of substring
                            .$1         "$1"
                               yh       first character of inverted case
                                 ++     concatenate replacement regex together
                                            e.g. "a$1A"
                                   R    do regex replacement

Wolfram Language (Mathematica), 148 bytes
#//.s_:>MinimalBy[StringReplaceList[s,a:(p_~~__)~~x___~~b:(q_~~__)/;(32==##&@@Abs[(t=ToCharacterCode)@a-t@b]):>p<>x<>q]/.{}->{s},StringLength][[1]]&

Try it online!

Japt -h, 33 bytes
à ñÊÅÔ£=rX+"(.*)"+Xc^H ÈÎ+Y+XÎc^H

Try it
à ñÊÅÔ£=rX+"(.*)"+Xc^H ÈÎ+Y+XÎc^H     :Implicit input of string U
à                                     :Combinations
  ñ                                   :Sort by
   Ê                                  :  Length
    Å                                 :Remove first element (the empty string)
     Ô                                :Reverse
      £                               :Map each X
       =                              :  Reassign to U
        r                             :  Global replacement
         X+"(.*)"+                    :  Append "(.*)" to X and then append
                  Xc                  :    Charcodes of X
                    ^H                :    XORed with 32
                      È               :  Pass each match X, with captured group Y, through the following function
                       Î+Y+           :    Append Y to the first character of X and then append
                           XÎc^H      :      The charcode of the first character of X XORed with 32

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Order a list but respect integer ordering (natural sort order)
Given a list of n strings, return a list of that strings in ascending order. However, be aware, that in this case we want integer comparison for all numbers appearing in the strings, meaning that "12" > "3".
Example cases:
{"abc123", "abc6", "abc47", "abd49"} -> {"abc6", "abc47", "abc123", "abd49"}
{"foo0", "bar12", "foobar12", "foo"} -> { "bar12", "foo", "foo0", "foobar12"}
{"Bond007", "Bond07", "Bond7", "Bond12"} -> {"Bond007", "Bond07", "Bond7", "Bond12"}
{"one1", "one11two23", "one1two2", "one1two3", "1"} -> {"1", "one1", "one1two2", "one1two3", "one11two23"}

You can expect to only find [a-zA-Z0-9]+ in each string.
This is code-golf so shortest code in bytes wins.
Standard Loopholes are forbidden.
Update:
- Sorting is case insensitive
- The ascending order is integers < "abcdefghijklmnopqrstuvwxyz"
- Every sequence of integers as in the aforementioned order should be interpreted as one integer, meaning "421" represents 421, not 4, 2 and 1 and thus is smaller than "1341", as 421 < 1341
-Treat numbers with leadings zeroes as though they were decimals meaning "001" -> "0.01" so "001" < "01" < "1"
Thanks for Adám for pointing out, that this is called natural sort order.

So, you mean order it by consecutive integers inside the strings?  Or you could mean order it by all integers inside the string?

How funny. I was planning on posting this challenge.

Unfortunately, there are a lot specifications missing here.

Yes. Unclear rules. foo < foo0 but Bond007 < Bond7. I first thought (foo):(foo)(0) => (Bond)(007) (Bond)(7). Is uppercase/lowercase of any significance?

(VTC as unclear because of ^)

This is called natural sort order.

To prevent the challenge being unclear you should 1 provide a rigorous mathematical definition, 2 give a reference implementation and 3 (optional, but recommended) sandbox the challenge.

All your test cases do not indicate case-sensitivity or not. I would advise against making this rule as you may invalidate existing answers, and it doesn't really add to the challenge.

You have not specified how to sort 01 vs 1 and your examples do not indicate it either as the only relevant example is the "bond" one and the output has the same order as the input. Does the longer come first, or are they considered the same and just stay in input order?

So by the decimals rule, 012 < 03 < 2 ?

@Adám It's also their fault to answer an unclear challenge.

Also, it's still unclear what to do about 01 vs. 010.

The decimals' rule doesn't make any sense. I think what you want is that otherwise identical numbers, but where some have leading zeros, should sort by length, longest first, right?

Since the case insensitivity leads to ties you have to specify if the sort has to be stable or not. I suggest not since otherwise you force people whose language sort is unstable to implement their own sort

Adding to what @TonHospel said: Alternatively, you can specify a secondary sort order, e.g. that when tie-breaking, lowercase comes before uppercase. But again, I think you're better off making it case sensitive and just go by ASCII order.

This is a nice challenge I'd like to do but the spec is still incomplete. So could you please update your question ? The only things you still need to do is to specify how ties in the sorting are to be handled and fix the rule for leading zeros (presumably saying that more leading zeros sort before less leading zeros instead of trying to get to this using fractions).

05AB1E, 7 bytes
ΣDþïs)}

Try it online!
Explanation
ΣDþïs)}  Full Program
Σ     }  Sort by result of key: a
 D       a, a
  þ      digits_only(a), a
   ï     int(digits_only(a)), a
    s    a, int(digits_only(a))
     )   [a, int(digits_only(a))]

Python 2, 68 bytes
lambda l:sorted(l,key=lambda x:int(re.sub("\D","",x)or 0))
import re

Try it online!
I used something like this to sort PDF files recently!
my entry originally didn't work but Neil fixed it (thanks!)

Perl 6,  32 31  30 bytes
*.sort(*.comb(/\d+|\D+/)».&val)

Test it
*.sort(*.comb(/\d+|\D/)».&val)

Test it
*.sort(*.comb(/\d+|./)».&val)

Test it
Expanded:
*\                         # WhateverCode lambda (this is the parameter)

.sort(                     # sort by doing the following to each string

  *.comb( / \d+ | . / )\ # split the string into consecutive digits or a character

  ».&val                   # convert each to a Numeric if possible

)

Note:
"Bond007".comb(/\d+|\D+/)».&val
# results in
("Bond", IntStr.new(7, "007"))

# and

"Bond007".comb(/\d+|./)».&val
# results in
("B", "o", "n", "d", IntStr.new(7, "007"))

APL (Dyalog Unicode) 17.0 (currently in alpha), 31 bytesSBCS
Anonymous tacit prefix function taking a list of strings as argument.
⊂⊃¨⍨∘⍋({0::⍵⋄⍎⍵}¨⊢⊂⍨1,2≠/∊∘⎕D)¨

As version 17.0 isn't on TIO yet, here is a test session transcript:
      f←⊂⊃¨⍨∘⍋({0::⍵⋄⍎⍵}¨⊢⊂⍨1,2≠/∊∘⎕D)¨
      ⎕JSON f ⎕JSON '["abc123", "abc6", "abc47", "abd49"]'
["abc6","abc47","abc123","abd49"]
      ⎕JSON f ⎕JSON '["foo0", "bar12", "foobar12", "foo"]'
["bar12","foo","foo0","foobar12"]
      ⎕JSON f ⎕JSON '["Bond007", "Bond07", "Bond7", "Bond12"]'
["Bond007","Bond07","Bond7","Bond12"]
      ⎕JSON f ⎕JSON '["one1", "one11two23", "one1two2", "one1two3", "1"]'
["1","one1","one1two2","one1two3","one11two23"]

⊂ from the entire argument…
⊃¨⍨ pick each of the indices…
∘ that are…
⍋ the ascending grade (indices which would place in ascending order) of…
(…)¨ the following tacit function applied to each of the strings:
 ∊∘⎕D Boolean mask for the characters which are members of the set of Digits
 2≠/ pairwise inequality of that (i.e. indicate beginnings of letter runs and digit runs)
 1, prepend 1 to mark the first character as beginning a run
 ⊢⊂⍨ use that to partition (beginning partitions at 1s) the string
 {…}¨ apply the following anonymous lambda to each partition:
  0:: if any error happens, then:
   ⍵ return the argument as-is
  ⋄ try to:
   ⍎⍵ evaluate the argument

Python 3, 125 bytes
lambda a:[y for _,y in sorted([([i%2and int(e)or e for i,e in enumerate(re.findall("(\D+|\d+)",s))],s)for s in a])]
import re

Try it online!

Seems to ignore zeros.

@JonathanFrech Thanks, fixed for -11 bytes

Python 3, 107 106 bytes
import re
lambda a:sorted(a,key=lambda x:[n.isdigit()and n.zfill(9)or n for n in re.findall('\d+|\D+',x)])

Try it online!
Abused the fact that Python compares two lists lexicographically. Unfortunately re.split(r'\b',x) does not work.

r'... -> '....

Thanks, I didn't know that works.

Python 2, 92 bytes
lambda q:map(lambda a:a[1],sorted(map(lambda a:[int(re.sub("\D","",a)or 0),a],q)))
import re

Try it online!

PHP 7, 17 bytes
<?php natsort()?>

natsort — "Sort an array using a 'natural order' algorithm"


text:
Verifying a horizontal ASCII pet snake
Recently there have been a couple of ASCII pet snake challenges (e.g. here)
            0 0
  0        0 0 000
00 0     00       000 0      0
    000 0            0 0   00
       0                000

This challenge is to take a randomly generated horizontal pet snake (height of five lines, length of 30), and verify that :

Each column has only one 0
Each 0 is "connected" to the 0 before and after it (vertically spaced by 0 or 1 line only)

Final output can be true or 1 if the snake is valid, or false or 0 if the snake is invalid
Edit—Clarification
Assume the input:

Is a string
Contains only ' ', '0', and '\n'
Has exactly 30 characters each line
Has exactly 5 lines

I.e. verify whether the snake is connected, and that there are no stray chars. No need to validate the "canvas" that the snake is printed on.

Hi and welcome to PPCG :) This is a good challenge for a first post, but you probably want to add some more test cases that catch exceptional snakes. You also will probably want to decide if the snake has to be represented by zeros or can be any character. In the future, please consider using the sandbox. Good luck :)

Is this taken as a Sting? Or can it be input as a 2d array?

Are we guaranteed that the input consists of 0's and spaces? That every line has a length of 30? That there are 5 lines?

Waiting for the inevitable diagonal snake challenge...

Hmm, what about the polar snake? Or Ouroboros? :)

Can we choose a different character instead of 0?

Since this is a decision-problem how about truthy/falsey rather than true/false?

@JSchiff I'm sure a snake Bytes?

@MarioDS Except if it constraints then maybe it's a python?

I'm not really sure how a question that has 19 upvotes and 20 answers (at the time of commenting)  can justifiably be put on hold  as unclear particularly when many of the answers are from pretty high rep members who obviously have a lot of experience of these things. Maybe there is a justification for it being closed. In my (humble) opinion, "unclear" is not it. Just a bit surprised, that's all.

Sorry for the ambiguity—I've edited for clarification, can this be taken off hold?

@ElPedro Yes, it was unclear. There are 5~6 answers taking an array/list of strings as input, or assumes that input may be taken as a 2D array and provide multiple alternatives, or edit after the clarification.

JavaScript (ES2018), 62 54 bytes
s=>!/0(.{30}|.{60,62}(.{31})*)0|( .{30}){4} /s.test(s)

Input is a single string:

without trailing new line
contain only space, '0', and '\n'
30 characters each line, 5 lines, 154 character in total

Flag s means a dot match anything (including '\n'). This feature currently supported by Chrome 63+, Opera 50+, Safari 11.1+, based on compat-table. You may test this function with these supported browser. You will get an exception when loading the page if your browser do not support this feature.
How it works:

No column with no 0:

do not match /( .{30}){4} /

No two 0s in one column:

do not match /0.{30}(.{31})*0/

No 0 not connect to its neighbors:

do not match /0.{60}(.{31})*0/, /0.{62}(.{31})*0/

Merge all these regex, and you will finally got this one.

f =

s=>!/0(.{30}|.{60,62}(.{31})*)0|( .{30}){4} /s.test(s)
<textarea id=i style="width:100%;height:100px">            0 0
  0        0 0 000
00 0     00       000 0      0
    000 0            0 0   00
       0                000   </textarea>
<button onclick="o.value=f(i.value.slice(0,154))">Validate</button>
Result: <output id=o></output>

Thanks to Martin Ender point out that do a single ! operator may save 8 bytes.

SnakeEx, 51 bytes
This is obviously the right language for the task. :^D
s:({c<L>}{c<R>}0[(<R> <L>)(<L> <R>)_?])%{30}
c:0 *$

Matches the entire input if it is a valid snake; fails to match if it's not. Try it here!
Explanation
SnakeEx is a 2-D pattern matching language. A program consists of a list of definitions for "snakes," which crawl around the input matching characters, changing directions, and spawning other snakes. In our program, we define two snakes, s and c.
We'll start with c because it's simpler. Its definition is 0 *$, which should be quite readable if you know regex: match 0, followed by zero or more spaces, followed by the edge of the grid. The main catch here: this matching can proceed in any direction. We're going to use c both upward and downward from the snake, to verify that there are no extra 0s in each column.
Now for the main snake, s. It takes the form (...)%{30}, which means "match the contents of the parentheses 30 times"--once for each 0 in the snake. So far, so good. What goes inside the parentheses?
{c<L>}

This spawns a new c snake, turned left 90 degrees. The direction is relative to the s snake's direction, so the new snake moves toward the top of the grid (the main snake is moving toward the right). The c snake checks that the current grid cell is a 0 and that every cell above it is a space. If it fails, the whole match fails. If it succeeds, we continue with
{c<R>}

which does the same thing, only turned right (toward the bottom of the grid).
Note that these spawns don't affect the position of the match pointer in the main snake. They're a bit like lookaheads in regex. (Maybe here we could call them "lookbesides"?) So after verifying that we're pointing to a 0 and the rest of the column contains only spaces, we need to actually match the 0:
0

Now the match pointer is on the character to the right of the 0. We need to check three different options: the snake angles down, the snake angles up, or the snake goes straight. For this, we can use an OR expression:
[...]

Inside our OR, we have three possibilities:
(<R> <L>)

Turn right, match a space, and turn left again (snake angles down).
(<L> <R>)

Turn left, match a space, and turn right again (snake angles up).
_?

Match zero or one underscores. Since there are no underscores in the input, this will always be an empty match (snake goes straight).
After matching one of the above three options, the match pointer should be pointing to the 0 in the next column, ready to match the parenthesized expression again.

Jelly, 16 bytes
Zµi€”0IỊ;ċ€⁶=4ƊẠ

Try it online!
Assumes that the input string will always only contain only spaces and zeros. Takes input as a list of strings (each representing a line), and outputs 1 if truthy, 0 otherwise.
Explanation
Zµi€”0IỊ;ċ€⁶=4ƊẠ | Monadic full program.
Z                | Transpose.
 µ               | Start a new monadic chain.
  i€”0           | Retrieve the first index of 0 in each column.
      IỊ         | Check whether their increments are insignificant (element-wise).
        ;     Ɗ  | Append the result of the following:
         ċ€⁶     | In each list of characters, count the occurrences of a space.
            =4   | Check whether they equal 4 (returns a boolean array).
               Ạ | All. Check whether all the elements are truthy.

Husk, 12 bytes
Depending on rule clarifications, may be 11 bytes or 13 bytes.
±Λ=;1Ẋ×≈mηfT

Try it online!
Input is a list of lines containing only spaces and 0s; if a single string is required, prepend ¶ to the program to split into lines.
The TIO link already does this for clarity.
Output is 0 or 1; if any falsy and truthy values are fine, the ± can be removed.
Explanation
±Λ=;1Ẋ×≈mηfT  Implicit input: a list of lines.
           T  Transpose into list of columns.
        m     For each column,
         ηf   get list of indices of truthy elements.
              In Husk, whitespace characters are falsy and other are truthy,
              so this gets us the indices of 0s on each column.
     Ẋ        For each adjacent pair of these index lists,
      ×       for all pairs drawn from the two lists,
       ≈      give 1 if they differ by at most 1, otherwise 0.
              For each adjacent pair, this produces a list of 1s and 0s.
 Λ            Do all of these lists
  =;1         equal [1]? Return either 0 or 30 (length of the outer list + 1).
±             Signum; convert to 0 or 1.

The idea is to use ×≈ to guarantee that (a) all columns contain precisely one 0, and (b) their positions differ by at most one.
As an example, consider the 8-column input
0  0  0
 000 0
  00   0

First, mηfT transforms it to the list of index lists
[[1],[2],[2,3],[1,2,3],[],[2],[1],[3]]

Then Ẋ×≈ gives
[[1],[1,1],[1,1,0,1,1,1],[],[],[1],[0]]

Each 1 corresponds to a pair of indices that differ by at most 1, and each 0 corresponds to a pair that doesn't.
Each result equals [1] precisely when both lists have one index, and the indices differ by at most 1.

CJam, 35 34 bytes
{z_{'0e=1=}%:*\'0f#2ew::-[W0X]-!*}

Try it online! Input is a rectangular array of arrays of characters. Assumes input only contains   and 0.
Explanation:
{z_{'0e=1=}%:*\'0f#2ew::-[W0X]-!*}   Function taking a character matrix:
 z                                      Transpose.
   {      }%                            Consider whether each row
      e=                                  contains
        1=                                exactly one
    '0                                    of the character '0'.
            :*                            This must be true for every row.
                  #                     Next, find the position
               '0                         of the character '0'
                 f                        at every row
  _           \                           in the original input.
                       :-               Find the differences between
                      :                   each
                   2                      pair
                    ew                    of adjacent elements (in other words, compute
                                            the increments).
                                        For the snake to be valid, this array of increments
                                            must only contain {0, 1, -1}, so
                              -         Remove from this list
                         [   ]            the elements
                          W                 -1,
                           0                0,
                            X               and 1,
                               !          and then check whether the array is empty.
                                *       The previous code tested two different properties
                                          of the matrix; they both must be true for a
                                          valid snake.

05AB1E, 18 bytes
ζDε0k}¥Ä2‹sεþg}ìPΘ

Try it online!
Explanation
ζ                    # transpose
 D                   # duplicate
  ε  }               # for each row in the first copy (column of input)
   0k                # get the index of the first 0
      ¥Ä             # calculate absolute delta's
        2‹           # check that each is less than 2
          sε  }      # for each row in the second copy (column of input)
            þg       # calculate the length of the string with non-digits removed
               ì     # concatenate the lists
                P    # calculate product
                 Θ   # truthify (turn false values to 0)

C (gcc), 246 245 232 215 212 bytes
#define F)exit(1);
#define L for(i=l=0;i<30;i++)
#define X b[7][i]
char b[8][31];k,j,l;main(i){for(;j++<5;){gets(b);L{if(i[*b]>47){if(X++F memset(b[j+1]+i-1,l=1,3);}else if(!X&b[j][i]F}k+=!!l;}if(k<5 F L if(!X F}

Try it online!
Figured I'd take my favorite language to this (even though as I can see from the many other, smaller entries it's probably far from ideal for this sort of challenge) and C what I could manage. The program's approach to the problem is relatively straightforward, just with a lot of byte penny-pinching; it takes the snake on stdin and gives its result in the return value of main (thus the exit code; as requested in the problem 0 indicates an invalid snake and 1 valid even though for an exit code that's weird as typical for exit codes 0 is a valid snake and 1 is an invalid snake). With the macros expanded and some nice whitespace it looks more like the following:
char b[8][31];l,j,k;                           //Declares a buffer to work in, initialized all to 0; l j and k default to int and as globals are init to 0
main(i) {                                      //This is run no-args, so argc is 1 and the undeclared type defaults to int.
  for (; j++ < 5;) {                           //Iterating over each row, 1-indexed for convenience accessing the buffer
    gets(b);                                   //Reads into b[0] because of stack array decl layout
    for (i = l = 0; i < 30; i++) {             //j and l both init each time we begin this overall loop
      if (i[*b] > 47) {                        //Did we read a zero?
        if(b[7][i]++) exit(1);                 //If the snake already had a zero in this column, fail out
        memset(b[j+1] + i-1, l = 1, 3);        //Expect them on the next row in the columns left and right of this one (also set l)
      } else if (!b[7][i] & b[j][i]) exit(1);  //If we didn't read a zero, and we had reason to expect one this row, and there wasn't already a zero in this column, fail out
    }
    k+=!!l;                                    //Adds 1 to k iff l is nonzero
  } if (k < 5) exit(1);                        //If less than 5 rows had zeroes in them, fail out
  for(i = l = 0 ; i < 30; i++) {               //l isn't relevant in this loop but saves some bytes when sharing a macro with the other horizontal loop
    if(!b[7][i]) exit(1);                      //If any columns didn't have zeroes, fail out
  }                                            //Else, snake is valid. main default returns 0.
}

Lines of input are read into the first row of the buffer, the next five are for tracking what places are expected to (read: must) have zeroes in the row after each current one, and the last is for tracking whether a zero has already been read in a given column, in any row. The program processes each row in turn.
It's not at all robust (gets() is only the beginning) and the input must contain all the relevant spaces (no left-off trailing whitespace for instance), and gcc spews warnings and notes about stdlib functionality left implicitly declared and so on, but, C la vie.
It also assumes that the snake head need not be in the center row, and that a valid snake must have at least one zero in every row (i.e. no rows of all spaces in the 5 input rows). If the latter's not a requirement it can be made a bit shorter - everything to do with k and l in the program can be pared out or replaced with fewer bytes of code in that case.
Thanks to user202729 for approx. 26 bytes saved.

Welcome to PPCG! And, don't worry about shorter programs in other languages.

You can left out the space between #define F and ) for -1 byte.

Also, because the input only have \n (10), <space> (32) and 0 (48) you can check for ==48 with >47 (-1 byte). / You can remove the ={0} when initialize b if the variable is global. Similarly make k global and i a (untyped -> int) parameter of main (in place of argc which is 1).

Thank you! Edited before I saw the latter suggestions; I'll tick my way through them (that i as argc is genius). First drafts of this were well over 400 bytes; took me long enough just to drag it down to my personal goals of 300 and then 256 so there may well be more ways to slim it down I've missed.

Decided to make k, j, and l all globals to save on having separate int declarations, then realized the defaults would let me get away with leaving the type off entirely. Thanks again!

l?k++:k can be k+=!!l. k != 5 can be k<5.

Some && can be & too. Tips for golfing in C

Because for program return value 0 is success and 1 is fail, you can return 1 when the snake is invalid and 0 when it's valid, remove 8 bytes (as you don't need an explicit exit(0))

b[0][j] can be j[*b]

Thanks for the link and all the other bits besides! There's a tweak I'll need to make to another spot before I can replace && in this case - tried the bitwise & a while ago and broke my execution, but I think I just found a way around the problem. As for the return value, I was just sticking close to the prompt.

-1 byte using this.

183 bytes

Python 2, 71 bytes
f=lambda s:s[1]<' 'or'0'in s[::31]in' %s '%s[1::31]in'%6s'%0*2*f(s[1:])

Try it online!
Takes input as a multiline string. Tests case from Bubbler.
The first column is extracted as s[::31] and the second as s[1::31], and they are checked for validity. We recurse on s removing the first character, causing successive pairs of columns to be checked.
The check for two columns uses Python's comparison chaining for in combine multiple checks:

'0'in s[::31] checks that the first column has at least one 0
s[::31]in' %s '%s[1::31] checks that the first column is a substring of the second column sandwiches between two spaces, which ensures the position of the 0 has shifted at most one space
' %s '%s[1::31]in'%6s'%0*2 checks that the second column contains at most one 0.

The ending *f(s[1:]) also forces the recursive case to be true.

Now that I think about it, Python is an awesome language for these "snake" challenges. :P

MATL, 18 17 bytes
32>&fun30=wd|2<vA

Input is a 2D char array. Any non-space character can be used for the snake.
Try it online!
Explanation
32>      % Implicit input. Transform non-space into 1, space into 0
&f       % Push vector of row indices and vector of column indices of nonzeros
u        % Unique: vector of deduplicated entries
n        % Length
30=      % Does it equal 30? (*)
w        % Swap. Moves vector of row indices to top
d|       % Absolute consecutive differences
2<       % Is each value less than 2? (**)
v        % Concatenate results (*) and (**) vertically
A        % All: true if all entries are nonzero. Implicit display

The spec implies the line lengths being 30 is guaranteed, so I think you can save a few.

@JonathanAllan Thanks! I'm using un30= to check that all column indices are different, and none of the 30 columns is empty. Maybe I can test that more directly, but I don't see how

Jelly, (14?*) 13 bytes
Zn⁶T€z-IỊ0-¦Ȧ

A monadic link taking a list of five strings*, each of length 30 consisting of spaces and any other characters (e.g. 0s), and returning an integer (1 if a snake as defined, 0 otherwise)
* If input must be a single string (list of characters) then prepend a Ỵ to split the string at line feeds.
Try it online!
How?
Zn⁶T€z-IỊ0-¦Ȧ - Link: list of lists of characters, Lines
Z             - transpose the lines -> columns
  ⁶           - literal space character
 n            - not equal? -> 0 where there were spaces and 1 where there were "0"s
   T€         - truthy indices for each -> e.g. [0,0,1,0,0] -> [3] or [0,1,1,0,0] -> [2,3]
              -                           note: [0,0,0,0,0] -> []
      -       - literal minus one
     z        - transpose with filler (-1) -> {valid: a single list of heights {top:1,...,bottom:5}
              -                              invalid: list of >1 lists, some of which contain -1
              -                                       ...OR an empty list (no 0s in the input at all)}
       I      - differences -> {up:-1; down:1; flat:0; invalid:-6,-5,...,-2,2,...4}
        Ị     - insignificant (abs(z)<=1) -? {up/down/flat:1; invalid:0}
           ¦  - sparse application///
         0    - ...action: literal zero
          -   - ...to indices: [-1] -> make penultimate list into a zero (when one exists)
            Ȧ - any & all -> when flattened:{empty or contains a 0:0; otherwise:1}

Ah thought I'd tried all edge cases, thanks for the heads-up; will have to address later.

@LuisMendo heh and in fixing that I saved three, so thanks again!

... uh, but I introduced another. Fixed up for another 3 :(

Not a bad byte-count though :-)

Stax, 20 bytesCP437
Å┴m▐◘5)ît╢V¼≥+╝╜►º½ê

24 bytes when unpacked,
LM{'0|Ic%vChm:-{Jh!f%29=

Run and debug online!
May not be the best golfed one but I think the method is novel and interesting.
Explanation
LM                          Load the input string as a 2d array of characters, and transpose it

  {         m               Map array with block
   '0|I                     Get all indices of substring "0"
       c%vC                 Map to nothing if the indices are not unique
           h                Otherwise map to the unique index

             :-             Take pairwise difference

               {   f        Filter array with block
                Jh!         Only keep 0, 1 and -1

                    %29=    Check whether the final array has exactly 29 elements

Grime, 30 26 23 bytes
Thanks to Zgarb for saving 7 bytes and pointing out a bug.
e`" 0/0 "oO|#29ddv&d#1+

Try it online!

Slip, 28 bytes
((\|/)?0(<(?| *$^)<){2}){30}

Test it here.

J, 38, 37 30 bytes
-8 bytes thanks to FrownyFrog
[:($e.~[:(-:*)2-/\])@:I.'0'=|:

Try it online!

How about [:(-:*)2-/\, check if all differences are −1, 0 or 1.

@FrownyFrog Yes, it's much beteter! Thank you!

@ FrownyFrog Hmm, I didn't realize that. I'll try to fix it. Thank you for pointing that out.

@ FrownyFrog - I submitted a revised solution, based on counting the '0's in a different way. It could most probably be golfed further.

[:(#@{.=[:(-:*)2-/\])@:I.'0'=|:

Oh, this also works [:($e.~[:(-:*)2-/\])@:I.'0'=|:

@FrownyFrog Thanks! (you put a lot of efforts in this :) )

Jelly, 19 bytes
Zn⁶T€L€=1$$;FIỊ$$$Ạ

Try it online!
-2 bytes thanks to Mr. Xcoder
Explanation
Zn⁶T€L€=1$$;FIỊ$$$Ạ  Main Link
Z                    Transpose the matrix of characters
                         (string -> list of chars in Jelly)
 n⁶                  != " " (vectorizing)
   T€                For each column, get (row) indices of snake parts
     L€=1$$          For each index list, is its length 1? (that is, exactly one snake part per column)
           ;     $   Append (helper part)
            FIỊ$$    helper part:
            F        flatten index list
             I       get increments/forward differences
              Ị      are the values insignificant? (|z| <= 1)
                  Ạ  Are these all true?

Input is as a list of strings

@Mr.Xcoder Huh fail, Jelly string representation issues lol. fixed by ungolfing the 1 byte

Python 2 and Python 3, 122 120 119 bytes
lambda s:s.count('0')<31and all(s[i-31*(i>30):31*(i<124)-~i:31].strip(' ')for i,x in enumerate(s,1)if' '<x)and' '<s[62]

Try it online!
Input format is one string of length 154 (5 x 30 chars, 4 newlines):
'''
            0 0
  0        0 0 000
00 0     00       000 0      0
    000 0            0 0   00
       0                000   '''[1:] # to exclude starting newline

If the head doesn't have to be the center row
The center-row-head requirement was in the original challenge, but I found that it's not the case here (at least it's not explicitly mentioned).
Python 2 and Python 3, 124 123 bytes
lambda s:s.count('0')<31and all(s[i-31*(i>30):31*(i<124)-~i:31].strip(' ')for i,x in enumerate(s,1)if' '<x)and'0'in s[::31]

Try it online!

Edit:

Reduced 2 bytes by changing equals(==) into inequalities for each code.
Found mistakes in the less limiting version, and revised it. (Fortunately it's not too terrible, so I could keep all versions similar in length.) You can see additional test cases in the latter two TIO links.
Found a dangling byte in Py2 solutions, making the all() trick meaningless in Py3, so merged both versions.

Pip -r, 26 24 bytes
$&ZgM{0Na<2>yAD#y*Ya@?0}

Takes the snake from stdin and outputs 0 for invalid or 1 for valid. Attempt This Online!
Explanation
This was fun. I went through several different versions, finally ending up with a solution that abuses the y variable delightfully and also shows off Pip's chaining comparison operators.
$&ZgM{0Na<2>yAD#y*Ya@?0}
                          g is list of lines of stdin (-r flag); y is "" (implicit)
  Zg                      Zip g, transposing rows and columns
    M{                 }  To each sublist (column of the original input), map this function:
      0Na                  The number of 0s in this column
         <2                 is less than 2
           >                and 2 is greater than the following quantity:
            y                The index of the 0 in the previous column, or "" if this is
                              the first column
             AD              Absolute difference with
               #y*            len(y) times
                   a@?0       the index of 0 in this column
                  Y           which we also store in y
$&                        Fold the resulting list on logical AND

The expression yAD#y*Ya@?0 warrants further explanation. We want to calculate the difference between the indices of 0s in consecutive columns. We calculate the index of 0 in the current column (a@?0) and store it in y by using the Yank operator (Ya@?0).
But then how can we access the previous column's index, which was stored in y? We'll have to access it before overwriting y with the new value. Since Pip expressions are always evaluated left-to-right, we can use the old value of y on the left side of the expression and update to the new value on the right.
The first column presents another wrinkle. Here, when we access the old value of y, we haven't had a chance to set it to anything yet, and it still has its initial value of "". We want the first column to succeed no matter what its 0 index is, which means we need the difference to be between -1 and 1. So we multiply the new value by the length of the old value (#y). If y hasn't been set yet, this multiplies the new value by 0, making the difference 0. If y has been set, it will be a single-digit number (since there are only 5 rows in the input), and so multiplying by its length will leave the new value unchanged.

Vyxal, 14 bytes
∩ȧvT:v₃$¯ȧ2<JA

Try it Online!
Takes input as a list of char lists.
∩              # Transpose the input
 ȧ             # Remove whitespace (since this is a char list list, spaces become empty)
  vT           # Truthy indices (indices of 0) of each
            JA # Are both...
    :v₃        # All elements are length 3
       $¯ȧ     # And all elements have absolute differences
          2<   # Less than 2.

Excel (VBA), 68 bytes
Using Immediate Window, Cell[A6] as output.
[A1:AD5]="=CHOOSE(ROUND(RAND()+1,),0,"""")":[A6]="=COUNT(A1:AD5)=30"

Snails, 18 bytes
\0!(ud.,\0)raa7)30

Try it online!

Ruby, 93 bytes
->x{x.transpose.map{|x|x.count(?0)<2&&x.index(?0)}.each_cons(2).all?{|x,y|x&&y&&(x-y).abs<2}}

Try it online!

Python 2, 141 bytes
lambda g:(lambda a:all(map(len,a)+[-2<x-y<2 for b in[sum(a,[])]for x,y in zip(b,b[1:])]))([[i for i in range(5)if"0"==r[i]]for r in zip(*g)])

Try it online!
Input is a grid of characters.

JavaScript (Node.js), 128 126 bytes
Edited after input clarification stating that the input is "a string".
F=(a,l=29,r=0,t=/^( *)0 *$/.exec(a.split`
`.map(p=>p[l]).join``),q=t&&~t[1].length)=>q&&(s=q-(r=r||q))>-2&s<2?l?F(a,l-1,q):1:0

Try it online!

Python 3, 197 185 bytes
In command prompt do verify.py<snake.txt or in bash do cat snake.txt | python verify.py. Where snake.txt is a file containing a snake to verify.
If the snake is correct nothing will be output. If it isn't correct Python will raise an index error.
import sys
s=sys.stdin.read().split("\n")
x=0
exec('t,y="",0\nwhile y<5:t+=s[y][x];y+=1\ns+=[t];x+=1;'*30)
s=list(map(lambda l:len(l.rstrip()),s))
while y<35:"ee"[abs(s[y]-s[y+1])];y+=2

Oh, didn't notice that my output had to be either true or false. Does the error code returned count?

Golfed 12 bytes.