Julia, 90 karakter
s->all(cumsum(map(i->i∈"!|.\":"?-1:i∈"()_@\$&",mapfoldl(collect,hcat,split(s,"
")))').>-1)
Berbeda dengan solusi asli (di bawah), ini menggunakan matematika untuk menentukan solusi. mapfoldl(collect,hcat,split(s,"\n"))(ditulis di atas dengan \ndiganti dengan baris baru yang sebenarnya untuk menyimpan karakter) mengubah string menjadi array karakter 2d. map(i->i∈"!|.\":"?-1:i∈"()_@\$&",...)menciptakan array angka, dengan 1 jika karakternya adalah awan, -1 jika karakternya hujan, dan 0 sebaliknya.
cumsum(...')menghitung jumlah kumulatif dari baris (biasanya akan ditulis cumsum(...,2), tetapi karena kita tidak peduli tentang orientasi sejak saat ini, mentransposisi hanya biaya satu karakter), dan kemudian all(... .>-1)memeriksa angka negatif - negatif hanya akan terjadi jika karakter hujan muncul tanpa didahului oleh karakter cloud.
Julia, 139 136 karakter
s->(t=join(mapfoldl(i->split(i,""),.*,split(s,"
")),"
");while t!=(t=replace(t,r"[()_@$&](.*?)[!|.\":]",s"\g<1>"))end;∩("!|.\":",t)==[])
Fungsi ini pertama-tama mentransposisi teks sehingga baris menjadi kolom dan sebaliknya. Perhatikan bahwa baris baru hadir dalam kode dalam bentuk baris baru yang sebenarnya, untuk menyimpan satu karakter per instance.
Fungsi kemudian secara iteratif menggantikan pasangan cloud / droplet dengan spasi, dan setelah semua pasangan tersebut dihapus, ia mengembalikan true jika ada tetesan yang tersisa dan false jika tidak.
r"[()_@$&](.*?)[!|.\":]"- ini adalah regex yang akan mencocokkan pasangan cloud / droplet dengan cara yang malas, dengan grup 1 berisi segalanya antara cloud dan droplet. Kemudian s"\g<1>"suruh untuk menghapus awan dan tetesan yang cocok, tetapi simpan di antara keduanya (diperlukan karena dapat mengandung awan) - \g<1>adalah apa pun yang cocok di grup 1 regex. ∩("!|.\":",t)==[]akan menghasilkan persimpangan karakter tetesan dengan string terakhir, dan jika kosong, maka tidak ada karakter tetesan hadir, dan hujan.