Zar*_*nen 10 code-golf reversi
好的,这是一个相当复杂的代码高尔夫挑战:实施一个黑白棋(奥赛罗)游戏.
以尽可能少的字符执行此操作.
会话应该看起来像这样:
abcdefgh
1
2
3
4 wb
5 bw
6
7
8
b>d3
abcdefgh
1
2
3 b
4 bb
5 bw
6
7
8
Run Code Online (Sandbox Code Playgroud)
Haskell,821个字符†,包括换行符.
import Array
import List
import Maybe
import IO
a=((1,0),(8,7))
z=zip
x=range
y=repeat
o=putStr
i=['a'..'h']
r=[0,1,-1]
d b=' ':i++concatMap(\i->'\n':show(i+1)++map g(take 8$drop(i*8)$elems b))[0..7]++"\n"
e=array a(z(x a)$y 0)//z(x((4,3),(5,4)))[1,-1,-1,1]
f b p i|b!i/=0=Nothing|True=if b==v then Nothing else Just v where v=foldr u b(map(takeWhile(inRange a).($i).iterate.(\(i,j)(k,l)->(i+k,j+l)))$tail[(i,j)|i<-r,j<-r]);u r m=m//case(group$map(m!)r)of([_]:c@(m:_):(l:_):_)|m/=0&&l==p->z(take(1+length c)$r)(y p);_->[]
g=fromJust.(`lookup`z[-1..1]"b w")
h b p=do o$g p:">";hFlush stdout;c:r<-getLine;case f b p(read r,head$elemIndices c i)of;Nothing->h b p;Just m->o(d m)>>case filter(\s->mapMaybe(f m s)(x a)/=[])[-1*p,p]of(n:_)->h m n;_->print$if w==' 'then 'd'else w where w=g$signum$sum$elems m
main=o(d e)>>h e 1
Run Code Online (Sandbox Code Playgroud)
以上内容基于此版本:
import Data.Array
import Data.List
import Data.Maybe
import System.IO
type Index = (Int, Int)
type Player = Int -- (-1, 0, 1) for white, unclaimed and black, resp.
type Board = Array Index Player
-- Infix function which add two vectors
(|+|) :: Index -> Index -> Index
(i, j) |+| (k, l) = (i + k, j + l)
-- The functions dim, pieces and board2Str must be updated if one wishes to
-- alter the board's dimensions.
-- Board dimensions
dim :: (Index, Index)
dim = ((0, 0), (7, 7))
-- The pieces that will initially be on the board
pieces :: [(Index, Player)]
pieces = zip (range ((3, 3), (4, 4))) [1, -1, -1, 1]
-- Return a textual representation of the given board
board2Str :: Board -> String
board2Str b = ' ' : ['a'..'h'] ++ -- column names
concatMap (\i -> '\n' : show (i + 1) ++ -- row names
map player2Str (take 8 $ drop (i * 8) $ elems b)) [0..7] ++ "\n" -- rows
-- The initial board, including the initial pieces
initial :: Board
initial = array dim (zip (range dim) $ repeat 0) // pieces -- the empty board
-- The directions in which pieces can be flipped.
deltas :: [(Int, Int)]
deltas = tail [(i, j) | i <- [0,1,-1], j <- [0,1,-1]]
-- All 'lines' in any direction starting from the given index
dirs :: Index -> [[Index]]
dirs c = map (takeWhile (inRange dim) . ($ c) . iterate . (|+|)) deltas
-- Attempt to perform a move
move :: Board -> Player -> Index -> Maybe Board
move b p i | b ! i /= 0 = Nothing
| otherwise = if b == updateAll then Nothing else Just updateAll
where
-- Attempt to swap pieces in all directions
updateAll = foldr update b (dirs i)
-- Attempt to swap pieces in the given direction
update r b' = b' // case (group $ map (b' !) r) of
([_]:c@(m:_):(l:_):_) | m /= 0 && l == p -> -- all conditions are met
zip (take (1 + length c) $ r) (repeat p) -- so swap the pieces
_ -> [] -- nothing to swap
player2Str :: Player -> Char
player2Str = fromJust . (`lookup` zip [-1..1] "b w")
-- Test whether the given player can make a move
possible :: Board -> Player -> Bool
possible b p = mapMaybe (move b p) (range dim) /= []
-- Ask the players to make a move in turns, and update the board when required
mainLoop :: Board -> Player -> IO ()
mainLoop b p = do
putStr $ player2Str p : "> "
hFlush stdout
c:r <- getLine -- get user input (this is very fragile!)
-- Attempt to perform the suggested move...
case move b p (read r - 1, head $ elemIndices c ['a'..]) of
Nothing -> mainLoop b p -- ...try again if not possible
Just b' -> do -- ...accept if possible
putStr $ board2Str b' -- print the new board state
case filter (possible b') [-1 * p, p] of -- select next player to move
(p':_) -> mainLoop b' p' -- move if possible, otherwise game over
_ -> print $ if winner == ' ' then 'd' else winner
where winner = player2Str $ signum $ sum $ elems b'
-- Let the games begin!
main :: IO()
main = putStr (board2Str initial) >> mainLoop initial 1
Run Code Online (Sandbox Code Playgroud)
†:是的,我是756个字符,但注意到代码没有正确应用Reversi的规则.游民.
这是 Perl,现在减少到 408 个字符。可以用更简单的方法砍掉另外 25 个字符来宣布获胜者(比如用 代替"B")"Winner: Black\n"。前两个换行符很重要;包括其他内容是为了便于阅读。
sub O{2&$B[$q+=$_]*$%}sub A{grep{$q=$=;$"=''while&O;$B[$q]*O$q=$=}$B[$=]?():@d}
sub F{$B[$q]=$%;O&&&F}sub D{print'
',a..h,$/,(map{($e="@B[$_*9+1..$_*9+8]
")=~y/012/ bw/;$_,$e}1..8),@_}
@d=map{$_,-$_}1,8..10;@B=(@z=(0)x40,$%=2,1,(0)x7,1,2,@z);
for$!(%!){$%^=3;for$=(9..80){$=%9*A&&do{{D$%-2?b:w,"> ";
$_=<>;$==(/./g)[1]*9-96+ord;A||redo}F$q=$=for A;last}}}
$X+=/1/-/2/for@B;D"Winner: ",$X<0?White:$X?Black:None,$/
Run Code Online (Sandbox Code Playgroud)
@B持有游戏板。$B[$i*9+$j]指行 $i (1..8) 和列 $j (1..8)
@d是 8 个有效方向的列表
O 是一种方便的方法。如果 at 的棋子属于当前玩家的对手,则它会增加$q($_当前方向)并返回非零$B[$q]
F 处理当前方向的翻转棋子$_
A 检查当前玩家是否可以进行合法的移动$B[$=]并返回棋子可以翻转的方向集
D(@_)画板并打印@_
主循环切换$%(当前玩家)并迭代棋盘上的位置,以找到该玩家的合法动作。如果发现任何合法的移动,则从标准输入读取移动(重复直到输入有效的移动)并更新棋盘。