Python 2.6+ - 334 322 316 个字符
397 368 366 个未压缩字符
#coding:l1
exec'xÚEPMO!½ï¯ i,P*Ýlš%ì‰=‰Ö–*†þz©‰:‡—Lò¾fÜ”bžAù,MVi™.ÐlǃwÁ„eQL&•uÏÔ‹¿1O6ǘ.€LSLÓ’¼›î”3òšL¸tŠv[ѵl»h;ÁºŽñÝ0Àë»Ç‡ÛûH.ª€¼âBNjr}¹„V5¾3Dë@¼¡•gO. ¾ô6 çÊsÃЮürÃ1&›ßVˆùZ`Ü€ÿžcx±ˆ‹sCàŽ êüRô{U¯ZÕDüE+³ŽFA÷{CjùYö„÷¦¯Î[0þøõ…(Îd®_›â»E#–Y%’›”ëýÒ·X‹d¼.ß9‡kD'.decode('zip')
需要一个换行符,我把它算作一个字符。
浏览器代码页 mumbo jumbo 可能会阻止成功复制和粘贴此代码,因此您可以选择从此代码生成文件:
s = """
23 63 6F 64 69 6E 67 3A 6C 31 0A 65 78 65 63 27 78 DA 45 50 4D 4F 03 21
10 BD EF AF 20 69 2C 50 2A 02 DD 6C 9A 25 EC AD 07 8D 89 07 3D 89 1C D6
96 2A 86 05 02 1B AD FE 7A A9 89 3A 87 97 4C F2 BE 66 DC 94 62 9E 41 F9
2C 4D 56 15 69 99 0F 2E D0 6C C7 83 77 C1 16 84 65 51 4C 26 95 75 CF 8D
1C 15 D4 8B BF 31 4F 01 36 C7 98 81 07 2E 80 4C 53 4C 08 D3 92 BC 9B 11
EE 1B 10 94 0B 33 F2 9A 1B 4C B8 74 8A 9D 76 5B D1 B5 6C BB 13 9D 68 3B
C1 BA 8E F1 DD 30 C0 EB BB C7 87 DB FB 1B 48 8F 2E 1C AA 80 19 BC E2 42
4E 6A 72 01 7D B9 84 56 35 BE 33 44 8F 06 EB 40 BC A1 95 67 4F 08 2E 20
BE F4 36 A0 E7 CA 73 C3 D0 AE FC 72 C3 31 26 9B DF 56 88 AD F9 5A 60 DC
80 FF 9E 63 78 B1 88 8B 73 43 E0 8E A0 EA FC 52 F4 7B 55 8D AF 5A 19 D5
44 FC 45 2B B3 8E 46 9D 41 F7 7B 43 6A 12 F9 59 F6 84 F7 A6 01 1F AF CE
5B 30 FE F8 F5 85 28 CE 64 AE 5F 9B E2 BB 45 23 96 59 25 92 9B 94 EB FD
10 D2 B7 58 8B 64 BC 2E DF 39 87 6B 44 27 2E 64 65 63 6F 64 65 28 27 7A
69 70 27 29
"""
with open('golftris.py', 'wb') as f:
f.write(''.join(chr(int(i, 16)) for i in s.split()))
测试
积分
[ ]
[ ]
[ ]
[ ]
[###]
[########]
[===========]
T2 Z6 I0 T7
换行符必须是 Unix 风格的(仅限换行符)。最后一行的尾随换行符是可选的。
去测试:
> python golftris.py < 整数
[ ]
[ ]
[ ]
[####]
[####]
[##### ####]
[===========]
10
此代码解压缩原始代码,并使用exec
. 这个解压后的代码有 366 个字符,看起来像这样:
import sys
r=sys.stdin.readlines();s=0;p=r[:1];a='[##########]\n'
for l in r.pop().split():
n=int(l[1])+1;i=0xE826408E26246206601E>>'IOZTLSJ'.find(l[0])*12;m=min(zip(*r[:6]+[a])[n+l].index('#')-len(bin(i>>4*l&31))+3for l in(0,1,2))
for l in range(12):
if i>>l&2:c=n+l/4;o=m+l%4;r[o]=r[o][:c]+'#'+r[o][c+1:]
while a in r:s+=10;r.remove(a);r=p+r
print''.join(r),s
换行符是必需的,每个换行符是一个字符。
不要试图阅读这段代码。变量名称实际上是随机选择的,以搜索最高压缩(使用不同的变量名称,压缩后我看到多达 342 个字符)。一个更容易理解的版本如下:
import sys
board = sys.stdin.readlines()
score = 0
blank = board[:1] # notice that I rely on the first line being blank
full = '[##########]\n'
for piece in board.pop().split():
column = int(piece[1]) + 1 # "+ 1" to skip the '[' at the start of the line
# explanation of these three lines after the code
bits = 0xE826408E26246206601E >> 'IOZTLSJ'.find(piece[0]) * 12
drop = min(zip(*board[:6]+[full])[column + x].index('#') -
len(bin(bits >> 4 * x & 31)) + 3 for x in (0, 1, 2))
for i in range(12):
if bits >> i & 2: # if the current cell should be a '#'
x = column + i / 4
y = drop + i % 4
board[y] = board[y][:x] + '#' + board[y][x + 1:]
while full in board: # if there is a full line,
score += 10 # score it,
board.remove(full) # remove it,
board = blank + board # and replace it with a blank line at top
print ''.join(board), score
症结在于我说过我会解释的三个神秘的行。
四联骨牌的形状在那里以十六进制数字编码。每个 tetronimo 被认为占据一个 3x4 的单元格网格,其中每个单元格要么是空白的(空格),要么是完整的(数字符号)。然后用 3 个十六进制数字对每个片段进行编码,每个数字描述一个 4 单元列。最低有效位描述最左边的列,每个数字中的最低有效位描述每列中最顶部的单元格。如果位为 0,则该单元格为空白,否则为“#”。例如,I tetronimo 被编码为00F
,最低有效位的四位设置为对最左列中的四个数字符号进行编码,而T是131
, 最高位设置在左侧和右侧,最高两位设置在中间。
然后将整个十六进制数向左移动一位(乘以 2)。这将允许我们忽略最底部的位。我会在一分钟内解释为什么。
因此,给定输入中的当前片段,我们找到这个十六进制数的索引,其中 12 位描述它的形状,然后将其向下移动,以便bits
变量的位 1-12(跳过位 0)描述当前片段。
的分配drop
决定了该棋子在落在其他棋子碎片之前从网格顶部掉落的行数。第一行查找比赛场地每列顶部有多少空单元格,而第二行查找棋子每列中占用最低的单元格。该zip
函数返回一个元组列表,其中每个元组由输入列表中每个项目的第n个单元格组成。因此,使用示例输入板,zip(board[:6] + [full])
将返回:
[
('[', '[', '[', '[', '[', '[', '['),
(' ', ' ', ' ', ' ', ' ', ' ', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', ' ', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(']', ']', ']', ']', ']', ']', ']')
]
我们从这个列表中选择对应于适当列的元组,并找到列中第一个的索引'#'
。这就是为什么我们在调用之前附加了一个“完整”行zip
,以便index
当该列为空白时会有一个合理的返回(而不是抛出异常)。
然后为了找到'#'
每列中的最低值,我们移动并屏蔽描述该列的四个位,然后使用该bin
函数将其转换为一串 1 和 0。该bin
函数只返回有效位,因此我们只需要计算该字符串的长度即可找到最低占用单元(最高有效位)。该bin
函数还前置'0b'
,所以我们必须减去它。我们也忽略了最低有效位。这就是为什么十六进制数向左移动一位的原因。这是为了考虑空列,其字符串表示形式与仅顶部单元格已满的列具有相同的长度(例如T块)。
例如,如前所述,IF
tetromino 的列是、0
和0
。 bin(0xF)
是'0b1111'
。忽略 后'0b'
,我们的长度为 4,这是正确的。但是bin(0x0)
是0b0
。忽略 后'0b'
,我们的长度仍然是 '1,这是不正确的。为了解决这个问题,我们在末尾添加了一个额外的位,以便我们可以忽略这个无关紧要的位。因此,+3
代码中的 是为了说明开头占用的额外长度'0b'
,以及末尾的无关紧要的位。
所有这些都发生在三列 ( (0,1,2)
) 的生成器表达式中,我们利用min
结果来找到该片段在触及三列中的任何一列之前可以删除的最大行数。
通过阅读代码,其余部分应该很容易理解,但是for
这些分配之后的循环会将这块添加到板上。在此之后,while
循环删除完整的行,用顶部的空白行替换它们,并计算分数。最后,将棋盘和分数打印到输出中。