The basics:
Consider the following tetrominoes and empty playing field:
0123456789 I O Z T L S J [ ] [ ] # ## ## ### # ## # [ ] # ## ## # # ## # [ ] # ## ## [ ] # [ ] [==========]
The dimensions of the playing field are fixed. The numbers at the top are just here to indicate the column number (also see input).
Input:
1. You are given a specific playing field (based on the above) which can already be filled partly with tetrominoes (this can be in a separate file or provided via stdin).
Sample input:
[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========]
2. You are given a string which describes (separated by spaces) which tetromino to insert (and drop down) at which column. Tetrominoes don't need to be rotated. Input can be read from stdin.
Sample input:
T2 Z6 I0 T7
You can assume input is 'well-formed' (or produce undefined behaviour when it's not).
Output
Render the resulting field ('full' lines must disappear) and print the score count (every dropped line accounts for 10 points).
Sample output based on the sample input above:
[ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
Winner:
Shortest solution (by code character count). Usage examples are nice. Have fun golfing!
Edit: added a bounty of +500
reputation to draw some more attention to the nice efforts the answerers already made (and possibly some new solutions to this question)...
Perl,
586 523 483 472 427 407 404 386 387 356353 chars(Needs Perl 5.10 for the defined-or
//
operator).Takes all input from stdin.
Still needs some serious golfing.Note that ^Q represents ASCII 17 (DC1/XON), ^C represents ASCII 3 and ^@ represents ASCII 0 (NUL).
Commented version:
Edit 1: some serious golfing, fix output bug.
Edit 2: some inlining, merged two loops into one for a net saving of (drum roll...) 3 chars, misc golfing.
Edit 3: some common subexpression elimination, a little constant merging and tweaked a regex.
Edit 4: changed representation of tetrominoes into a packed bit vector, misc golfing.
Edit 5: more direct translation from tetromino letter to array index, use non-printable characters, misc golfing.
Edit 6: fixed bug cleaning top line, introduced in r3 (edit 2), spotted by Nakilon. Use more non-printable chars.
Edit 7: use
vec
for getting at tetromino data. Take advantage of the fact that the playfield has fixed dimensions.if
statement =>if
modifier, the merging of loops of edit 2 starts paying off. Use//
for the 0-score case.Edit 8: fixed another bug, introduced in r6 (edit 5), spotted by Nakilon.
Edit 9: don't create new references when clearing lines, just move references around via array slicing. Merge two
map
's into one. Smarter regex. "Smarter"for
. Misc golfings.Edit 10: inlined tetromino array, added commented version.
C,
727 [...] 596 581 556 517 496 471 461457 charsThis is my first code golf, I think character count can get
muchlower, would be nice if experienced golfers can give me some hints.The current version can handle playfields with different dimensions, too.The input can have linebreaks in both DOS/Windows and Unix format.The code was pretty straightforward before optimization, the tetrominoes are stored in 4 integers that are interpreted as an (7*3)x4 bit array, the playfield is stored as-is, tiles are dropped and complete lines are removed at start and after each tile drop.
I wasn't sure how to count characters, so I used the filesize of the code with all unneccessary linebreaks removed.
EDIT 596=>581: Thanks to KitsuneYMG, everything except the
%ls
suggestion worked perfectly, additionally, I noticedputch
instead ofputchar
can be used (getch
somehow doesn't work) and removed all the parentheses in#define G
.EDIT 581=>556: Wasn't satisfied with the remaining
for
and the nestedF
loops, so there was some merging, changing and removing of loops, quite confusing but definitely worth it.EDIT 556=>517: Finally found a way to make
a
an int array. SomeN;
merged withc
, nobreak
anymore.EDIT 496=>471: Playfield width and height fixed now.
EDIT 471=>461: Minor modifications,
putchar
used again asputch
is no standard function.EDIT: Bugfix, complete lines were removed before tile drop instead of after, so complete lines could be left at the end. Fix doesn't change the character count.
Python 2.6+ -
334322316 characters397368366 characters uncompressedThe single newline is required, and I've counted it as one character.
Browser code-page mumbo jumbo might prevent a successful copy-and-paste of this code, so you can optionally generate the file from this code:
Testing
intetris
Newlines must be Unix-style (linefeed only). A trailing newline on the last line is optional.
To test:
This code unzips the original code, and executes it with
exec
. This decompressed code weighs in at 366 characters and looks like this:Newlines are required, and are one character each.
Don't try to read this code. The variable names are literally chosen at random in search of the highest compression (with different variable names, I saw as much as 342 characters after compression). A more understandable version follows:
The crux is in the three cryptic lines I said I'd explain.
The shape of the tetrominoes is encoded in the hexadecimal number there. Each tetronimo is considered to occupy a 3x4 grid of cells, where each cell is either blank (a space) or full (a number sign). Each piece is then encoded with 3 hexadecimal digits, each digit describing one 4-cell column. The least significant digits describe the left-most columns, and the least significant bit in each digit describes the top-most cell in each column. If a bit is 0, then that cell is blank, otherwise it's a '#'. For example, the I tetronimo is encoded as
00F
, with the four bits of the least-significant digit set on to encode the four number signs in the left-most column, and the T is131
, with the top bit set on the left and the right, and the top two bits set in the middle.The entire hexadecimal number is then shift one bit to the left (multiplied by two). This will allow us to ignore the bottom-most bit. I'll explain why in a minute.
So given the current piece from the input, we find the index into this hexadecimal number where the 12 bits describing it's shape begin, then shift that down so that bits 1–12 (skipping bit 0) of the
bits
variable describe the current piece.The assignment to
drop
determines how many rows from the top of the grid the piece will fall before landing on other piece fragments. The first line finds how many empty cells there are at the top of each column of the playing field, while the second finds the lowest occupied cell in each column of the piece. Thezip
function returns a list of tuples, where each tuple consists of the nth cell from each item in the input list. So, using the sample input board,zip(board[:6] + [full])
will return:We select the tuple from this list corresponding to the appropriate column, and find the index of the first
'#'
in the column. This is why we appended a "full" row before callingzip
, so thatindex
will have a sensible return (instead of throwing an exception) when the column is otherwise blank.Then to find the lowest
'#'
in each column of the piece, we shift and mask the four bits that describe that column, then use thebin
function to turn that into a string of ones and zeros. Thebin
function only returns significant bits, so we need only calculate the length of this string to find the lowest occupied cell (most significant set bit). Thebin
function also prepends'0b'
, so we have to subtract that. We also ignore the least significant bit. This is why the hexadecimal number is shift one bit to the left. This is to account for empty columns, whose string representations would have the same length as a column with only the top cell full (such as the T piece).For example, the columns of the I tetromino, as mentioned earlier, are
F
,0
, and0
.bin(0xF)
is'0b1111'
. After ignoring the'0b'
, we have a length of 4, which is correct. Butbin(0x0)
is0b0
. After ignoring the'0b'
, we still have a length of' 1, which is incorrect. To account for this, we've added an additional bit to the end, so that we can ignore this insignificant bit. Hence, the+3
in the code is there to account for the extra length taken up by the'0b'
at the beginning, and the insignificant bit at the end.All of this occurs within a generator expression for three columns (
(0,1,2)
), and we take themin
result to find the maximum number of rows the piece can drop before it touches in any of the three columns.The rest should be pretty easy to understand by reading the code, but the
for
loop following these assignments adds the piece to the board. After this, thewhile
loop removes full rows, replacing them with blank rows at the top, and tallies the score. At the end, the board and score are printed to the output.Golfscript 260 chars
I'm sure this could be improved, I'm kind of new to Golfscript.
End of lines are relevant (there shouldn't be one at the end). Anyway, here are some of the test cases I used:
Note that there is no end of line in the input file, an end of line would break the script as is.
Ruby —
427 408 398 369359Ruby
505 479 474 442 439426 charsA first attempt. Have done it with IronRuby. I'm sure it can be improved, but I really should get some work done today!
Testing
Edit Now using normal ruby. Got the walls output..