10

OK、これはかなり手の込んだコード ゴルフ チャレンジです:リバーシ(オセロ) のゲームを実装します。

  • ゲームは、ゲーム ボードの現在の状態を表示し、1 台のコンピューターでプレーヤーが交互に動きを入力できるようにする必要があります。
  • 不正な入力と許可されていない動きはキャッチする必要がありますが、黙って無視することができます。
  • ゲームは、それ以上の動きができなくなったときに終了する必要があります (ボードがいっぱいになるか、どの動きもピースを裏返さないため)。
  • その後、ゲームはどちらが勝ったか、または引き分けかを発表する必要があります。

できるだけ少ない文字でこれを行います。

セッションは次のようになります。

 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        
4

9 に答える 9

7

Haskell821文字、改行を含む。

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

上記は大まかにこのバージョンに基づいています:

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

  :はい、私は756文字でしたが、コードがReversiのルールを適切に適用していないことに気づきました。残念。

于 2009-10-17T20:14:33.087 に答える
4

C++、672 文字

これが私のバージョンです。改行を含めて 672 文字になります。

#include <iostream>
#define F for
#define G F(i p=9;p<90;++p)
#define R return
#define C std::cout
typedef int i;i b[100];i f(i p, i s, i d){i t=0;i q[]={-11,-10,-9,-1,1,9,10,11};F(i o=0;o<8;++o){i c=p+q[o];F(;b[c]==-s;c+=q[o]);if(b[c]==s)F(--t;c!=p;c-=q[o],++t)if(d)b[c]=s;}R t;}i h(i s){G if(!b[p]&&f(p,s,0))R 1;R 0;}i main(){F(i p=0;p<100;++p)b[p]=p<10||p>89||!(p%10%9)?2:0;b[44]=b[55]=-1;b[45]=b[54]=1;i s=1;F(;;){C<<" abcdefgh";G C<<(char)(p%10?"w b\n"[b[p]+1]:'0'+p/10);s=h(s)?s:-s;if(!h(s)){s=-34;G s+=b[p];C<<(s<0?'s':s?'b':'d')<<'\n';R 0;}i p=0;F(;p<9||p>90||b[p]||!f(p,s,1);){C<<"w b"[s+1]<<">";std::string m;std::cin>>m;p=m[0]-'`'+(m[1]-'0')*10;}b[p]=s;s=-s;}}
于 2009-10-20T08:06:07.730 に答える
3

パール、408文字

これは Perl で、現在は 408 文字まで縮小されています。勝者を宣言するためのより最小限のアプローチで、さらに 25 文字を切り刻むことができます ("B"代わりに を言うなど"Winner: Black\n")。最初の 2 つの改行が重要です。他のものは読みやすくするために含まれています。

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,$/

@Bゲームボードを保持します。$B[$i*9+$j]行 $i (1..8) と列 $j (1..8) を参照

@d8つの有効な方向のリストです

O 便利な方法です。(現在の方向)だけインクリメント$qし、現在のプレーヤーの対戦相手に属している$_場合はゼロ以外を返します$B[$q]

F 現在の方向でのピースの反転を処理します$_

A 現在のプレイヤーが正当な動きをすることができるかどうかを確認し$B[$=]、ピースを裏返すことができる一連の方向を返します

D(@_)ボードを描画して印刷します@_

メイン ループ$%は (現在のプレーヤー) を切り替え、ボード上の位置を反復処理して、そのプレーヤーの正当な動きを見つけます。正当な移動が見つかった場合は、標準入力から移動を読み取り (有効な移動が入力されるまで繰り返します)、ボードを更新します。

于 2009-10-19T06:54:25.570 に答える
2

述べたように、これは問題を完全には解決しませんが、この実装は実際にはかなり強力なレベルでOthello(Reversi)を再生します。私の意見では、これはこれまでで最高のIOCCCエントリの1つです。詳細については、前のIOCCC受賞者ページの「lievaart」をご覧ください。

(私は公開されたとおりに実装をコピーしましたが、GCCはのアイデア全体を受け入れませんでした#define D define。を使用s/D/define/gすると、プログラムはコンパイルされ、正常に実行されます。)

#define D define
#D Y return
#D R for
#D e while
#D I printf
#D l int
#D W if
#D C y=v+111;H(x,v)*y++= *x
#D H(a,b)R(a=b+11;a<b+89;a++)
#D s(a)t=scanf("%d",&a)
#D U Z I
#D Z I("123\
45678\n");H(x,V){putchar(".XO"[*x]);W((x-V)%10==8){x+=2;I("%d\n",(x-V)/10-1);}}
l V[1600],u,r[]={-1,-11,-10,-9,1,11,10,9},h[]={11,18,81,88},ih[]={22,27,72,77},
bz,lv=60,*x,*y,m,t;S(d,v,f,_,a,b)l*v;{l c=0,*n=v+100,j=d<u-1?a:-9000,w,z,i,g,q=
3-f;W(d>u){R(w=i=0;i<4;i++)w+=(m=v[h[i]])==f?300:m==q?-300:(t=v[ih[i]])==f?-50:
t==q?50:0;Y w;}H(z,0){W(E(v,z,f,100)){c++;w= -S(d+1,n,q,0,-b,-j);W(w>j){g=bz=z;
j=w;W(w>=b||w>=8003)Y w;}}}W(!c){g=0;W(_){H(x,v)c+= *x==f?1:*x==3-f?-1:0;Y c>0?
8000+c:c-8000;}C;j= -S(d+1,n,q,1,-b,-j);}bz=g;Y d>=u-1?j+(c<<3):j;}main(){R(;t<
1600;t+=100)R(m=0;m<100;m++)V[t+m]=m<11||m>88||(m+1)%10<2?3:0;I("Level:");V[44]
=V[55]=1;V[45]=V[54]=2;s(u);e(lv>0){Z do{I("You:");s(m);}e(!E(V,m,2,0)&&m!=99);
W(m!=99)lv--;W(lv<15&&u<10)u+=2;U("Wait\n");I("Value:%d\n",S(0,V,1,0,-9000,9000
));I("move: %d\n",(lv-=E(V,bz,1,0),bz));}}E(v,z,f,o)l*v;{l*j,q=3-f,g=0,i,w,*k=v
+z;W(*k==0)R(i=7;i>=0;i--){j=k+(w=r[i]);e(*j==q)j+=w;W(*j==f&&j-w!=k){W(!g){g=1
;C;}e(j!=k)*((j-=w)+o)=f;}}Y g;}

このバージョンの最新の再実装は、私のOthelloページにあります。

于 2009-10-18T21:58:59.593 に答える
2

私はJavaの1143文字でそれを行うことができます:

import java.io.*;public class R{public static void main(String[]args)throws Exception{char[][]b=new char[10][10];for(inty=0;y<10;y++)for(int x=0;x<10;x++)b[y][x]=' ';b[4][4]='w';b[4][5]='b';b[5][4]='b';b[5][5]='w';char c='b';BufferedReader r=new BufferedReader(new InputStreamReader(System.in));while(true){System.out.println(" abcdefgh");boolean m=false;for(int y=1;y<9;y++){System.out.print(y);for(int x=1;x<9;x++){System.out.print(b[y][x]);m=m||(b[y][x]==' '&&f(x,y,b,c,false));}System.out.println();}if(!m)break;System.out.print(c+">");String l = r.readLine();if(l.length()<2)continue;int x=l.charAt(0)-'a'+1;int y=l.charAt(1)-'0';if(x<1||x>8||y<1||y>8||b[y][x]!=' '||!f(x, y, b, c, true))continue;b[y][x]=c;c=c=='b'?'w':'b';}int s=0;for(int y=1;y<9;y++)for(int x=1;x<9;x++)s+=b[y][x]=='b'?1:b[y][x]=='w'?-1:0;System.out.println(s==0?"d":s<0?"w":"b");}static boolean f(int x,int y,char[][]b,char c,boolean o){boolean p=false;for(int u=-1;u<2;u++)for(int v=-1;v<2;v++){if(u==0&&v==0)continue;int d=0;do d++;while(b[y+d*u][x+d*v]==(c=='b'?'w':'b'));if(b[y+d*u][x+d*v]==c&&d>1){p=true;if(o)for(int e=1;e<d;e++)b[y+e*u][x+e*v]=c;}}return p;}}

これは(ほぼ)同じJavaのロングハンドバージョンです:

import java.io.*;

public class Reversi {
    public static void main(String[] args) throws Exception {
        // Initialise game board, made of chars - ' ' is empty, 'b' is a black piece, 'w' a white.
        // Using a 10x10 board, with the outer ring of empties acting as sentinels.
        char[][] board = new char[10][10];
        for (int y = 0; y < 10; y++) { for (int x = 0; x < 10; x++) { board[y][x] = ' '; } }
        // Set up the four pieces in the middle.
        board[4][4] = 'w'; board[4][5] = 'b'; board[5][4] = 'b'; board[5][5] = 'w';
        // Color of the current player.
        char currentColor = 'b';
        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            // Print game board.
            System.out.println(" abcdefgh");
            for (int y = 1; y < 9; y++) {
                System.out.print(y);
                for (int x = 1; x < 9; x++) { System.out.print(board[y][x]); }
                System.out.println();
            }
            // See if there are any legal moves by considering all possible ones.
            boolean legalMovesAvailable = false;
            for (int y = 1; y < 9; y++) { for (int x = 1; x < 9; x++) {
                legalMovesAvailable = legalMovesAvailable ||
                        (board[y][x] == ' ' && flip(x, y, board, currentColor, false));
            }}
            if (!legalMovesAvailable) { break; }
            // Print input, indicating which color's turn it is.
            System.out.print(currentColor + ">");
            // Parse input.
            String l = r.readLine();
            if (l.length() < 2) { continue; }
            int x = l.charAt(0) - 'a' + 1;
            int y = l.charAt(1) - '0';
            // Discard malformed input.
            if (x < 1 || x > 8 || y < 1 || y > 8 || board[y][x] != ' ') { continue; }
            // Check if valid move & flip if it is - if not, continue.
            if (!flip(x, y, board, currentColor, true)) { continue; }
            // Put down the piece itself.
            board[y][x] = currentColor;
            // Switch players.
            currentColor = currentColor == 'b' ? 'w' : 'b';
        }
        // Calculate final score: negative is a win for white, positive one for black.
        int score = 0;
        for (int y = 1; y < 9; y++) { for (int x = 1; x < 9; x++) {
            score += board[y][x] == 'b' ? 1 : board[y][x] == 'w' ? -1 : 0;
        }}
        System.out.println(score == 0 ? "d" : score < 0 ? "w" : "b");
    }

    /** Flip pieces, or explore whether putting down a piece would cause any flips. */
    static boolean flip(int pieceX, int pieceY, char[][] board, char playerColor, boolean commitPutDown) {
        boolean causesFlips = false;
        // Explore all straight and diagonal directions from the piece put down.
        for (int dY = -1; dY < 2; dY++) { for (int dX = -1; dX < 2; dX++) {
            if (dY == 0 && dX == 0) { continue; }
            // Move along that direction - if there is at least one piece of the opposite color next
            // in line, and the pieces of the opposite color are followed by a piece of the same
            // color, do a flip.
            int distance = 0;
            do {
                distance++;
            } while (board[pieceY + distance * dY][pieceX + distance * dX] == (playerColor == 'b' ? 'w' : 'b'));
            if (board[pieceY + distance * dY][pieceX + distance * dX] == playerColor && distance > 1) {
                causesFlips = true;
                if (commitPutDown) {
                    for (int distance2 = 1; distance2 < distance; distance2++) {
                        board[pieceY + distance2 * dY][pieceX + distance2 * dX] = playerColor;
                    }
                }
            }
        }}
        return causesFlips;
    }
}
于 2009-10-17T15:35:58.843 に答える
1

ここでコードが最適化されたバージョンで機能すると仮定します。

1081文字

import java.util.*;import java.io.*;class R{public static void main(String[]a)throws Exception{PrintStream h=System.out;char[][]b=new char[10][10];for(int y=0;y<10;y++)for(int x=0;x<10;x++)b[y][x]=' ';b[4][4]='w';b[4][5]='b';b[5][4]='b';b[5][5]='w';char c='b';Scanner r=new Scanner(System.in);while(true){h.println(" abcdefgh");boolean m=false;for(int y=1;y<9;y++){h.print(y);for(int x=1;x<9;x++){h.print(b[y][x]);m=m||(b[y][x]==' '&&f(x,y,b,c,false));}h.println();}if(!m)break;h.print(c+">");String l=r.nextLine();if(l.length()<2)continue;int x=l.charAt(0)-'a'+1;int y=l.charAt(1)-'0';if(x<1||x>8||y<1||y>8||b[y][x]!=' '||!f(x,y,b,c,true))continue;b[y][x]=c;c=c=='b'?'w':'b';}int s=0;for(int y=1;y<9;y++)for(int x=1;x<9;x++)s+=b[y][x]=='b'?1:b[y][x]=='w'?-1:0;h.println(s==0?"d":s<0?"w":"b");}static boolean f(int x,int y,char[][]b,char c,boolean o){boolean p=false;for(int u=-1;u<2;u++)for(int v=-1;v<2;v++){if(u==0&&v==0)continue;int d=0;do d++;while(b[y+d*u][x+d*v]==(c=='b'?'w':'b'));if(b[y+d*u][x+d*v]==c&&d>1){p=true;if(o)for(int e=1;e<d;e++)b[y+e*u][x+e*v]=c;}}return p;}}
于 2009-10-17T15:38:53.450 に答える
1

JavaScript/HTML 1419文字(入力不備、放置)

キノピコはこのエントリーを放棄しています。エントリを提出した後、これの非ゴルフ版にもう少し取り組んだ後、私は問題が見た目よりもはるかに複雑であることに気付きました. たとえば、プレイできないポジションを確認し、両方のプレーヤーがプレイできないポジションにいる場合は勝者を宣言する必要があります。他の回答が実際にそれを行うかどうかはわかりませんが、ロジックが非常に複雑であるため、これはもはや楽しい問題ではありません。他の誰かがこれを引き継いで終了したい場合は、遠慮なくそうしてください。

これはまだ完了していません (スコアは保持されません)。入力を読み取るのではなく、ポイントしてクリックするようにしました。

<html>
<head>
<style>
.s{background-color:green;width:50;height:50;font-size:40}
.w{color:white;font-size:40}
.b{color:black;font-size:40}
.h{width:50;height:50;font-size:30}
</style>
<script>
b=new Array()
for(i=0;i<10;i++)b[i]=new Array(0,0,0,0,0,0,0,0,0);
function j(x,y,c){a=k("s"+x+y)
a.innerHTML=String.fromCharCode(parseInt("25CF",16))
a.className="s "+c}
z="b"
function v(x,y,c){
d=0
for(g=(x>1?x-1:1);g<=(x<8?x+1:8);g++){
for(h=(y>1?y-1:1);h<=(y<8?y+1:8);h++){
if(g==x&&h==y)continue
n=b[g][h]
if(n!=0&&n!=c){e=g-x
f=h-y
for(t=1;;t++){p=x+t*e
q=y+t*f
if(p<1||q<1||p>8||q>8)break
if(!b[p][q])break
if(b[p][q]==c){d=1
for(s=1;s<t;s++){r=x+s*e
u=y+s*f
b[r][u]=c
a=k("s"+r+u)
a.className="s "+c}break}}}}}return d}
function w(x,y){if(b[x][y])return
if(!v(x,y,z))return
b[x][y]=z
j(x,y,z)
z=(z=="b"?"w":"b")}

function create_b(){
b[4][4]=b[5][5]="w";b[4][5]=b[5][4]="b"
t=k("b");
r=o("tr",t)
for(x=0;x<9;x++){
if(x){
h=o("th",r)
h.innerHTML=x}
else 
h=o("th",r)
h.className="h"}
for(y=1;y<9;y++){
r=o("tr",t)
for(x=0;x<9;x++){
if(x){td=o("td",r)
td.className="s a"
td.id="s"+x+y;(function(x,y){td.onclick=function(){w(x,y)}}(x,y))
if(b[x][y])j(x,y,b[x][y])
}else{
h=o("th",r)
h.innerHTML=y
h.className="h"}}}}
function o(p,q){n=document.createElement(p);q.appendChild(n);return n}
function k(i){return document.getElementById(i)}
</script>
</head>
<body onload="create_b()">
<table id="b"></table>
</body>
</html>
于 2009-10-17T19:53:36.983 に答える
0

これは 1266 バイトの WinXP .COM ファイルです。これは少し大きいように見えるかもしれませんが、要件をいくらか超えています。わかりました、私は少し夢中になりました。

コントロール:

w,s,a,d = カーソルを移動
スペース = プレースピース
入る = プログラムを出る

かなり直感的にプレイできるはずです。

PSソースコードはこちら!

于 2009-10-24T23:07:25.470 に答える