| Bytes | Lang | Time | Link |
|---|---|---|---|
| 033 | Jelly | 170809T150356Z | Jonathan |
| 124 | Python 3 | 170809T161621Z | lynn |
| 066 | APL Dyalog | 170812T080259Z | ngn |
| 087 | APL Dyalog | 170809T131944Z | Adá |
| 053 | Jelly | 170809T142320Z | Erik the |
| nan | Perl 5 | 170809T183714Z | Xcali |
| 164 | JavaScript ES6 | 170809T132651Z | ETHprodu |
| 060 | MATL | 170809T145946Z | Luis Men |
| 125 | Retina | 170809T154339Z | Neil |
Jelly, 54 43 42 41 33 bytes
§TḢ⁸ṫZUµƬ¬Ṃj1Ḅ“6÷¥*fÆ-‘i’ị“¥Çıƭ⁵»
A monadic Link that accepts a list of four lists each of four integers from \$[0,1]\$ and yields a character from zoistjlw where w means "not a tetromino".
Try it online! Or see the test-suite.
How?
The code firstly repeatedly:
- strips empty rows from the start of the input matrix
- rotates that a quarter clockwise until no change occurs, collecting the input and the results. For example:
[[0,0,0,0], => [[0, 0, 0], => [[0, 0, 0], => [[0, 1], => [[1, 1, 0],
[0,1,1,0], [0, 0, 1], [1, 1, 0], [1, 1], [0, 1, 1],
[0,0,1,1], [0, 1, 1], [0, 1, 1], [1, 0] ]
[0,0,0,0], [0, 1, 0]] ] ]
]
Then it inverts the values in all of these and picks the minimum, which will be a consistent one of the set of distinct, fully stripped rotations inverted, in this case:
[[0, 0, 1],
[1, 0, 0],
]
We need to be able to differentiate an inputted O tetromino from any other inputted square of ones, but both will produce a square matrix of zeros, so rather than flattening and converting to binary the code joins the resulting rows with ones and converts to binary. It then looks for the resulting integer in a list of the integers produced by each of the seven tetrominoes and uses the index (or 0 if not found) to look up the name in a compression of the words "zoist" and "jowl" concatenated:
§TḢ⁸ṫZUµƬ¬Ṃj1Ḅ“..‘i’ị“..» - Link: list of list of 0/1, M
µƬ - collect while distinct under:
§ - sums of rows
T - get truthy indices
Ḣ - head -> index of the first row with any ones
⁸ṫ - tail the matrix from that row
ZU - rotate a quarter clockwise
¬ - logical NOT (vectorises)
Ṃ - minimum
j1 - join with ones
Ḅ - convert from binary
“..‘i - first 1-indexed index of that in [54,28,4,42,102,13,45]
or 0 if not found (not a tetromino)
’ - decrement
ị“..» - index into "zoistjowl" (1-indexed and modular)
-> -1: w; 0..6: lzoistj
“6÷¥*fÆ-‘ is a list of code-page indices, [54,28,4,42,102,13,45].
“¥Çıƭ⁵» is a compressed string of the words zoist and jowl.
Here is a script that will categorise all the numbers in a range to the tetrominoes (those not listed are those for which the code yielded w). It is too slow for all \$2^{16}\$ so either run locally or run it a second time with an argument of range(32768, 65535) to see the rest.
Python 3, 124 bytes
def f(n):
while n&4369<n/n:n>>=1
while n&15<1:n>>=4
return'TJLZSIO'["rēȣc63ıGtIJȱᄑ@'̢̑@@@@Ȳq".index(chr(n))%7]
Expects an integer n representing a 4 × 4 binary matrix. Throws if no tetromino is found.
Line 2 slides the shape to the right until a 1 is in the rightmost column. (4369 is 0001 0001 0001 0001 in binary.) Line 3 lowers the shape until a 1 is in the bottom row. Together this turns e.g.:
0 1 0 0 0 0 0 0
1 1 1 0 into 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 1 1 1
Then we look for the index of n in this list:
[114 275 547 99 54 15 51
305 71 116 306 561 4369 64
39 802 785 64 64 64 64
562 113 23]
# T J L Z S I O
Each column of indices equivalent modulo 7 corresponds to a tetromino shape. 64 (@) is used as a padding value as n cannot be 64 at this point in the code.
NB. An exception is thrown for input 0 by computing n/n instead of 1.
APL (Dyalog), 66 bytes
{'TIOJSLZ-'[(¯51 144 64,,∘+⍨12J96 ¯48J64)⍳×/(+/-4×⊢)⍵/,0j1⊥¨⍳4 4]}
The arg is a boolean vector.
Computes signed distances of the dots to their centre of gravity as complex numbers (real and imaginary part are ∆x,∆y) and multiplies the complex numbers together. This turns out to be a good enough invariant to distinguish among the tetrominoes.
APL (Dyalog), 95 94 93 89 87 bytes
-2 thanks to Zacharý
Requires ⎕IO←0 which is default on many systems. Takes Boolean matrix (of any shape!) as argument. Returns nothing if the given number of bits is not four, and a blank line if the four given bits do not form a tetromino.
{4=+/,⍵:'OIZSJLT'/⍨∨/1∊¨(((2 2)4⍴¨1),(0 1⌽¨⊂K⌽2⊖J),(⍳3)⊖¨⊂J←1,⍪K←3↑1)∘.⍷⍵∘{⌽∘⍉⍣⍵⊢⍺}¨⍳4}
Works by creating all four rotations of the input, then looking for each tetromino in each rotation.
{…} anonymous function where the argument is represented by ⍵:
,⍵ ravel (flatten) the argument
+/ sum it
4= is four equal to that?
: if so, then (else return nothing):
⍳4 first four ɩndices; [0,1,2,3]
⍵∘{…}¨ apply the following function on each, using the input as fixed left argument
⍺ the left argument i.e. the input
⊢⍺ yield that (separates ⍵ from ⍺)
⌽∘⍉⍣⍵ mirror and transpose (i.e. rotate 90°) ⍵ times
(…)∘.⍷ outer "product", but using Find*, of the following list and the rotations:
3↑1 take three elements from one, padding with zeros; [1,0,0]
K← store that as K
⍪ table (make into column vector); [[1],[0],[0]]
1, prepend a one; [[1,1],[1,0],[1,0]] ("J")
J← store as J
(…)⊖¨⊂ rotate the entire J vertically, each of the following number of steps:
⍳3 first three ɩntegers; [0,1,2]
we have [[[1,1],[1,0],[1,0]],[[1,0],[1,0],[1,1]],[[1,0],[1,1],[1,0]]] ("J", "L, "T")
(…), prepend the following list:
2⊖J rotate J two steps vertically; [[1,0],[1,1],[1,0]] ("T")
K⌽ rotate the rows of that by 1, 0, and 0 steps respectively; [[0,1],[1,1],[1,0]] ("Z")
0 1⌽¨⊂ rotate the entire array vertically, no times and once; [[[0,1],[1,1],[1,0]],[[1,0],[1,1],[0,1]]] ("Z", "S")
(…), prepend the following list:
(2 2)4⍴¨1 reshape a one into each of a 2×2 matrix and a 4-element list; [[[1,1],[1,1]],[1,1,1,1]] ("O", "I")
1∊¨ for each, is one a member?
∨/ horizontal OR reduction (i.e. across rotations; one Boolean for each shape)
'OIZSLJT'/⍨ use that to filter the string
* Find returns a Boolean array of same shape as its right argument, with ones indicating the top left corner of all subarrays identical to the left argument.
Jelly, 53 bytes
ZL0ẋW⁸tZµ⁺ZU$3С“©©“œ“Ç¿“¦©¦“ƽ‘;Uḃ2$’¤iЀṀị“÷¶Ė¡µỵỤ»
Full program. Takes a 4x4. Prints m if not a tetromino, otherwise prints lowercase.
Perl 5, 197 + 1 (-p) = 198 bytes
s/(0000)*$//;1while s/(...)0(...)0(...)0(...)0/0${1}0${2}0${3}0${4}/;$_={51,O,15,I,4369,I,54,S,561,S,99,Z,306,Z,547,L,23,L,785,L,116,L,275,J,113,J,802,J,71,J,114,T,562,T,39,T,609,T}->{oct("0b".$_)}
Takes a 16 bit string as input. Outputs nothing if input is not a single tetromino.
How?
The two substitutions "move" the input shape to the bottom right corner. The resulting bit string is converted to an integer, then checked for in a hash of valid integers.
JavaScript (ES6), 242 212 172 164 bytes
x=>[...'OISZLJT'].filter((z,y)=>x.match(`^0*(${'99,33825|15,51|2145,195|561,2115|57,1059|135,71|1073'.split`,`[y].replace(/\d+/g,C=x=>x?x%2+C(x>>1)+x%2:'|')})0*$`))
Was supposed to be just to get the ball rolling, but I'm a little late for that ¯\_(ツ)_/¯
Takes a string of bits, with rows separated by 0s ('0001000110001000000' representing 0001 0011 0010 0000) and returns an array containing the character representing the tetromino, or an array containing nothing.
This works by checking each rotation of tetromino to see if the input at any point contains the tetromino, surrounded entirely by zeroes on either side. Each tetromino is represented by one or more binary numbers:
0 0 0 0 -> 0000 0110 1100 0000
0 1 1 0 -> 0000001100110000000
1 1 0 0 -> 110011
0 0 0 0 -> 51
0 1 0 0 -> 0100 0110 0010 0000
0 1 1 0 -> 0100001100001000000
0 0 1 0 -> 100001100001
0 0 0 0 -> 2145
So to check if the input contains an S tetromino, we simply check whether it contains the binary representation of either 51 or 2145, with only 0s on either side.
A few of the tetrominoes have 4 orientations. If you look at the binary representations of these, each has 2 representations which are simply the mirror of the other two. To save space, the binary representation is built up forward and backward simultaneously with the recursive C function, allowing us to only put two of the orientations in and have the other two implied.
Alternate approach with charcodes:
x=>[...'OISZLJT'].filter((z,y)=>x.match(`^0*(${[...'÷,êÿ,óî,ûÝ,ëúüÏ,çöïþ,ßýíÞ'.split`,`[y]].map(c=>(C=n=>n?'1e'+(n%4+2)%5-0+C(n>>2):'')(c.charCodeAt())).join`|`})0*$`))
MATL, 60 bytes
Itt6tIl7tl7H15vHe"4:"G@X!HYa]4$v@BIthYaEqY+4=aa]v'OSZLJTI'w)
Input is a binary 4×4 array (matrix), using ; as row separator. Ouput is a letter or empty for no tetromino.
Try it online! Or verify all test cases (output has a dot appended to allow identifying an empty result).
Explanation
The code builds 4 rotations of the input 4×4 array in steps of 90 degrees. Each rotated array is padded with 2 zeros up and down, which transforms it into a 8×4 array. The 4 arrays are vertically concatenated into a 32×4 array. The four rotated arrays within this concatenated array are "isolated" thanks to the zero-padding.
Each of the 7 possible patterns is tested to see if it is present in the 32×4 array. A loop is used for this. Each pattern is defined by two numbers, which expressed in binary give the appropriate 0/1 mask. For example, numbers 3, 6 define the "S" shape.
The 7 sets of 2 numbers are arranged into a 2×7 matrix, from which the loop will pick each column sequentially. The matrix is defined by pushing all numbers to the stack, contatenating them into a vector, and reshaping into a 2-row matrix. Since the "I" shape is defined by number 15 followed by 0, putting it at the end allows the 0 to be implicitly filled by the reshaping function.
The mask is then padded with 3 zeros in the four directions. This is necessary so as to detect unwanted values in the input.
To see if the mask is present in the 32×4 array, the latter is transformed to bipolar form (i.e. −1/1 instead of 0/1) and convolved with the mask. Since the mask has 4 ones, matching occurs if some entry in the convolution result equals 4.
At the end of the loop, 7 false/true results have been obtained, at most one of which is true. This is used to index into a string containing the possible output letters.
Retina, 125 bytes
s`(.*1){5}.*
{s`.*1111.*
I
s`.*111(.{2,4})1.*
$.1
T`234`\LTJ
s`.*11(.{2,4})11.*
$.1
T`2-90`S\OZ4-9
s`.*4.*
O#$`.
$.%`
O#$^`
Try it online! Link includes test cases plus a header to convert from integers to a 4×4 matrix. Explanation:
s`(.*1){5}.*
Delete the input if it contains 5 1s.
{s`.*1111.*
I
Check all rotations of the input (see below). If the input contains four consecutive 1s, it's an I.
s`.*111(.{2,4})1.*
$.1
T`234`\LTJ
If it contains three consecutive 1s plus a 1 on the next line underneath one of the three, then map the number of intermediate characters to the appropriate result letter.
s`.*11(.{2,4})11.*
$.1
Similarly for two adjacent 1s adjacent to two adjacent 1s on the next line.
T`2-90`S\OZ4-9
But also keep count of the number of rotations using the otherwise unused 0s.
s`.*4.*
And give up if too many rotations have been performed.
O#$`.
$.%`
O#$^`
Transpose and reverse the array, thus rotating it.