Kingdom Builder oyununa puan verin


16

Burada yeni bir kod golf denemek istiyorum. Bonuslara benzer şekilde, mücadelenin tüm bölümlerinin tamamlanması gerekmez, ancak her cevap belirli bir boyutta bir alt küme uygulamak zorundadır (ve her cevabın uygulamak zorunda olduğu bir çekirdek vardır). Bu yüzden golfün yanı sıra, bu zorluk birlikte iyi giden bir dizi özellik seçmeyi de içerir.

Kurallar

Kingdom Builder (sivri uçlu) altıgen ızgarada oynanan bir masa oyunudur. Tahta, her biri 10x10 heks hücre içeren dört (rastgele) kadrandan oluşur (böylece tam bir tahta 20x20 olacaktır). Bu meydan okuma amacıyla, her altıgen hücre su ( W), dağ ( M) bir kasaba ( T), bir kale ( C) veya boş ( .) içerir. Yani bir çeyrek daire şöyle görünebilir

. . 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 .

İkinci satır her zaman ilk satırdan sağa kaydırılır. Oyuncular 1, 4her biri boş hücrelere en fazla 40 yerleşim yerleştirebilir (bu meydan okuma için göz ardı edeceğimiz bazı kurallara uyarak). Oyunun sonunda olası bir tahta şudur:

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 . .

Kadranları şöyle etiketleyeceğiz

1 2
3 4

Senin görevin böyle bir tahta puan olacaktır. Her zaman kullanılan bir temel puan ve her oyun için 3'ü seçilmiş 8 isteğe bağlı puan vardır. Aşağıda, 9 skorun hepsini açıklayacağım ve yukarıdaki kurulumu her oyuncunun kaç puan alacağına örnek olarak kullanacağım.

† Gerçek oyunda 10 puan var, ancak iki tanesini bırakacağım çünkü kimse onları golf oynamak istemiyor.

Çekirdek puan. Bir oyuncu, yanında bir yerleşim yeri bulunan her astle için 3 puan alır C. Örnek puanlar: 18, 0, 15, 12.

İsteğe bağlı puanlar.

  1. Bir oyuncu en az bir yerleşime sahip olduğu her yatay sıra için 1 puan alır .

    Örnek puanlar: 14, 20, 12, 16.

  2. Her oyuncu için, yerleşim yerlerinin çoğunda yatay sırayı bulun (bir kravat durumunda herhangi birini seçin). Bir oyuncu o sıradaki her bir yerleşim için 2 puan alır .

    Örnek puanlar: 14 (sıra 16), 8 (sıra 4, 5 veya 6), 28 (sıra 11), 10 (sıra 1).

  3. Oyuncu, ater'in yanında inşa edilen her yerleşim için 1 puan alır W.

    Örnek puanlar: 13, 21, 10, 5.

  4. Bir oyuncu bir dağın yanındaki her yerleşim için 1 puan alır M.

    Örnek puanlar: 4, 12, 8, 4.

  5. Her bir çeyrekte her oyuncunun yerleşimlerini sayın. Çeyrek başına, en fazla sayıda yerleşime sahip oyuncuların her biri 12 puan , ikinci en fazla yerleşime sahip oyuncuların her biri 6 puan alır .

    Örnek puanlar: 18 (6 + 0 + 6 + 6), 36 (12 + 12 + 0 + 12), 12 (0 + 0 + 12 + 0), 18 (12 + 6 + 0 + 0).

  6. Her oyuncu için en az yerleşim sayısına sahip oldukları çeyreği belirleyin. Bir oyuncu bu çeyrekte her yerleşim için 3 puan alır .

    Örnek puanlar: 18 (Çeyrek 2), 0 (Çeyrek 3), 15 (Çeyrek 1 veya 2), 27 (Çeyrek 3).

  7. Bir oyuncu bağlantılı her yerleşim grubu için 1 puan alır .

    Örnek puanlar: 7, 5, 6, 29.

  8. Bir oyuncu , oyuncunun en büyük bağlantılı yerleşim grubundaki her 2 yerleşim için 1 puan alır .

    Örnek puanlar: 4, 10, 8, 2.

Meydan okuma

Oyunda olduğu gibi size seçecek 3 opsiyonel puanlarının ve çekirdek puanı ve bu üç puanlarına göre verilen bir tahta skor. Kodunuz 4 puanlık bir liste oluşturmalıdır. Seçim konusunda bir kısıtlama var: Puanları 3 gruba ayırdım ve her gruptan birini uygulayacaksınız:

  • 1 ve 2'den birini uygulayın .
  • Birini uygulamak 3, 4, 5 ve 6 .
  • 7 ve 8'den birini uygulayın .

STDIN, komut satırı bağımsız değişkeni, bilgi istemi veya işlev parametresi aracılığıyla girdi alarak bir program veya işlev yazabilirsiniz. Sonucu iade edebilir veya STDOUT'a yazdırabilirsiniz.

Giriş için herhangi bir uygun 1D veya 2D liste / dize biçimini seçebilirsiniz. Sen olabilir değil tam bitişiklik bilgi içeren bir grafiği kullanın. İşte altıgen ızgaralarda bazı iyi okumalarİlham almanız gerekiyorsa .

Çıktınız ayrıca herhangi bir uygun, anlaşılır liste veya dize biçiminde olabilir.

Bu kod golf, yani en kısa cevap (bayt cinsinden) kazanır.

Diğer Varsayımlar

Bunu varsayabilirsin ...

  • ... her oyuncunun en az 1 yerleşimi vardır ve her oyuncunun 40'tan fazla yerleşimi yoktur.
  • ... her çeyrekte bir kasaba ve iki kale ya da iki kasaba ve bir kale bulunur.
  • ... kasabalar ve kaleler birbirinden yeterince uzaktır, öyle ki ikisine bitişik hiçbir yerleşim yeri olamaz.

Test Durumları

Yine de yukarıdaki tahtayı kullanarak, puanlama mekanizmalarının tüm olası seçenekleri için bireysel puanlar:

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

Kombinasyon ne olursa olsun, bir oyuncunun her zaman kazandığı bir masa var mı?
ThreeFx

@ThreeFx Oyuncu başına yerleşim sayısının alt sınırı 1 olduğundan, kurulumu oldukça kolaydır. ;) Ama her oyuncu için aynı sayıda yerleşimde, aslında bilmiyorum.
Martin Ender

Yanıtlar:


5

Python 2, 367 bayt

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"]

Program 1, 3, 7 puanlarını kullanır. Girdi, her bir hücreyi temsil eden karakter listelerinin listesidir. Örnek kartı kolayca test etmek için şunları yapabiliriz:

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]

Altıgen ızgarayı kullanma

Onaltılık bir ızgarada olduğumuz için, komşularla biraz farklı başa çıkmak zorundayız. Temsilimiz olarak geleneksel bir 2D ızgara kullanırsak, o (1, 1)zaman:

. 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)

Daha yakından incelendiğinde, ofsetlerin bulunduğunuz sıranın paritesine bağlı olduğunu fark ederiz. Yukarıdaki örnek tek satırlar içindir, ancak satırlarda bile ofsetler

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

Değişen tek şey, 1., 2., 5. ve 6. çiftlerin ikinci koordinatlarını 1 azaltmasıdır.

Lambda işlevi Nbir koordinat çifti alır(row, col) ve hücrenin tüm komşularını ızgara içinde döndürür. İç kavrama, yukarıdaki ofsetleri basit bir baz 3 kodlamasından çıkararak, sıra garip ise ikinci koordinatı artırarak üretir ve komşuları vermek için ilgili hücrelere ofsetleri ekler. Dış anlayış daha sonra süzülür ve sadece şebekenin sınırları dahilindeki komşuları bırakır.

Ungolfed

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

Can not def Fayrı bir fonksiyon yerine bir iç işlevi olabilir mi? 'Den kkaldırılamıyor def F:mu?
Justin

@Quincunx Ftaşkın doldurma işlevidir ve erişime ihtiyacı vardır J, bu yüzden Jbir parametre olarak geçişte kaydetmek için içeride (derin kopyalamanın etrafında gidip edemeyeceğimi görmek için biraz deneyeceğim). kYine de haklısın , teşekkürler :) (yeni kod kısa devreye bağlı olduğu için biraz korkak görünüyor)
Sp3000

2

Yanıt Seti Programlama, 629 bayt

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, burada Potassco çerçevesi , özellikle Clingo (topraklayıcı Gringo + çözücü Tokası) tarafından enkarne edilen mantık programlama dili ailesine aittir . Paradigma sınırlaması nedeniyle, verilen kartı doğrudan bir çıktı olarak alamaz, bu nedenle verilerin önişlenmesi gereklidir (burada python'da gerçekleştirilir). Bu ön işleme toplam bayt skorunda sayılmaz.

Onun benim ilk kod golf ve amaç gerçekten oyunu kazanmak daha önce golf daha önce hiç görmediğim bir dili göstermek için daha fazla. Ayrıca, ASP bir uzman olmaktan uzak, kodun birçok optimizasyon kesinlikle daha az bayt içinde sonuçlar için gerçekleştirilebilir.

Bilgi temsili

Atomları kurulu dönüştüren python kodu vardır:

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'
        ]

Örneğin, örnek tahtanın ilk satırı için verilen b atomları (__b__oard için) aşağıdaki gibidir:

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).

Burada b (0,0,3), oyuncu 3'ün koordinatlarda (0; 0) bir yerleşime sahip olduğunu açıklayan bir atomdur.

ASP çözümü

ASP kodu vardır, birçok isteğe bağlı puan uygulanmıştır:

% 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

Bu program şu komutla başlatılabilir:

clingo board.lp golf.lp 

Ve sadece bir çözüm bulacaktır (noktaları dağıtmanın tek bir yolu olduğuna dair bir kanıt):

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)

Burada s (7,3,6) oyuncu 3'ün isteğe bağlı skor 7 ile 6 puan kazandığını ve s (t, 4,62) oyuncu 4'ün toplamda 62 puan kazandığını söylüyor (çekirdek + 1 + 3 + 7).

Süslü bir tablo var ayrıştırmak kolay!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.