킹덤 빌더의 게임 득점


16

여기에서 새로운 형태의 코드 골프를 시도하고 싶습니다. 보너스와 마찬가지로 도전 과제의 모든 부분을 완료해야하는 것은 아니지만 각 답변은 특정 크기의 하위 집합을 구현해야합니다 (모든 답변을 구현해야하는 핵심 사항이 있음). 따라서 골프 외에도이 과제는 잘 어울리는 기능을 선택하는 것과 관련이 있습니다.

규칙

Kingdom Builder 는 보드 게임으로 (뾰족한) 육각 격자에서 재생됩니다. 보드는 4 개의 (무작위 화) 사분면으로 구성되며 각 사분면에는 10x10 개의 육각 셀이 있습니다 (따라서 전체 보드는 20x20입니다). 이 도전의 목적으로, 각 육각 셀에는 물 ( W), 산 ( M), 마을 ( T), 성 ( C) 또는 비어 있음 ( .)이 있습니다. 사분면은

. . W . . . . . . .
 . M W W . . . . . .
. M . . W . . . T .
 M M . W . . . . . .
. . M . W W . . . .
 . . . . . W W W W W
. T . . . . . . . .
 . . W . . C . . . .
. . W W . . . . M . 
 . . . . . . . M M .

두 번째 행은 항상 첫 번째 행에서 오른쪽으로 오프셋됩니다. 선수 1로는 4(우리는이 도전을 무시합니다 몇 가지 규칙에 따라) 빈 셀에 40 개 정착촌 각까지 배치 할 수 있습니다. 게임이 끝날 때 가능한 보드는 다음과 같습니다.

3 3 W . . . 4 . 4 . . 2 W . 4 . . 4 . 4
 3 M W W . 1 1 . . 4 2 W . 3 C 4 4 . . 4
3 M 2 2 W 1 1 1 T 3 2 W 4 3 . 1 4 . 4 .
 M M . W 2 2 . . . 2 2 W 3 . 1 1 1 . . .
. 4 M . W W 2 2 2 2 W W 3 . 1 4 . T . .
 . . . . . W W W W W . 3 C 1 . . 2 2 2 2
. T 1 1 1 1 . . 2 . . 4 . . . 2 2 M M M
 4 . W 4 . C 4 4 . . . . . . 2 M M M M M
. 4 W W . . . 4 M . . W . W . 2 2 2 M M
 . . . . . . . M M . . W W . . . . 2 M .
. . . 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 . 1
 M 3 3 . . . . . . . . 4 . T 2 . 2 4 1 .
M M . C . 4 . 4 . . . . . 1 2 4 2 1 1 .
 M . . 1 . 4 . . . . M M 1 2 . . 2 1 . .
. . . W 1 1 4 1 1 . . . 1 2 . . 2 W W W
 . . 1 1 W 1 T . 1 1 1 1 T . . 2 W . 4 .
. 1 1 W . 3 3 . . . . . . . . 2 W 4 C 3
 C 1 3 3 3 . 3 . 4 . 4 . 4 . . 2 W 1 1 M
4 3 3 4 . M 4 3 . . . . . . . 2 W . . .
 . . . 4 . M M 3 . . 4 4 . 4 . 2 W W . .

사분면에 다음과 같이 레이블을 지정합니다.

1 2
3 4

당신의 임무는 그런 보드를 득점하는 것입니다. 항상 사용되는 하나의 핵심 점수와 8 개의 선택 점수 가 있으며 그 중 3 개 는 각 게임에 대해 선택됩니다. 다음에서는 9 점을 모두 설명하고 위의 설정을 각 플레이어가 얻는 포인트 수의 예로 사용합니다.

† 실제 게임에는 10 점이 있지만 골프를 원하지 않는 사람은 2 명입니다.

핵심 점수. 플레이어는 옆에 정착지가있을 때 마다 3 점 을 얻 C습니다. 점수 예 : 18, 0, 15, 12.

선택적 점수.

  1. 플레이어는 적어도 하나의 정착지가있는 각 수평 행에 대해 1 점 을 얻습니다 .

    점수 예 : 14, 20, 12, 16.

  2. 각 플레이어마다 자신의 정착지가 가장 많은 가로줄을 찾으십시오 (동점 인 경우 선택). 플레이어는 해당 행의 각 정착지에 대해 2 점 을 얻습니다 .

    점수 예 : 14 (행 16), 8 (행 4, 5 또는 6), 28 (행 11), 10 (행 1).

  3. 플레이어는 아터 옆에있는 각 정착지마다 1 점 을 얻습니다 W.

    점수 예 : 13, 21, 10, 5.

  4. 선수는 ountain 옆에있는 각 정착지마다 1 점 을 얻습니다 M.

    점수 예 : 4, 12, 8, 4.

  5. 각 사분면에서 각 플레이어의 합의를 세십시오. 사분면 당 가장 많은 합의를 가진 플레이어는 각각 12 점을 얻 습니다. 두 번째로 큰 합의를 가진 플레이어는 각각 6 점을 얻습니다 .

    점수 예 : 18 (6 + 0 + 6 + 6), 36 (12 + 12 + 0 + 12), 12 (0 + 0 + 12 + 0), 18 (12 + 6 + 0 + 0).

  6. 각 플레이어마다 합의 수가 가장 적은 사분면을 결정하십시오. 플레이어는 해당 사분면에서 각 합의마다 3 점 을 얻습니다 .

    점수 예 : 18 (사분면 2), 0 (사분면 3), 15 (사분면 1 또는 2), 27 (사분면 3).

  7. 플레이어는 연결된 각 정착 그룹에 대해 1 점 을 얻습니다 .

    예시 점수 : 7, 5, 6, 29.

  8. 플레이어는 플레이어의 가장 큰 연결된 합의 그룹에서 2 개의 합의 마다 1 점 을 얻습니다 .

    점수 예 : 4, 10, 8, 2.

도전

게임에서와 마찬가지로 당신이 선택합니다 3 (선택 사양) 점수, 그리고 핵심 점수와이 세 가지 점수에 따라 주어진 보드를 점수. 코드는 4 개의 점수 목록을 생성해야합니다. 선택에는 한 가지 제한이 있습니다. 점수를 3 개 그룹으로 그룹화했으며 각 그룹 중 하나를 구현해야합니다.

  • 1과 2 중 하나를 구현하십시오 .
  • 3, 4, 5 및 6 중 하나를 구현하십시오 .
  • 7과 8 중 하나를 구현하십시오 .

STDIN, 명령 줄 인수, 프롬프트 또는 함수 매개 변수를 통해 입력을 받아 프로그램이나 함수를 작성할 수 있습니다. 결과를 반환하거나 STDOUT에 인쇄 할 수 있습니다.

입력에 편리한 1D 또는 2D 목록 / 문자열 형식을 선택할 수 있습니다. 전체 인접 정보가있는 그래프를 사용할 수 없습니다 . 영감이 필요한 경우 16 진 격자에 대한 유용한 정보가 있습니다.

출력은 또한 편리하고 명확한 목록 또는 문자열 형식 일 수 있습니다.

이것은 코드 골프이므로 가장 짧은 대답 (바이트)이 이깁니다.

추가 가정

당신은 가정 할 수 있습니다 ...

  • ... 각 플레이어는 하나 이상의 합의를 가지며 각 플레이어의 합은 40 개를 넘지 않습니다.
  • ... 각 사분면에는 하나의 도시와 두 개의 성 또는 두 개의 도시와 한 개의 성이 있습니다.
  • 마을과 성이 멀리 떨어져있어 두 곳과 정착 할 수 없습니다.

테스트 사례

위의 보드를 계속 사용하면서 가능한 모든 점수 매기기 메커니즘에 대한 개별 점수는 다음과 같습니다.

Chosen Scores      Total Player Scores
1 3 7              52 46 43 62
1 3 8              49 51 45 35
1 4 7              43 37 41 61
1 4 8              40 42 43 34
1 5 7              57 61 45 75
1 5 8              54 66 47 48
1 6 7              57 25 48 84
1 6 8              54 30 50 57
2 3 7              52 34 59 56
2 3 8              49 39 61 29
2 4 7              43 25 57 55
2 4 8              40 30 59 28
2 5 7              57 49 61 69
2 5 8              54 54 63 42
2 6 7              57 13 64 78
2 6 8              54 18 66 51

조합에 관계없이 한 명의 플레이어가 항상이기는 ​​보드가 있습니까?
ThreeFx

@ThreeFx 플레이어 당 합의 수의 하한이 1이므로 설정이 매우 간단합니다. ;) 그러나 각 플레이어에 대해 같은 수의 정착지로, 나는 실제로 모른다.
Martin Ender

답변:


5

파이썬 2, 367 바이트

T=range(20)
N=lambda r,c:{(a,b)for a,b in{(r+x/3-1,c+x%3-1+(x/3!=1)*r%2)for x in[0,1,3,5,6,7]}if-1<b<20>a>-1}
def S(B):
 def F(r,c):j=J[r][c]!=i;J[r][c]*=j;j or map(F,*zip(*N(r,c)));return j
 J=map(list,B);X=lambda r,c,x,y:x+y in{B[r][c]+B[a][b]for a,b in N(r,c)};return[sum((i in B[r])+20*(3*X(r,c,"C",i)-~X(r,c,i,"W")-F(r,c))for r in T for c in T)/20for i in"1234"]

프로그램은 1, 3, 7 점수를 사용합니다. 입력은 각 셀을 나타내는 문자 목록입니다. 예제 보드를 쉽게 테스트하기 위해 다음을 수행 할 수 있습니다.

board = """
3 3 W . . . 4 . 4 . . 2 W . 4 . . 4 . 4
 3 M W W . 1 1 . . 4 2 W . 3 C 4 4 . . 4
3 M 2 2 W 1 1 1 T 3 2 W 4 3 . 1 4 . 4 .
 M M . W 2 2 . . . 2 2 W 3 . 1 1 1 . . .
. 4 M . W W 2 2 2 2 W W 3 . 1 4 . T . .
 . . . . . W W W W W . 3 C 1 . . 2 2 2 2
. T 1 1 1 1 . . 2 . . 4 . . . 2 2 M M M
 4 . W 4 . C 4 4 . . . . . . 2 M M M M M
. 4 W W . . . 4 M . . W . W . 2 2 2 M M
 . . . . . . . M M . . W W . . . . 2 M .
. . . 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 . 1
 M 3 3 . . . . . . . . 4 . T 2 . 2 4 1 .
M M . C . 4 . 4 . . . . . 1 2 4 2 1 1 .
 M . . 1 . 4 . . . . M M 1 2 . . 2 1 . .
. . . W 1 1 4 1 1 . . . 1 2 . . 2 W W W
 . . 1 1 W 1 T . 1 1 1 1 T . . 2 W . 4 .
. 1 1 W . 3 3 . . . . . . . . 2 W 4 C 3
 C 1 3 3 3 . 3 . 4 . 4 . 4 . . 2 W 1 1 M
4 3 3 4 . M 4 3 . . . . . . . 2 W . . .
 . . . 4 . M M 3 . . 4 4 . 4 . 2 W W . .
"""

board = [row.split() for row in board.strip().split("\n")]
print S(board)

# [52, 46, 43, 62]

육각 격자 다루기

우리는 육각 격자에 있기 때문에 이웃을 조금 다르게 다루어야합니다. 전통적인 2D 그리드를 표현으로 사용하면 다음과 같은 (1, 1)이점이 있습니다.

. N N . .       . N N . .                (0, 1), (0, 2)            (-1, 0), (-1, 1)
 N X N . .  ->  N X N . .  -> Neighbours (1, 0), (1, 2) -> Offsets (0, -1), (0, 1)
. N N . .       . N N . .                (2, 1), (2, 2)            (1, 0), (1, 1)

자세히 살펴보면 오프셋이 현재 행의 패리티에 따라 달라집니다. 위의 예는 홀수 행에 대한 것이지만 짝수 행에 대한 오프셋은

(-1, -1), (-1, 0), (0, -1), (0, 1), (1, -1), (1, 0)

변경된 유일한 것은 첫 번째, 두 번째, 다섯 번째 및 여섯 번째 쌍의 두 번째 좌표가 1 씩 감소했다는 것입니다.

람다 함수 N는 좌표 쌍을 가져와 (row, col)그리드 내에서 셀의 모든 이웃을 반환합니다. 내부 이해는 간단한 기본 3 인코딩에서 오프셋을 추출하여 위의 오프셋을 생성하고 행이 홀수 인 경우 두 번째 좌표를 증가시키고 해당 셀에 오프셋을 추가하여 이웃을 제공합니다. 그런 다음 외부 이해는 필터링하여 그리드의 경계 내에있는 이웃 만 남겨 둡니다.

언 골프

def neighbours(row, col):
    neighbour_set = set()

    for dr, dc in {(-1,-1), (-1,0), (0,-1), (0,1), (1,-1), (1,0)}:
        neighbour_set.add((row + dr, col + dc + (1 if dr != 0 and row%2 == 1 else 0)))

    return {(r,c) for r,c in neighbour_set if 20>r>-1 and 20>c>-1}

def solve(board):
    def flood_fill(char, row, col):
        # Logic negated in golfed code to save a few bytes
        is_char = (dummy[row][col] == char)
        dummy[row][col] = "" if is_char else dummy[row][col]

        if is_char:
            for neighbour in neighbours(row, col):
                flood_fill(char, *neighbour)

        return is_char

    def neighbour_check(row, col, char1, char2):
        return board[row][col] == char1 and char2 in {board[r][c] for r,c in neighbours(row, col)}

    dummy = [row[:] for row in board] # Need to deep copy for the flood fill
    scores = [0]*4

    for i,char in enumerate("1234"):
        for row in range(20):
            for col in range(20):
                scores[i] += (char in board[row])                        # Score 1
                scores[i] += 20 * 3*neighbour_check(row, col, "C", char) # Core score
                scores[i] += 20 * neighbour_check(row, col, char, "W")   # Score 3
                scores[i] += 20 * flood_fill(char, row, col)             # Score 7

        # Overcounted everything 20 times, divide out
        scores[i] /= 20

    return scores

def F내부 함수가 아닌 별도의 함수가 될 수 없습니까 ? k에서 제거 할 수 없습니까 def F:?
Justin

@Quincunx F는 플러드 필 기능이며에 액세스해야 J하므로 J매개 변수로 전달하는 것을 절약하기 위해 내부에 있습니다 (심층 복사를 피할 수 있는지 조금 실험 해 보겠습니다). k그래도 당신은 옳습니다. :) (단, 단락에 의존하여 새로운 코드는 약간 펑키 해 보입니다)
Sp3000

2

응답 세트 프로그래밍, 629 바이트

d(X,Y):-b(X,Y,_).p(1;2;3;4).n(X,Y,(((X-2;X+2),Y);((X-1;X+1),(Y-1;Y+1)))):-d(X,Y).n(X,Y,I,J):-n(X,Y,(I,J));d(I,J).t(X,Y,P):-n(X,Y,I,J);b(I,J,P).s(c,P,S*3):-S={t(X,Y,P):b(X,Y,"C")};p(P).s(1,P,S*1):-S=#count{r(Y):b(_,Y,P)};p(P).s(3,P,S):-S={b(X,Y,P):t(X,Y,"W")};p(P).o(X,Y,Y+X*100):-d(X,Y).h(P,X,Y,I,J):-o(X,Y,O);o(I,J,Q);O<Q;n(X,Y,I,J);b(X,Y,P);b(I,J,P);p(P).h(P,X,Y,I,J):-o(X,Y,O);o(I,J,Q);O<Q;h(P,X,Y,K,L);n(K,L,I,J);b(I,J,P);p(P).c(P,X,Y):-h(P,X,Y,_,_);not h(P,_,_,X,Y).c(P,X,Y):-{h(P,X,Y,_,_);h(P,_,_,X,Y)}0;b(X,Y,P);p(P).s(7,P,S):-S=#count{c(P,X,Y):c(P,X,Y)};p(P).s(t,P,C+S+T+U):-s(c,P,C);s(1,P,S);s(3,P,T);s(7,P,U).#shows/3.

ASP는 로직 프로그래밍 언어 제품군에 속하며 Potassco 프레임 워크 , 특히 Clingo (grounder Gringo + solver Clasp)에 의해 구현됩니다. 패러다임 제한으로 인해 보드를 직접 출력으로 사용할 수 없으므로 데이터의 사전 처리가 필요합니다 (여기서는 파이썬에서 수행됨). 이 전처리 과정은 총 바이트 점수에 포함되지 않습니다.

그것의 첫 번째 코드 골프, 그리고 목표는 실제로 게임에서이기는 것보다 골프에서 결코 본 적이없는 언어를 보여주는 것입니다. 또한 ASP의 전문가와 거리가 멀기 때문에 적은 바이트로 결과를 얻기 위해 많은 코드 최적화를 수행 할 수 있습니다.

지식 표현

보드를 원자로 변환하는 파이썬 코드가 있습니다.

def asp_str(v):
    return ('"' + str(v) + '"') if v not in '1234' else str(v)

with open('board.txt') as fd, open('board.lp', 'w') as fo:
        [fo.write('b('+ str(x) +','+ str(y) +','+ asp_str(v) +').\n')
         for y, line in enumerate(fd)
         for x, v in enumerate(line) if v not in ' .\n'
        ]

예를 들어, 예제 보드의 첫 번째 줄에 제공된 원자 b (__ b__oard의 경우)는 다음과 같습니다.

b(0,0,3).
b(2,0,3).
b(4,0,"W").
b(12,0,4).
b(16,0,4).
b(22,0,2).
b(24,0,"W").
b(28,0,4).
b(34,0,4).
b(38,0,4).

여기서 b (0,0,3)은 플레이어 3이 좌표 (0; 0)에서 합의를 가지고 있음을 나타내는 원자입니다.

ASP 해결

많은 선택적 점수가 구현 된 ASP 코드가 있습니다.

% input : b(X,Y,V) with X,Y the coordinates of the V value

domain(X,Y):- b(X,Y,_).
player("1";"2";"3";"4").

% neighbors of X,Y
neighbors(X,Y,((X-2,Y);(X+2,Y);((X-1;X+1),(Y-1;Y+1)))) :- domain(X,Y).
neighbors(X,Y,I,J):- neighbors(X,Y,(I,J)) ; domain(I,J).

% Player is next to X,Y iff has a settlement next to.
next(X,Y,P):- neighbors(X,Y,I,J) ; b(I,J,P).


% SCORES

% Core score : 3 point for each Castle "C" with at least one settlement next to.
score(core,P,S*3):- S={next(X,Y,P): b(X,Y,"C")} ; player(P).

% opt1: 1 point per settled row
score(opt1,P,S*1):- S=#count{row(Y): b(_,Y,P)} ; player(P).

% opt2: 2 point per settlement on the most self-populated row
% first, defines how many settlements have a player on each row
rowcount(P,Y,H):- H=#count{col(X): b(X,Y,P)} ; domain(_,Y) ; player(P).
score(opt2,P,S*2):- S=#max{T: rowcount(P,Y,T)} ; player(P).

% opt3: 1 point for each settlements next to a Water "W".
score(opt3,P,S):- S={b(X,Y,P): next(X,Y,"W")} ; player(P).

% opt4: 1 point for each settlements next to a Mountain "M".
score(opt4,P,S):- S={b(X,Y,P): next(X,Y,"M")} ; player(P).

% opt5:
%later…

% opt6:
%later…

% opt7: 1 point for each connected component of settlement
% first we need each coord X,Y to be orderable.
% then is defined path/5, that is true iff exists a connected component of settlement of player P
%   that links X,Y to I,J
% then is defined the connected component atom that give the smaller coords in each connected component
% then computing the score.
order(X,Y,Y+X*100):- domain(X,Y).
path(P,X,Y,I,J):- order(X,Y,O1) ; order(I,J,O2) ; O1<O2 ; % order
                  neighbors(X,Y,I,J) ; b(X,Y,P) ; b(I,J,P) ; player(P). % path iff next to
path(P,X,Y,I,J):- order(X,Y,O1) ; order(I,J,O2) ; O1<O2 ; % order
                  path(P,X,Y,K,L) ; neighbors(K,L,I,J) ; % path if path to next to
                  b(I,J,P) ; player(P).
concomp(P,X,Y):- path(P,X,Y,_,_) ; not path(P,_,_,X,Y). % at least two settlements in the connected component
concomp(P,X,Y):- 0 { path(P,X,Y,_,_) ; path(P,_,_,X,Y) } 0 ; board(X,Y,P) ; player(P). % concomp of only one settlements
score(opt7,P,S):- S=#count{concomp(P,X,Y): concomp(P,X,Y)} ; player(P).

% opt8: 0.5 point for each settlement in the bigger connected component
%later…


% total score:
score(total,P,C+S1+S2+S3):- score(core,P,C) ; score(opt1,P,S1) ; score(opt3,P,S2) ; score(opt7,P,S3).

#show. # show nothing but the others show statements
#show total_score(P,S): score(total,P,S).
%#show score/3. % scores details

이 프로그램은 다음 명령으로 시작할 수 있습니다.

clingo board.lp golf.lp 

그리고 단 하나의 솔루션을 찾을 것입니다 (포인트를 배포하는 유일한 방법이 있다는 증거).

s(c,1,18) s(c,2,0) s(c,3,15) s(c,4,12) s(1,1,14) s(1,2,20) s(1,3,12) s(1,4,16) s(3,1,13) s(3,2,21) s(3,3,10) s(3,4,5) s(7,1,7) s(7,2,5) s(7,3,6) s(7,4,29) s(t,1,52) s(t,2,46) s(t,3,43) s(t,4,62)

s (7,3,6)는 플레이어 3이 선택 점수 7로 6 점을 얻는다고 말하고 s (t, 4,62)는 플레이어 4가 총 62 점을 얻습니다 (코어 + 1 + 3 + 7).

멋진 테이블을 가지고 파싱하기 쉬운!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.