Vị trí tàu chiến lười biếng


39

Hãy tưởng tượng kịch bản sau đây: bạn đang chơi tàu chiến với một người bạn nhưng quyết định gian lận. Thay vì di chuyển một con tàu sau khi anh ta bắn vào nơi con tàu của bạn từng ở, bạn quyết định không đặt bất kỳ con tàu nào cả. Bạn nói với anh ta tất cả các cú đánh của anh ta là bỏ lỡ, cho đến khi không thể đặt tàu theo cách như vậy.

Bạn phải viết một hàm hoặc một chương trình đầy đủ bằng cách nào đó có 3 đối số: kích thước trường, danh sách số lượng kích cỡ tàu và danh sách ảnh.

Chiến trường

Một trong những tham số đã cho là kích thước bảng. Chiến trường là một ô vuông và tham số đã cho chỉ đơn giản là một mặt của hình vuông.
Ví dụ, dưới đây là một bảng có kích thước 5.

Các tọa độ trên trường được chỉ định dưới dạng chuỗi 2 thành phần: một chữ cái theo sau là một số. Bạn có thể dựa vào các chữ cái trong một số trường hợp cụ thể.
Chữ cái chỉ định cột, số chỉ định hàng của ô (được lập chỉ mục 1). Ví dụ trong hình trên, ô được tô sáng được ký hiệu là "D2".
Vì chỉ có 26 chữ cái, trường không thể lớn hơn 26x26.

Tàu thuyền

Các tàu là các đường thẳng từ 1 khối trở lên. Số lượng tàu được chỉ định trong một danh sách, trong đó phần tử đầu tiên là số lượng tàu 1 ô, thứ hai - của tàu 2 ô, v.v.
Ví dụ, danh sách [4,1,2,0,1]sẽ tạo các tàu sau:

Khi được đặt trên chiến trường, tàu không thể giao nhau, hoặc thậm chí chạm vào nhau. Thậm chí không có góc. Tuy nhiên, họ có thể chạm vào các cạnh của lĩnh vực.
Dưới đây bạn có thể thấy một ví dụ về vị trí tàu hợp lệ:

Bạn có thể giả định rằng đối với một con tàu nhất định, luôn tồn tại một vị trí trên một bảng trống có kích thước nhất định.

Đầu ra

Nếu các vị trí tàu như vậy tồn tại, bạn phải xuất bất kỳ vị trí nào trong số chúng.
Chương trình phải xuất ra một ma trận phân tách dòng mới gồm các ký tự ascii thuộc một trong ba loại - một để biểu thị ô trống, một - một mảnh tàu và một - một ô được đánh dấu là "bị bỏ lỡ". Không có ký tự khác nên được xuất.
Ví dụ,

ZZ@Z
\@@Z
@\\Z
\Z\\

(Trong ví dụ này, tôi đã xác định @là ô trống, là ô \"bị bỏ lỡ" và Zlà mảnh tàu)

Nếu không có vị trí như vậy tồn tại, chương trình / chức năng sẽ trở lại mà không xuất ra bất cứ điều gì.

Đầu vào

Nếu bạn quyết định tạo một chương trình đầy đủ, bạn sẽ chỉ định cho bạn cách các danh sách được nhập, một số có thể đi qua các đối số, một số thông qua stdin.

Đây là , số lượng nhân vật chiến thắng thấp nhất.

Một ví dụ về giải pháp tối ưu hóa không chơi gôn có thể được tìm thấy ở đây
Biên dịch với -std=c99, đối số đầu tiên là kích thước của bảng, các đối số khác là kích cỡ tàu. Một danh sách các bức ảnh được phân tách bằng dòng mới được đưa ra trên stdin. Thí dụ:
./a 4 1 1 1 <<< $'A2\nA4\nB3\nC3\nC4\D4'


26x26? Tôi đã phác thảo một giải pháp dựa trên regexps và đệ quy, và nó trở nên cực kỳ chậm = không thể sử dụng cho các trường nhiều hơn 6x6. Hoặc tôi làm điều gì đó rất ngu ngốc, hoặc thiếu câu trả lời có nghĩa là những người khác cũng không có thành công.
dùng2846289

Tôi vừa viết một triển khai trong C, nó tính toán ngay lập tức ít nhất là 10x10với một con 4,3,2,1tàu
mniip

@mniip: Bạn có cách xử lý cụ thể nào đối với các trường hợp khó khăn (bảng lớn, nhiều tàu, không thành công do vị trí bắn) không? Hay chỉ là (một chút thông minh) lực lượng vũ phu?
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Nó có một vài tối ưu hóa, trước tiên cố gắng đặt các tàu nhỏ và loại trừ các tàu hoán đổi có kích thước tương đương với lực lượng vũ phu. Thật là chậm khi có rất nhiều tàu trên một bảng nhỏ và gần như trống rỗng.
mniip

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Tôi đã thêm một liên kết giải pháp ví dụ.
mniip

Câu trả lời:


2

GolfScript, 236 ký tự

n%([~](:N):M;[.,,]zip{~[)]*~}%-1%:S;{(65-\~(M*+}%:H;{{M*+}+N,/}N,%H-S[]]]{(~\.{(:L;{{M*+{+}+L,%}+N)L-,/}N,%{.{.M/\M%M*+}%}%{3$&,L=},{:K[{..M+\M-}%{..)\(}%3$\- 1$3$K+]}%\;\;\;\+.}{;:R;;;0}if}do{{{M*+.H?)'!'*\R?)'#'*'.'++1<}+N,/n}N,%}R!!*

Đầu vào được đưa ra trên STDIN. Dòng đầu tiên chứa kích thước và số lượng tàu, mỗi dòng sau tọa độ của một lần bắn.

Thí dụ:

4 1 1 1
A2
A4
B3
C3
C4
D4

##.#
!..#
#!!#
!.!!

Tôi nghĩ rằng thử thách này cũng nên có ít nhất một câu trả lời GolfScript. Cuối cùng, nó trở nên rất vô văn hóa do thuật toán được sử dụng thiên về hiệu năng trong thời gian ngắn.

Mã chú thích:

n%               # Split the input into lines
([~]             # The first line is evaluated to an array [N S1 S2 S3 ...]
(:N              # This happy smiley removes the first item and assigns it to variable N
):M;             # While this sad smiley increases N by one and assigns it to M

[.,,]zip         # For the rest of numbers in the first line create the array [[0 S1] [1 S2] [2 S3] ...]
{~[)]*~}%        # Each element [i Si] is converted into the list (i+1 i+1 ... i+1) with Si items. 
-1%:S;           # Reverse (i.e. largest ship first) and assign the list to variable S.
                 # The result is a list of ship lengths, e.g. for input 3 0 2 we have S = [3 3 1 1 1].

{                # On the stack remains a list of coordinates
  (65-           # Convert the letter from A,B,... into numeric value 0,1,...
  \~(            # The number value is decreased by one
  M*+            # Both are combined to a single index (M*row+col)
}%:H;            # The list of shots is then assigned to variable H

                 # The algorithm is recursive backtracking implemented using a stack of tuples [A S R] where
                 #   - A is the list of open squares
                 #   - S is a list of ships to be placed
                 #   - R is the list of positions where ships were placed                     

    {{           # initial A is the full space of possible coordinates
      M*+        #   combine row and column values into a single index
    }+N,/}N,%    # do the N*N loop
    H-           # minus all places where a shot was done already
    S            # initial S is the original list
    []           # initial R is the empty list (no ships placed yet)
  ]
]                # The starting point is pushed on the stack 

{                # Start of the loop running on the stack
  (~\            # Pop from the stack and extract items in order A R S

  .{             #   If S is non-empty

    (:L;         #     Take first item in S (longest ship) and asign its length to L

    {{M*+{+}+L,%}+N)L-,/}N,%{.{.M/\M%M*+}%}%
                 #     This lengthy expression just calculates all possible ship placements on a single board
                 #     (could be shortened by 3 chars if we don't respect board size but I find it clearer this way)

    {3$&,L=},    #     This step is just a filter on those placements. The overlap (&) with the list of open squares (3$) 
                 #     must be of size L, i.e. all coordinates must be free

                 #     Now we have possible placements. For each one generate the appropriate tuple (A* S* R*) for recursion
    {
      :K         #     Assign the possible new ship placement to temporary variable K
      [
        {..M+\M-}%
        {..)\(}% 
                 #       For each coordinate add the square one row above and below (first loop)
                 #       and afterwards for the resulting list also all squares left and right (second loop)
        3$\-     #       Remove all these squares from the list of available squares A in order to get the new A*
        1$       #       Reduced list of ships S* (note that the first item of S was already remove above)
        3$K+     #       Last item in tuple is R* = R + K, i.e. the ship's placements are added to the result
      ]
    }%           

    \;\;\;       #     Discard the original values A R S
    \+           #     Push the newly generated tuples on the stack
    .            #     Loop until the stack is empty

  }{             #   else

    ;:R;;;       #     Assign the solution to the variable R and remove all the rest from the stack. 
    0            #     Push a zero in order to break the loop

  }if            #   End if

}do              # End of the loop


{                # The output block starts here
  {{             
    M*+
    .H?)         #   Is the current square in the list of shots?
    '!'*         #     then take a number of '!' otherwise an empty string
    \R?)         #   Is the current square in the list of ships?
    '#'*         #     then take a number of '#' otherwise an empty string
    '.'++        #   Join both strings and append a '.'
    1<           #   Take the first item of the resulting string, i.e. altogether this is a simple if-else-structure
  }+N,/n}N,%     # Do a N*N loop
}
R!!*             # Run this block only if R was assigned something during the backtracking. 
                 # (!! is double-negation which converts any non-zero R into a one)
                 # Note: since the empty list from the algorithm is still on the stack if R wasn't assigned
                 # anything the operator !! works on the code block (which yields 1) which is then multiplied
                 # with the empty list.

6

SWI-Prolog, 536 441 1 byte

1 dòng UNIX kết thúc, dòng mới cuối cùng không được tính

Phiên bản với tất cả tối ưu hóa đã bị xóa ( 441 byte):

:-[library(clpfd)].
m(G,L):-maplist(G,L).
l(L,A):-length(A,L).
y(A,E,(X,Y)):-nth1(X,A,R),nth1(Y,R,F),var(F),F=E.
a(A,S):-l(L,A),X#>0,X#=<L,Y#>0,Y#=<L,h(S,(X,Y),A).
h(0,_,_).
h(L,(X,Y),A):-(B=A;transpose(A,T),B=T),y(B,s,(X,Y)),M#=L-1,Z#=Y+1,h(M,(X,Z),B).
e([],_,[]).
e([H|R],I,O):-J#=I+1,e(R,J,P),l(H,Q),Q ins I,append(P,Q,O).
r(R):-m(c,R),nl.
c(E):-var(E)->put(@);put(E).
g(L,H,S):-l(L,A),m(l(L),A),m(y(A,\),S),e(H,1,G),!,m(a(A),G),!,m(r,A).

Vì mã được thay đổi để giảm thiểu số lượng byte, nên nó sẽ không còn chấp nhận danh sách các ảnh có trùng lặp.


Phiên bản với tối ưu hóa cơ bản, được chơi đầy đủ ( 536 → 506 byte)

:-[library(clpfd)].
m(G,L):-maplist(G,L).
l(L,A):-length(A,L).
x(A,I,E):-X=..[a|A],arg(I,X,E).
y(A,E,(X,Y)):-x(A,X,R),x(R,Y,E).
a(A,S):-l(L,A),X#>0,X#=<L,Y#>0,Y#=<L,(B=A;transpose(A,T),B=T),h(S,(X,Y),B).
h(0,_,_).
h(L,(X,Y),A):-y(A,E,(X,Y)),var(E),E=s,M#=L-1,Z#=Y+1,h(M,(X,Z),A).
e([],_,[]).
e([H|R],I,O):-J#=I+1,e(R,J,P),l(H,Q),Q ins I,append(P,Q,O).
r(R):-m(c,R),nl.
c(E):-var(E)->put(@);put(E).
g(L,H,S):-l(L,A),m(l(L),A),sort(S,T),m(y(A,\),T),e(H,1,G),!,l(E,T),sumlist(G,D),L*L-E>=D,m(a(A),G),!,m(r,A).

Tôi thực hiện một số kiểm tra cơ bản ( đếm số khối tàu cần thiết ) để làm cho mã thoát nhanh hơn cho các trường hợp rõ ràng không thể. Mã này cũng miễn nhiễm với bản sao trong danh sách các ảnh chụp cho đến nay.


Dưới đây là phiên bản (phần nào) có thể đọc được, với các bình luận chi tiết:

:-[library(clpfd)].

% Shorthand for maplist, which works like map in high order function
m(G,L):-maplist(G,L).

% Creating a square matrix A which is L x L
board(L,A):-l(L,A),m(l(L),A).

% Shorthand for length, with order of parameters reversed
l(L,A):-length(A,L).

% Unification A[I] = E
x(A,I,E):-X=..[a|A],arg(I,X,E).

% Unification A[X][Y]=E
idx2(A,E,(X,Y)):-x(A,X,R),x(R,Y,E).

% Mark positions that have been shot
markshot(A,S):-m(idx2(A,\),S).

% Place all ships on the board
placeships(H,A):-m(placeship(A),H).

% Place a length S ship horizontal/vertical forward on the board
placeship(A,S):-
    l(L,A), % Get length
    X#>0,X#=<L,Y#>0,Y#=<L, % Constraint X and Y coordinates
    transpose(A,T), % Transpose to work on columns
    (placeship_h(S,(X,Y),A) ; placeship_h(S,(Y,X),T)).

% Place ship horizontal, forward at (X,Y)
placeship_h(0,_,_).
placeship_h(L,(X,Y),A):-
    idx2(A,E,(X,Y)),var(E),E=s, % Make sure position is unassigned, then mark
    L2#=L-1,Y2#=Y+1, % Do this for all blocks of the ship
    placeship_h(L2,(X,Y2),A).

% Expand the list of ships
% e.g. [2,3,1] --> [3,2,2,2,1,1]
shipexpand(S,O):-shipexpand(S,1,O).

shipexpand([],_,[]).
shipexpand([H|R],I,O):-
    I2#=I+1,shipexpand(R,I2,O2), % process the rest
    l(H,O1),O1 ins I, % duplicate current ship size H times
    append(O2,O1,O). % larger ship size goes in front

% Print the result
pboard(A):-m(prow,A).
prow(R):-m(pcell,R),print('\n').
pcell(E):-var(E)->print(@);print(E).

game(L,H,S):-
    board(L,A), % create board
    sort(S,SS), % remove duplicates
    markshot(A,SS), % mark positions that have been shot
    shipexpand(H,HH),!, % make a list of ships
    l(SC,SS),sumlist(HH,BC),L*L-SC>=BC, % check to speed-up, can be removed
    placeships(HH,A),!, % place ships
    pboard(A). % print result

Định dạng truy vấn:

game(Board_Size, Ships_List, Shots_List).

Truy vấn mẫu (sử dụng mẫu trong câu hỏi):

?- game(4,[1,1,1],[(2,1),(3,2),(3,3),(4,1),(4,3),(4,4)]).
ssss
\ss@
@\\@
\@\\
true.

?- game(4,[2,2,0,1],[(2,1),(3,2),(3,3),(4,1),(4,3),(4,4)]).
ssss
\sss
s\\s
\s\\
true.

Ah darn đánh tôi bởi một vài chục nhân vật! Không chắc tôi có thể nén tôi nữa hay không nhưng tôi sẽ tiếp tục ... sử dụng Prolog!
Claudiu

@Claudiu: Giải pháp của tôi vẫn có "bộ đệm" gồm 20 ký tự. Tôi đã để những mã kiểm tra trong đó vì lý do hiệu suất, nhưng chúng có thể bị xóa mà không ảnh hưởng đến tính chính xác;) Tôi không bận tâm nếu các câu trả lời khác đạt dưới 500, mặc dù.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

5

Matlab - 536 ký tự

Đã cập nhật: Định dạng đầu ra nhỏ hơn nhiều, một số khoảng trắng vòng lặp bị xóa.

Cập nhật: Đã thêm phiên bản chơi gôn

Đã cập nhật: Đã thêm phiên bản nhận xét, giảm phiên bản chơi gôn xuống ~ 100 ký tự

% Battleship puzzle solver.
%
% n: size of the map (ex. 4 -> 4x4)
% sh: list of shots (ex. ['A2';'C4'])
% sp: ships of each size (ex. [2,0,1] -> 2x1 and 1x3)
%
function bs(n,sh,sp)

  % sp holds a vector of ship counts, where the index of each element is
  % the size of the ship. s will hold a vector of ship sizes, with order
  % not mattering. This is easier to work with using recursion, because
  % we can remove elements with Matlab's array subselection syntax, rather
  % than decrement elements and check if they're zero.
  %
  % Tricks:
  %   Since sp never contains a -1, find(1+sp) is the same as 1:length(sp)
  %   but is three characters shorter.
  %
  s=[];
  for i=find(1+sp)
    s(end+1:end+sp(i))=i;
  end


  % m will hold the map. It will be +2 in each direction, so that later we
  % can find neighbors of edge-spaces without checking bounds. For now,
  % each element is either '0' or '1' for a space or missed shot,
  % respectively. We convert the shots as provided by the user (ex. 'A2')
  % to marks on the map.
  %
  % Tricks:
  %   It takes one shorter character to subtract 47 than 'A' to determine
  %   the indices into the map.
  %
  m=zeros(n+2);
  for h=sh'
    m(h(2)-47,h(1)-63)=1;
  end


  % Solve the puzzle. q will either be the empty array or a solution map.
  %
  q=pp(m,s);


  % If a solution was found, output it, showing the original shots and the
  % ship placement. If no solution was found, print a sad face.
  %
  % Tricks:
  %   q is 0 on failure, which is treated like 'false'. q is a matrix on
  %   success which is NOT treated like 'true', so we have to check for
  %   failure first, then handle success in the 'else' block.
  %
  %   q contains the "fake shots" that surround each placed ship (see the
  %   pl function). We don't want to output those, so we just copy the ship
  %   markings into the original map.
  %
  if ~q ':('
  else
  m(find(q==2))=2;
  num2str(m(2:n+1,2:n+1),'%d')
  end



% Depth-first search for a solution.
%
% m: map (see main code above)
% s: vector of ship sizes to place in the map
%
% Returns q: square matrix of integers, updated with all requested ship
% sizes, or 0 if no solution is possible.
%
function q = pp(m,s)

  % If we have no ships to process, we're all done recursing and the
  % current map is a valid solution. Rather than handle this in an 'else'
  % block, we can assume it's the case and overwrite q if not, saving 4
  % characters.
  %
  q=m;


  % If we have any ships to place...
  %
  % Tricks:
  %   Since we are only interested in positive values in s, we can use
  %   sum(s) in place of isempty(s), saving 4 characters.
  %
  if sum(s)

    % Try to place the first ship in the list into the map, both vertically
    % (first call to p) and vertically (second call to p). We can process
    % any ship in the list, but the first can be removed from the list
    % with the fewest characters. r will hold a cell-array of options for
    % this ship.
    %
    r=[p(m,s(1),0),p(m',s(1),1)];


    % Recurse for each option until we find a solution.
    %
    % Tricks:
    %   Start with q, our return variable, set to 0 (indicating no solution
    %   was found. On each loop we'll only bother to recurse if q is still
    %   0. This relieves the need for if/else to check whether to continue
    %   the loop, or any final q=0 if the loop exits without success.
    %
    %   Sadly, there's no way around the length(r) call. Matlab doesn't
    %   provide syntax for iterating over cell-arrays.
    %
    q=0;
    for i=1:length(r)
      if ~q q=pp(r{i},s(2:end));end
    end
  end



% Place a single ship into a map.
%
% m: map (see main code above)
% s: ship size to place
% t: if the map has been transposed prior to this call
%
% Returns r: cell-array of possible maps including this ship
%
function r=p(m,s,t)
  % Start with an empty cell-array and pre-compute the size of the map,
  % which we'll need to use a few times.
  %
  r={};
  z=size(m);


  % For each row (omitting the first and last 'buffer' rows)...
  %
  for i=2:z(2)-1

  % For each starting column in this row where enough consecutive 0s
  % appear to fit this ship...
  %
  for j=strfind(m(i,2:end-1),(1:s)*0)

    % Copy the map so we can modify it without overwriting the variable
    % for the next loop.
    %
    n=m;


    % For each location on the map that is part of this optional
    % placement...
    for l=0:s-1
      % Let's leave this is an exercise for the reader ;)
      %
      v=-1:1;
      n([(l+j)*z(1)+i,z(1),1]*[ones(1,9);kron(v,[1 1 1]);[v v v]])=1;
    end


    % Mark each location that is part of this optional placement with
    % a '2'.
    %
    n(i,1+j:j+s)=2;


    % Since our results are going into a cell-array it won't be
    % convenient for the caller to undo any transpositions they might
    % have done. If the t flag is set, transpose this map back before
    % adding it to the cell-array.
    %
    if t n=n';end
    r{end+1}=n;
  end
  end

Đây là phiên bản chơi gôn.

function bs(n,sh,sp)
s=[];for i=find(1+sp)
s(end+1:end+sp(i))=i;end
m=zeros(n+2);for h=sh'
m(h(2)-47,h(1)-63)=1;end
q=pp(m,s);if ~q ':('
else
m(find(q==2))=2;num2str(m(2:n+1,2:n+1),'%d')
end
function q = pp(m,s)
q=m;if sum(s)
r=[p(m,s(1),0),p(m',s(1),1)];q=0;for i=1:length(r)if ~q q=pp(r{i},s(2:end));end
end
end
function r=p(m,s,t)
r={};z=size(m);for i=2:z(2)-1
for j=strfind(m(i,2:end-1),(1:s)*0)n=m;for l=0:s-1
v=-1:1;n([(l+j)*z(1)+i,z(1),1]*[ones(1,9);kron(v,[1 1 1]);[v v v]])=1;end
n(i,1+j:j+s)=2;if t n=n';end
r{end+1}=n;end
end

Đây là một số mẫu.

>>bs(4,['A1';'B3'],[2,1])
1220
0000
2120
0000

>>bs(4,['A1';'B4'],[2,2])
1022
2000
0022
2100

>> bs(4,['A1';'B4';'C2'],[3,1])
1022
2010
0020
2100

>> bs(4,['A1';'B4';'C2'],[3,2])
:(

Dòng lớn với 'kron' (gần cuối mã không được đánh gôn) là phần yêu thích của tôi về điều này. Nó viết '1' cho tất cả các vị trí trong bản đồ lân cận một vị trí nhất định. Bạn có thể thấy nó hoạt động như thế nào? Nó sử dụng sản phẩm tenx kronecker, nhân ma trận và lập chỉ mục bản đồ dưới dạng mảng tuyến tính ...


4

Python, 464 ký tự

B,L,M=input()
R=range(B)
C=B+1
M=sum(1<<int(m[1:])*C-C+ord(m[0])-65for m in M)
def P(L,H,S):
 if len(L)==0:
  for y in R:print''.join('.#!'[(S>>y*C+x&1)+2*(M>>y*C+x&1)]for x in R)
  return 1
 for s in[2**L[0]-1,sum(1<<C*j for j in range(L[0]))]:
  for i in range(C*C):
   if H&s==s and P(L[1:],H&~(s|s<<1|s>>1|s<<B|s>>B|s<<C|s>>C|s<<C+1|s>>C+1),S|s):return 1
   s*=2
 return 0
P(sum(([l+1]*k for l,k in enumerate(L)),[])[::-1],sum((2**B-1)<<B*j+j for j in R)&~M,0)

Đầu vào (stdin):

7, [4,1,2,0,1], ['A1','B2','C3']

Đầu ra:

!#####.
.!.....
##!###.
.......
###.#.#
.......
#.#....

Hoạt động bằng cách sử dụng số nguyên giữ bitmap của các tính năng khác nhau:

M = bitmap of misses
H = bitmap of holes where ships can still go
S = bitmap of ships already placed
L = list of ship sizes not yet placed
B = dimension of board
C = bitmap row length

Nếu bạn không phiền, bạn có thực hiện bất kỳ tối ưu hóa nào không, hay đó chỉ là lực lượng vũ phu?
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Có một tối ưu hóa: cái [::-1]mà làm cho nó thử con tàu dài nhất trước tiên. Nó cũng quay lại ngay khi tìm thấy một con tàu mà nó không thể đặt.
Keith Randall

Bạn có thể sử dụng một tab duy nhất thay vì 2 hoặc 3 khoảng trắng trên các dòng 7, 8, 11 và 12, giảm số byte xuống còn 458. Xem tại đây .
mbomb007

3

Python, 562 ký tự, -8 với đầu ra xấu, +4? cho bash invocation

I=int;R=range
import sys;a=sys.argv
S=I(a[1]);f=[[0]*(S+2)for _ in R(S+2)]
C=a[2].split()
X=[]
for i,n in enumerate(C):X=[i+1]*I(n)+X
Q=a[3].split()
for q in Q:f[I(q[1:])][ord(q[0])-64]=1
D=R(-1,2)
V=lambda r,c:(all(f[r+Q][c+W]<2for Q in D for W in D),0,0)[f[r][c]]
def F(X):
 if not X:print"\n".join(" ".join(" .@"[c]for c in r[1:-1])for r in f[1:-1])
 x=X[0];A=R(1,S+1)
 for r in A:
    for c in A:
     for h in(0,1):
        def P(m):
         for i in R(x):f[(r+i,r)[h]][(c,c+i)[h]]=m
        if(r+x,c+x)[h]<S+2and all(V((r+i,r)[h],(c,c+i)[h])for i in R(x)):P(2);F(X[1:]);P(0)
F(X)

Lưu ý: các mức thụt là không gian, tab, tab + dấu cách, tab + tab và tab + tab + dấu cách. Điều này tiết kiệm một vài ký tự chỉ sử dụng khoảng trắng.

Cách sử dụng và ví dụ :

Lấy đầu vào từ các đối số dòng lệnh. Xuất ra một khoảng trống dưới dạng khoảng trắng, bắn như một phần .@là một phần của con tàu:

$ python bships_golf.py "7" "4 0 2 0 1" \
         "A1 C3 B5 E4 G6 G7 A3 A4 A5 A6 C1 C3 C5 C7 B6 B7 D1 D2 G3" 2>X
. @ . . @ @ @
  @   .
. @ . @   @ .
.     @ .
. . . @   @
. .   @     .
@ . . @   @ .

Khi không thể giải quyết, không in gì:

$ python bships_golf.py "3" "2" "A1 A3 B1 C1 C3" 2>X
. . .
@   @
.   .
$ python bships_golf.py "3" "2" "A1 A2 A3 B1 C1 C3" 2>X
$

Các 2>Xlà để ngăn chặn một thông báo lỗi kể từ khi thoát khỏi chương trình bằng cách ném một ngoại lệ. Vui lòng thêm hình phạt +4 nếu được coi là công bằng. Nếu không, tôi phải làm một try: ... except:0việc để triệt tiêu nó, dù sao cũng sẽ mất nhiều nhân vật hơn.

Tôi cũng có thể in ra như số ( 0, 12) để cạo 8 ký tự, nhưng thẩm mỹ giá trị tôi.

Giải thích :

Tôi trình bày bảng như một danh sách các danh sách các số nguyên có kích thước 2 lớn hơn đầu vào, để tránh phải kiểm tra giới hạn. 0đại diện cho một không gian trống, 1một phát bắn và 2một con tàu. Tôi chạy qua danh sách ảnh Qvà đánh dấu tất cả các bức ảnh. Tôi chuyển đổi danh sách các tàu thành một danh sách rõ ràng Xvề các tàu, ví dụ như [4, 0, 2, 0, 1]trở thành [5, 3, 3, 1, 1, 1, 1]. Sau đó, đó là một thuật toán quay lui đơn giản: theo thứ tự kích thước giảm dần, cố gắng đặt một con tàu, và sau đó cố gắng đặt phần còn lại của các con tàu. Nếu nó không hoạt động, hãy thử khe tiếp theo. Ngay sau khi thành công, danh sách tàu không Xcó giá trị và việc truy cập X[0]sẽ ném ra một ngoại lệ thoát khỏi chương trình. Phần còn lại chỉ là chơi golf hạng nặng (ban đầu là 1615 ký tự).


2

Perl, 455 447 437 436 422 418

$n=($N=<>+0)+1;@S=map{(++$-)x$_}<>=~/\d+/g;$_=<>;$f=('~'x$N.$/)x$N;substr($f,$n*$1-$n-65+ord$&,1)=x while/\w(\d+)/g;sub f{for my$i(0..$N*$n-1){for(0..@_-2){my($f,@b)=@_;$m=($s=splice@b,$_,1)-1;pos=pos($u=$_=$f)=$i;for(s/\G(~.{$N}){$m}~/$&&("\0"."\377"x$N)x$s|(o."\0"x$N)x$m.o/se?$_:(),$u=~s/\G~{$s}/o x$s/se?$u:()){for$k(0,$N-1..$n){s/(?<=o.{$k})~|~(?=.{$k}o)/!/sg}return$:if$:=@b?f($_,@b):$_}}}}$_=f$f,@S;y/!/~/;print

Thụt lề:

$n=($N=<>+0)+1;
@S=map{(++$-)x$_}<>=~/\d+/g;
$_=<>;
$f=('~'x$N.$/)x$N;
substr($f,$n*$1-$n-65+ord$&,1)=x while/\w(\d+)/g;
sub f{
    for my$i(0..$N*$n-1){
        for(0..@_-2){
            my($f,@b)=@_;
            $m=($s=splice@b,$_,1)-1;
            pos=pos($u=$_=$f)=$i;
            for(s/\G(~.{$N}){$m}~/
              $&&("\0"."\377"x$N)x$s|(o."\0"x$N)x$m.o/se?$_:(),
              $u=~s/\G~{$s}/o x$s/se?$u:()){
                for$k(0,$N-1..$n){
                    s/(?<=o.{$k})~|~(?=.{$k}o)/!/sg
                }
                return$:if$:=@b?f($_,@b):$_
            }
        }
    }
}
$_=f$f,@S;
y/!/~/;
print

Tôi hy vọng nó có thể được chơi gôn hơn nữa (ví dụ với eval<>đầu vào được định dạng trước, như tôi thấy nó ổn (?)), Và một số thứ khác (50 $sigils? Không, chúng sẽ ở lại).

Tốc độ, như tôi đã nói trước đó, có thể là một vấn đề (từ tức thời (xem ví dụ bên dưới) đến rất rất dài), tùy thuộc vào vị trí của giải pháp trên cây đệ quy, nhưng hãy đặt nó là câu hỏi về sự lỗi thời của phần cứng được sử dụng. Tôi sẽ thực hiện phiên bản tối ưu hóa sau, với đệ quy đã mất và 2-3 thủ thuật rõ ràng khác.

Nó chạy như thế này, 3 dòng được cho ăn qua STDIN:

$ perl bf.pl
7
4 1 2 0 1
A1 B2 C3
xo~o~o~
~x~~~~~
o~xo~o~
~~~o~o~
o~~~~o~
o~~~~~~
o~ooooo

~là đại dương (giải pháp nghệ thuật, không phải vậy), oxlà những con tàu và bức ảnh. 5 dòng đầu tiên nhận đầu vào và chuẩn bị 'chiến trường' của chúng tôi. $Nlà kích thước, @Slà mảng tàu không được kiểm soát (ví dụ 1 1 1 1 2 3 3 5như trên), $flà một chuỗi đại diện cho chiến trường (các hàng có dòng mới được nối). Tiếp theo là chương trình con đệ quy, dự kiến ​​trạng thái chiến trường hiện tại và danh sách các tàu còn lại. Nó kiểm tra từ trái sang phải, từ trên xuống dưới và cố gắng đặt từng con tàu vào từng vị trí, theo cả chiều ngang và chiều dọc (xem? Chín để tối ưu hóa, nhưng sẽ muộn hơn). Tàu ngang là sự thay thế regrec rõ ràng, dọc một chút khó khăn hơn - thao tác chuỗi bit để thay thế trong 'cột'. Khi thành công (H, V hoặc cả hai), các vị trí không thể tiếp cận mới được đánh dấu bằng!và nó chuyển sang lần lặp tiếp theo. Và như vậy.

Chỉnh sửa: OK, đây là phiên bản 594 byte (khi chưa được thụt lề) thực sự hữu ích (tức là nhanh) - được tối ưu hóa hết khả năng của tôi trong khi vẫn thực hiện các kỹ thuật tương tự - đệ quy (mặc dù được thực hiện 'thủ công') và biểu thức chính quy. Nó duy trì một 'ngăn xếp' -@A- mảng các trạng thái đáng để điều tra. Một 'trạng thái' là 4 biến: chuỗi chiến trường hiện tại, chỉ mục từ nơi bắt đầu cố gắng đặt tàu, tham chiếu đến mảng các tàu còn lại và chỉ số của tàu tiếp theo để thử. Ban đầu có một "trạng thái" duy nhất - bắt đầu chuỗi trống, tất cả các tàu. Trong trận đấu (H hoặc V, xem ở trên), trạng thái hiện tại được đẩy để điều tra sau, trạng thái cập nhật (với một con tàu được đặt và vị trí không thể tiếp cận được đánh dấu) được đẩy và khối được khởi động lại. Khi kết thúc chuỗi chiến trường mà không thành công, trạng thái sẵn có tiếp theo @Asẽ được điều tra (nếu có).

Các tối ưu hóa khác là: không khởi động lại từ đầu chuỗi, cố gắng đặt tàu lớn trước, không kiểm tra tàu có cùng kích thước nếu tàu trước đó bị hỏng ở cùng vị trí, + có thể là một thứ khác (như không có $&biến, v.v.).

$N=<>+0;
$S=[reverse map{(++$-)x$_}<>=~/\d+/g];
$_=<>;
$f=('~'x$N.$/)x$N;
substr($f,$N*$2-$N+$2-66+ord$1,1)=x while/(\w)(\d+)/g;
push@A,$f,0,$S,0;
O:{
    ($f,$i,$S,$m)=splice@A,-4;
    last if!@$S;
    F:{ 
        for$j($m..$#$S){
            next if$j and$$S[$j]==$$S[$j-1];
            $s=$$S[$j];
            my@m;
            $_=$f;
            $n=$s-1;
            pos=$i;
            push@m,$_ if s/\G(?:~.{$N}){$n}~/
                ${^MATCH}&("\0"."\377"x$N)x$s|(o."\0"x$N)x$n.o/pse;
            $_=$f;
            pos=$i;
            push@m,$_ if s/\G~{$s}/o x$s/se;
            if(@m){
                push@A,$f,$i,$S,$j+1;
                my@b=@$S;
                splice@b,$j,1;
                for(@m){
                    for$k(0,$N-1..$N+1){
                        s/(?<=o.{$k})~|~(?=.{$k}o)/!/gs
                    }
                    push@A,$_,$i+1,\@b,0
                }
                redo O
            }
        }
        redo if++$i-length$f
    }
    redo if@A
}
print@$S?'':$f=~y/!/~/r

.

perl bf+.pl
10
5 4 3 2 1
A1 B2 C3 A10 B9 C10 J1 I2 H3 I9 J10 A5 C5 E5 F6 G7
xooooo~oox
~x~~~~~~x~
ooxooooxo~
~~~~~~~~o~
xoxoxoo~o~
~o~o~x~~o~
~o~o~ox~~~
~~~~~o~ooo
oxo~~~~~x~
x~x~o~o~ox

OTOH, nó vẫn mất mãi mãi cho trường hợp không thể 6 5 4 3 2 1trong ví dụ trên. Có lẽ phiên bản thực tế nên thoát ngay lập tức nếu tổng trọng tải tàu vượt quá khả năng của chiến trường.


2

Giải pháp C #

  public static class ShipSolution {
    private static int[][] cloneField(int[][] field) {

      int[][] place = new int[field.Length][];

      for (int i = 0; i < field.Length; ++i) {
        place[i] = new int[field.Length];

        for (int j = 0; j < field.Length; ++j)
          place[i][j] = field[i][j];
      }

      return place;

    }

    private static void copyField(int[][] source, int[][] target) {
      for (int i = 0; i < source.Length; ++i)
        for (int j = 0; j < source.Length; ++j)
          target[i][j] = source[i][j];
    }

    // Check if placement a legal one
    private static Boolean isPlacement(int[][] field, int x, int y, int length, Boolean isHorizontal) {
      if (x < 0)
        return false;
      else if (y < 0)
        return false;
      else if (x >= field.Length)
        return false;
      else if (y >= field.Length)
        return false;

      if (isHorizontal) {
        if ((x + length - 1) >= field.Length)
          return false;

        for (int i = 0; i < length; ++i)
          if (field[x + i][y] != 0)
            return false;
      }
      else {
        if ((y + length - 1) >= field.Length)
          return false;

        for (int i = 0; i < length; ++i)
          if (field[x][y + i] != 0)
            return false;
      }

      return true;
    }

    //  When ship (legally) placed it should be marked at the field
    //  2 - ship itself
    //  3 - blocked area where no other ship could be placed
    private static void markPlacement(int[][] field, int x, int y, int length, Boolean isHorizontal) {
      if (isHorizontal) {
        for (int i = 0; i < length; ++i)
          field[x + i][y] = 2;

        for (int i = x - 1; i < x + length + 1; ++i) {
          if ((i < 0) || (i >= field.Length))
            continue;

          for (int j = y - 1; j <= y + 1; ++j)
            if ((j >= 0) && (j < field.Length))
              if (field[i][j] == 0)
                field[i][j] = 3;
        }
      }
      else {
        for (int i = 0; i < length; ++i)
          field[x][y + i] = 2;

        for (int i = x - 1; i <= x + 1; ++i) {
          if ((i < 0) || (i >= field.Length))
            continue;

          for (int j = y - 1; j < y + length + 1; ++j)
            if ((j >= 0) && (j < field.Length))
              if (field[i][j] == 0)
                field[i][j] = 3;
        }
      }
    }

    // Ship placement itteration
    private static Boolean placeShips(int[][] field, int[] ships) {
      int[] vessels = new int[ships.Length];

      for (int i = 0; i < ships.Length; ++i)
        vessels[i] = ships[i];

      for (int i = ships.Length - 1; i >= 0; --i) {
        if (ships[i] <= 0)
          continue;

        int length = i + 1;

        vessels[i] = vessels[i] - 1;

        // Possible placements
        for (int x = 0; x < field.Length; ++x)
          for (int y = 0; y < field.Length; ++y) {
            if (isPlacement(field, x, y, length, true)) {
              int[][] newField = cloneField(field);

              // Mark
              markPlacement(newField, x, y, length, true);

              if (placeShips(newField, vessels)) {
                copyField(newField, field);

                return true;
              }
            }

            if (length > 1)
              if (isPlacement(field, x, y, length, false)) {
                int[][] newField = cloneField(field);

                // Mark
                markPlacement(newField, x, y, length, false);

                if (placeShips(newField, vessels)) {
                  copyField(newField, field);

                  return true;
                }
              }
          }

        return false; // <- the ship can't be placed legally
      }

      return true; //    <- there're no more ships to be placed
    }

    /// <summary>
    /// Solve ship puzzle
    /// </summary>
    /// <param name="size">size of the board</param>
    /// <param name="ships">ships to be placed</param>
    /// <param name="misses">misses in (line, column) format; both line and column are zero-based</param>
    /// <returns>Empty string if there is no solution; otherwise possible ship placement where
    ///   . - Blank place
    ///   * - "miss"
    ///   X - Ship
    /// </returns>
    public static String Solve(int size, int[] ships, String[] misses) {
      int[][] field = new int[size][];

      for (int i = 0; i < size; ++i)
        field[i] = new int[size];

      if (!Object.ReferenceEquals(null, misses))
        foreach (String item in misses) {
          String miss = item.Trim().ToUpperInvariant();

          int x = int.Parse(miss.Substring(1)) - 1;
          int y = miss[0] - 'A';

          field[x][y] = 1;
        }

      if (!placeShips(field, ships))
        return "";

      StringBuilder Sb = new StringBuilder();

      foreach (int[] line in field) {
        if (Sb.Length > 0)
          Sb.AppendLine();

        foreach (int item in line) {
          if (item == 1)
            Sb.Append('*');
          else if (item == 2)
            Sb.Append('X');
          else
            Sb.Append('.');
        }
      }

      return Sb.ToString();
    }
  }

  ...

  int size = 4;
  int[] ships = new int[] { 1, 1, 1 };
  String[] misses = new String[] {"C1", "C2", "B2", "A3", "A1", "B3", "D1"};

  // *X**
  // .**X
  // **.X
  // XX.X
  Console.Out.Write(ShipSolution.Solve(size, ships, misses));

Mặc dù đây là một giải pháp tuyệt vời và nhanh chóng, nhưng nó dường như không xử lý các nhiệm vụ không thể giải quyết một cách chính xác. Ví dụ , size=1 ships={1} moves={"A1"}.
mniip

Tôi xin lỗi, tôi đã bỏ lỡ điều kiện khi con tàu tiếp theo không thể được đặt hợp pháp. Tôi đã chỉnh sửa giải pháp.
Dmitry Byigan

6
Vì câu hỏi là môn đánh gôn , vui lòng cố gắng giữ số lượng ký tự của bạn càng thấp càng tốt (ví dụ bằng cách xóa khoảng trắng) và bao gồm số ký tự trong mã của bạn.
Chương trìnhFOX

Số lượng nhân vật như hiện tại là 5399.
intx13

1

Java, 1178

Vâng, quá lâu ._.

import java.util.*;class S{public static void main(String[]a){new S();}int a;int[][]f;List<L>l;Stack<Integer>b;S(){Scanner s=new Scanner(System.in);a=s.nextInt();f=new int[a][a];for(int[]x:f)Arrays.fill(x,95);s.next(";");b=new Stack();for(int i=1;s.hasNextInt();i++){b.addAll(Collections.nCopies(s.nextInt(),i));}s.next(";");while(s.findInLine("([A-Z])")!=null)f[s.match().group(1).charAt(0)-65][s.nextInt()-1]=79;l=new ArrayList();for(int i=0;i<a;i++){l.add(new L(i){int g(int c){return g(c,i);}void s(int c,int v){f[c][i]=v;}});l.add(new L(i){int g(int r){return g(i,r);}void s(int r,int v){f[i][r]=v;}});}if(s()){String o="";for(int r=0;r<a;r++){for(int c=0;c<a;c++)o+=(char)f[c][r];o+='\n';}System.out.print(o);}}boolean s(){if(b.empty())return true;int s=b.pop();Integer n=95;for(L c:l){int f=0;for(int x=0;x<a;x++){if(n.equals(c.g(x)))f++;else f=0;if(f>=s){for(int i=0;i<s;i++)c.s(x-i,35);if(s())return true;for(int i=0;i<s;i++)c.s(x-i,n);}}}b.push(s);return false;}class L{int i;L(int v){i=v;}void s(int i,int v){}int g(int i){return 0;}int g(int c,int r){int v=0;for(int x=-1;x<2;x++)for(int y=-1;y<2;y++)try{v|=f[c+x][r+y];}catch(Exception e){}return v&(f[c][r]|32);}}}

Ung dung:

import java.util.*;

class S {
    public static void main(String[] a) {
        new S();
    }

    /**
     * Number of rows/columns
     */
    int a;

    /**
     * A reference to the full field
     */
    int[][] f;

    /**
     * List of Ls representing all columns/rows
     */
    List<L> l;

    /**
     * Stack of all unplaced ships, represented by their length as Integer
     */
    Stack<Integer> b;

    S() {
        // Read input from STDIN:
        Scanner s = new Scanner(System.in);
        a = s.nextInt();
        f = new int[a][a];
        // initialize field to all '_'
        for(int[] x: f)
            Arrays.fill(x, 95);
        // ; as separator
        s.next(";");
        b = new Stack();
        // Several int to represent ships
        for (int i = 1; s.hasNextInt(); i++) {
            // nCopies for easier handling (empty Stack => everything placed)
            b.addAll(Collections.nCopies(s.nextInt(), i));
        }
        // ; as separator
        s.next(";");
        // find an uppercase letter on this line
        while (s.findInLine("([A-Z])") != null) {
            // s.match.group(1) contains the matched letter
            // s.nextInt() to get the number following the letter
            f[s.match().group(1).charAt(0) - 65][s.nextInt() - 1] = 79;
        }
        // Loop is left when line ends or no uppercase letter is following the current position

        // Now create a List of Lists representing single columns and rows of our field
        l = new ArrayList();
        for (int i = 0; i < a; i++) {
            l.add(new L(i) {
                int g(int c) {
                    return g(c, i);
                }

                void s(int c, int v) {
                    f[c][i] = v;
                }
            });
            l.add(new L(i) {
                int g(int r) {
                    return g(i, r);
                }

                void s(int r, int v) {
                    f[i][r] = v;
                }
            });
        }
        // try to place all ships
        if (s()) {
            // print solution
            String o = "";
            for (int r = 0; r < a; r++) {
                for (int c = 0; c < a; c++) {
                    o += (char) f[c][r];
                }
                o += '\n';
            }
            System.out.print(o);
        }
    }

    /**
     * Try to place all ships
     *
     * @return {@code true}, if a solution is found
     */
    boolean s() {
        if (b.empty()) {
            // no more ships
            return true;
        }
        // take a ship from the stack
        int s = b.pop();
        // 95 is the Ascii-code of _
        Integer n = 95;
        // go over all columns and rows
        for (L c : l) {
            // f counts the number of consecutive free fields
            int f = 0;
            // move through this column/row
            for (int x = 0; x < a; x++) {
                // Is current field free?
                if (n.equals(c.g(x))) {
                    f++;
                } else {
                    f = 0;
                }
                // Did we encounter enough free fields to place our ship?
                if (f >= s) {
                    // enter ship
                    for (int i = 0; i < s; i++) {
                        c.s(x - i, 35);
                    }
                    // try to place remaining ships
                    if (s()) {
                        return true;
                    }
                    // placing remaining ships has failed ; remove ship
                    for (int i = 0; i < s; i++) {
                        c.s(x - i, n);
                    }
                }
            }
        }
        // we have found no place for our ship so lets push it back
        b.push(s);
        return false;
    }

    /**
     * List representing a single row or column of the field.
     * "Abstract"
     */
    class L {
        /**
         * Index of row/column. Stored here as loop-variables can not be final. Used only {@link #g(int)} and {@link #s(int, int)}
         */
        int i;

        L(int v) {
            i = v;
        }

        /**
         * Set char representing the state at the i-th position in this row/column.
         * "Abstract"
         */
        void s(int i, int v) {
        }

        /**
         * Get char representing the state at the i-th position in this row/column.
         * "Abstract"
         *
         * @return {@code '_'} if this and all adjacent field contain no {@code '#'}
         */
        int g(int i) {
            return 0;
        }

        /**
         * Get char representing the state at the position in c-th column and r-th row
         *
         * @return {@code '_'} if this and all adjacent field contain no {@code '#'}
         */
        int g(int c, int r) {
            // v stores the result
            int v = 0;
            // or all adjacent fields
            for (int x = -1; x < 2; x++) {
                for (int y = -1; y < 2; y++) {
                    // ungolfed we should use something like
                    // v |= 0 > c + x || 0 > r + y || c + x >= a || r + y >= a ? 0 : f[c + x][r + y];
                    // but his will do (and is shorter)
                    try {
                        v |= f[c + x][r + y];
                    } catch (Exception e) {
                    }
                }
            }
            // we use '_' (95), 'O' (79), '#' (35). Only 35 contains the 32-bit
            // So we only need the 32-bit of the or-ed-value + the bits of the value directly in this field
            return v & (f[c][r] | 32);
        }

    }
}

Đầu vào mẫu

6 ; 3 2 1 ; A1 A3 B2 C3 D4 E5 F6 B6 E3 D3 F4

Đầu ra mẫu

O###_#
_O____
O_OOO#
#_#O_O
#_#_O#
_O___O

Với

  • O bắn hụt
  • # phần tàu
  • _ bắn vào đây tiếp theo ;-)

Xem trên ideone.com

Xử lý đầu vào dự kiến ​​các khoảng trống xung quanh các số / ;và sẽ không hoạt động khác.

Tôi đang đặt những con tàu lớn trước vì chúng có ít nơi để đi hơn. Nếu bạn muốn chuyển sang nhỏ đầu tiên bạn có thể thay pop()bằng remove(0)push(s)bởi add(0,s)thậm chí thay thế chỉ một trong hai vẫn nên kết quả trong một chương trình hợp lệ.

Nếu bạn cho phép các tàu chạm vào nhau, g(int,int)chức năng có thể được đơn giản hóa hoặc loại bỏ rất nhiều.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.