ตำแหน่งเรือประจัญบานขี้เกียจ


39

ลองนึกภาพสถานการณ์ต่อไปนี้: คุณกำลังเล่นเรือรบกับเพื่อน แต่ตัดสินใจที่จะโกง แทนที่จะย้ายเรือหลังจากที่เขายิงจุดที่เรือของคุณเคยเป็นคุณตัดสินใจที่จะไม่วางเรือใด ๆ เลย คุณบอกเขาว่าทุกช็อตของเขาพลาดไปจนกว่าจะไม่สามารถวางเรือในลักษณะนี้ได้

คุณต้องเขียนฟังก์ชั่นหรือโปรแกรมเต็มรูปแบบที่ใช้เวลา 3 ข้อโต้แย้ง: ขนาดฟิลด์รายการจำนวนขนาดของเรือและรายการของภาพ

สนามรบ

หนึ่งในพารามิเตอร์ที่กำหนดคือขนาดกระดาน สนามรบเป็นรูปสี่เหลี่ยมจัตุรัสของเซลล์และพารามิเตอร์ที่กำหนดเป็นเพียงด้านเดียวของจัตุรัส
ตัวอย่างเช่นต่อไปนี้เป็นบอร์ดขนาด 5

พิกัดบนฟิลด์ถูกระบุเป็นสตริง 2 องค์ประกอบ: ตัวอักษรตามด้วยตัวเลข คุณสามารถพึ่งพาตัวอักษรในบางกรณี
ตัวอักษรระบุคอลัมน์ตัวเลขระบุแถวของเซลล์ (1 ดัชนี) "D2"ยกตัวอย่างเช่นในภาพข้างบนเซลล์ที่ไฮไลต์คือการแสดงโดย
เนื่องจากมีเพียง 26 ตัวอักษรสนามจึงไม่สามารถมีขนาดใหญ่กว่า 26x26

เรือ

เรือเป็นเส้นตรงที่มี 1 บล็อกขึ้นไป จำนวนเรือถูกระบุในรายการโดยที่องค์ประกอบแรกคือจำนวนเรือ 1 เซลล์สอง - จากเรือ 2 เซลล์และอื่น ๆ
ตัวอย่างเช่นรายการ[4,1,2,0,1]จะสร้างชุดต่อไปนี้:

เมื่อวางไว้ในสนามรบเรือไม่สามารถตัดกันหรือแม้แต่แตะต้องกัน ไม่แม้แต่กับมุม อย่างไรก็ตามพวกเขาสามารถสัมผัสขอบของสนาม
ด้านล่างคุณสามารถดูตัวอย่างของการจัดส่งที่ถูกต้อง:

คุณสามารถสันนิษฐานได้ว่าสำหรับเรือที่ได้รับนั้นจะมีตำแหน่งบนกระดานเปล่าตามขนาดที่กำหนด

เอาท์พุต

หากตำแหน่งของเรือดังกล่าวมีอยู่คุณจะต้องแสดงผลลัพธ์ใด ๆ
โปรแกรมจะต้องส่งออกเมทริกซ์ที่คั่นด้วยการขึ้นบรรทัดใหม่ของอักขระ ASCII ทั้ง 3 ประเภท - หนึ่งเพื่อแสดงเซลล์ว่างเปล่าหนึ่ง - ชิ้นส่วนเรือและหนึ่ง - เซลล์ทำเครื่องหมายว่า "พลาด" ไม่ควรส่งออกอักขระอื่น
ตัวอย่างเช่น,

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

(ในตัวอย่างนี้ฉันกำหนด@ให้เป็นเซลล์ว่างเปล่าเป็นเซลล์\"พลาด" และZเป็นชิ้นส่วนจัดส่ง)

หากไม่มีตำแหน่งดังกล่าวโปรแกรม / ฟังก์ชั่นควรกลับมาโดยไม่แสดงผลใด ๆ

อินพุต

หากคุณตัดสินใจที่จะสร้างโปรแกรมเต็มรูปแบบขึ้นอยู่กับว่าคุณระบุว่ารายการนั้นป้อนเข้ามาอย่างไรบางรายการอาจผ่านข้อโต้แย้งบางรายการผ่าน stdin

นี่คือจำนวนอักขระต่ำสุดชนะ

ตัวอย่างโซลูชันที่ไม่เหมาะกับการเล่นกอล์ฟสามารถดูได้ที่นี่
คอมไพล์ด้วย-std=c99อาร์กิวเมนต์แรกคือขนาดของบอร์ดส่วนอาร์กิวเมนต์อื่นคือขนาดของเรือ รายการภาพที่คั่นด้วยการขึ้นบรรทัดใหม่ถูกกำหนดไว้บน stdin ตัวอย่าง:
./a 4 1 1 1 <<< $'A2\nA4\nB3\nC3\nC4\D4'


26x26? ผมร่างแก้ปัญหาบนพื้นฐานของ regexps และเรียกซ้ำและจะได้รับช้ามาก = 6x6ใช้ไม่ได้สำหรับเขตข้อมูลมากกว่า ไม่ว่าฉันจะทำอะไรที่โง่มากหรือขาดคำตอบก็หมายความว่าคนอื่นก็ไม่ประสบความสำเร็จ
2846289

ฉันเพิ่งเขียนการใช้งานใน C มันคำนวณทันทีเป็นเวลาอย่างน้อย10x10กับชุด4,3,2,1เรือ
mniip

@mniip: คุณมีวิธีรับมือกับกรณียาก ๆ หรือไม่ (กระดานใหญ่เรือหลายลำล้มเหลวเนื่องจากตำแหน่งของการยิง)? หรือเป็นเพียงกำลังดุร้าย (ฉลาดเล็กน้อย)?
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

มันมีการปรับให้เหมาะสมเล็กน้อย, fe พยายามที่จะวางเรือรบลำเล็กก่อนและไม่รวมเรือรบที่มีขนาดเท่ากันจากกำลังดุร้าย มันค่อนข้างช้าเมื่อมีเรือจำนวนมากบนกระดานขนาดเล็กและว่างเปล่าเกือบ
mniip

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ ฉันได้เพิ่มลิงค์ตัวอย่างเช่น
mniip

คำตอบ:


2

GolfScript 236 ตัวอักษร

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!!*

อินพุตถูกกำหนดบน STDIN บรรทัดแรกมีขนาดและจำนวนเรือรบแต่ละพิกัดบรรทัดต่อไปนี้ของนัดเดียว

ตัวอย่าง:

4 1 1 1
A2
A4
B3
C3
C4
D4

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

ฉันคิดว่าความท้าทายนี้ควรมีคำตอบ GolfScript อย่างน้อยหนึ่งคำ ในที่สุดมันก็กลายเป็นสิ่งไม่สวยงามมากเนื่องจากอัลกอริธึมที่ใช้ซึ่งสนับสนุนประสิทธิภาพการทำงานในระยะสั้น

รหัสข้อเขียน:

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ไบต์

1 การสิ้นสุดบรรทัด UNIX บรรทัดใหม่สุดท้ายไม่ถูกนับ

รุ่นที่มีการเพิ่มประสิทธิภาพทั้งหมดถูกลบ ( 441ไบต์):

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

เนื่องจากรหัสถูกเปลี่ยนเพื่อลดจำนวนไบต์จึงไม่ยอมรับรายการภาพที่ซ้ำกันอีกต่อไป


รุ่นที่มีการเพิ่มประสิทธิภาพพื้นฐานกอล์ฟเต็ม ( 536 → 506ไบต์)

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

ฉันใช้การตรวจสอบขั้นพื้นฐานบางอย่าง ( นับจำนวนบล็อกการเดินเรือที่จำเป็น ) เพื่อทำให้โค้ดออกเร็วขึ้น รหัสนี้ยังมีภูมิคุ้มกันที่จะซ้ำในรายการนัดจนถึง


ด้านล่างนี้เป็นรุ่นที่อ่านได้บ้างมีความคิดเห็นโดยละเอียด:

:-[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

รูปแบบการค้นหา:

game(Board_Size, Ships_List, Shots_List).

ตัวอย่างแบบสอบถาม (ใช้ตัวอย่างในคำถาม):

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

อี้ยเอาชนะฉันด้วยตัวละครไม่กี่โหล! ไม่แน่ใจว่าฉันสามารถบีบอัดของฉันได้อีกหรือไม่ แต่ฉันจะลองใช้ Prolog ต่อไป!
Claudiu

@Claudiu: โซลูชันของฉันยังมี "บัฟเฟอร์" 20 ตัวอักษร ฉันทิ้งโค้ดการตรวจสอบเหล่านั้นไว้ที่นั่นด้วยเหตุผลด้านประสิทธิภาพ แต่สามารถลบออกได้โดยไม่ส่งผลกระทบต่อความถูกต้อง;) ฉันไม่ต้องกังวลหากคำตอบอื่น ๆ ได้ต่ำกว่า 500
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

5

Matlab - 536 ตัวอักษร

อัปเดต: การจัดรูปแบบเอาต์พุตมีขนาดเล็กลงมากช่องว่างบางวงถูกลบออก

อัปเดต: เพิ่มเวอร์ชัน golfed

อัปเดต: เพิ่มเวอร์ชันที่แสดงความคิดเห็นลดเวอร์ชัน golfed โดย ~ 100 chars

% 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

นี่คือเวอร์ชั่น golfed

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

นี่คือตัวอย่างบางส่วน

>>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])
:(

บรรทัดใหญ่ที่มี 'kron' (ใกล้ด้านล่างของรหัสที่ไม่ตีกอล์ฟ) คือส่วนที่ฉันชอบ มันเขียน '1' ไปยังสถานที่ทั้งหมดในแผนที่ที่เพื่อนบ้านตั้งอยู่ในตำแหน่งที่กำหนด คุณเห็นไหมว่ามันทำงานอย่างไร มันใช้ผลิตภัณฑ์ kronecker tensor, การคูณเมทริกซ์และจัดทำดัชนีแผนที่เป็นอาร์เรย์เชิงเส้น ...


4

Python 464 ตัวอักษร

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)

อินพุต (stdin):

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

เอาท์พุท:

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

ทำงานโดยใช้จำนวนเต็มที่เก็บบิตแมปของคุณสมบัติต่าง ๆ

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̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

มีการเพิ่มประสิทธิภาพหนึ่งอย่าง: [::-1]ซึ่งทำให้ลองใช้งานเรือที่ยาวที่สุดก่อน มันยังย้อนรอยทันทีที่พบเรือที่ไม่สามารถวางได้
Keith Randall

คุณสามารถใช้แท็บเดียวแทน 2 หรือ 3 ช่องว่างในสาย 7, 8, 11, 12 และลดการนับไบต์เพื่อ 458. ดูที่นี่
mbomb007

3

Python, 562 ตัวอักษร, -8 พร้อมเอาต์พุตน่าเกลียด, +4? สำหรับการเชิญทุบตี

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)

หมายเหตุ: ระดับเยื้องคือช่องว่างแท็บแท็บ + ช่องว่างแท็บ + แท็บและแท็บ + แท็บ + ช่องว่าง วิธีนี้ช่วยประหยัดอักขระสองสามตัวจากการใช้ช่องว่างเท่านั้น

การใช้งานและตัวอย่าง :

รับอินพุตจากอาร์กิวเมนต์บรรทัดรับคำสั่ง ส่งออกช่องว่างเป็นช่องว่างยิงเป็น.และ@เป็นส่วนหนึ่งของเรือรบ:

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

เมื่อแก้ไม่ตกไม่พิมพ์อะไร:

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

การ2>Xระงับข้อความแสดงข้อผิดพลาดตั้งแต่ออกจากโปรแกรมโดยการโยนข้อยกเว้น อย่าลังเลที่จะเพิ่มบทลงโทษ +4 ถ้าถือว่ายุติธรรม ไม่งั้นฉันก็ต้องทำ a try: ... except:0เพื่อยับยั้งมันซึ่งจะใช้ตัวละครมากกว่านี้

ฉันยังสามารถพิมพ์ออกเป็นตัวเลข ( 0, 1และ2) เพื่อโกน 8 ตัวอักษร แต่ฉันสวยงามคุ้มค่า

คำอธิบาย :

ฉันแสดงบอร์ดเป็นรายการของจำนวนเต็มที่มีขนาดใหญ่กว่าอินพุต 2 เพื่อหลีกเลี่ยงการตรวจสอบขอบเขต 0หมายถึงพื้นที่ว่าง1ยิงและ2เรือ ฉันวิ่งผ่านรายการช็อตQและทำเครื่องหมายช็อตทั้งหมด ฉันจะแปลงรายการของเรือไปยังรายการที่ชัดเจนXของเรือเช่นกลายเป็น[4, 0, 2, 0, 1] [5, 3, 3, 1, 1, 1, 1]จากนั้นเป็นอัลกอริทึมการย้อนรอยง่าย ๆ : ตามลำดับจากมากไปหาน้อยลองวางเรือรบแล้วลองวางส่วนที่เหลือของเรือ หากไม่ได้ผลให้ลองช่องถัดไป ทันทีที่ประสบความสำเร็จรายชื่อเรือXจะเป็นโมฆะและการเข้าถึงจะX[0]ส่งข้อยกเว้นที่ออกจากโปรแกรม ส่วนที่เหลือเป็นเพียงการเล่นกอล์ฟหนัก


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

เยื้อง:

$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

ฉันคาดหวังว่ามันจะสามารถเล่นกอล์ฟได้มากขึ้น (เช่นeval<>สำหรับการป้อนข้อมูลที่มีการจัดรูปแบบไว้ล่วงหน้าตามที่ฉันเห็นว่ามันโอเค (?)) และสิ่งอื่น ๆ อีกด้วย (50 $เครื่องหมายไม่?

ความเร็วตามที่ฉันกล่าวไว้ก่อนหน้านี้อาจเป็นปัญหา (จากตัวอย่างทันที (ดูตัวอย่างด้านล่าง) ไปจนถึงยาวมาก) ขึ้นอยู่กับตำแหน่งที่โซลูชันอยู่บนต้นไม้ที่เรียกซ้ำ แต่ให้คำถามเกี่ยวกับความล้าสมัยของฮาร์ดแวร์ที่ใช้ ฉันจะปรับรุ่นให้เหมาะสมในภายหลังโดยการเรียกซ้ำไปมาและอีก 2-3 เทคนิคที่ชัดเจน

มันทำงานแบบนี้มี 3 สายที่ป้อนผ่าน 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

~คือมหาสมุทร (คำตอบทางศิลปะใช่มั้ย) oและxเป็นเรือและช็อต 5 บรรทัดแรกรับอินพุตและเตรียม 'สนามรบ' ของเรา $Nis size, @Sคืออาร์เรย์ที่ไม่ได้ควบคุมของเรือ (เช่น1 1 1 1 2 3 3 5ด้านบน), $fเป็นสตริงที่แสดงถึงสนามรบ (แถวที่มีการขึ้นบรรทัดใหม่) ถัดไปคือรูทีนย่อยแบบเรียกซ้ำซึ่งคาดว่าสถานะสนามรบปัจจุบันและรายชื่อเรือที่เหลือ มันตรวจสอบจากซ้ายไปขวาบนลงล่างและพยายามวางเรือแต่ละลำในแต่ละตำแหน่งทั้งแนวนอนและแนวตั้ง (ดู? สุกเพื่อปรับให้เหมาะสม แต่มันจะเป็นภายหลัง) เรือในแนวนอนคือการแทนที่ regexp ที่เห็นได้ชัดแนวตั้ง bit trickier - การจัดการสตริง bitwise เพื่อแทนที่ใน 'คอลัมน์' ในความสำเร็จ (H, V หรือทั้งสองอย่าง) ตำแหน่งที่เข้าไม่ถึงใหม่จะถูกทำเครื่องหมายด้วย!และมันจะทำการวนซ้ำในครั้งถัดไป และอื่น ๆ

แก้ไข:ตกลงรุ่นต่อไปนี้ของ594ไบต์ (เมื่อไม่มีการเยื้อง) ที่พยายามจะมีประโยชน์ (เช่นเร็ว) - ปรับให้เหมาะกับความสามารถของฉันมากที่สุดในขณะที่ยังคงใช้เทคนิคเดียวกัน - เรียกซ้ำ (แม้ว่าจะทำเอง) มันจะรักษา 'สแต็ค' -@A- อาร์เรย์ของรัฐที่คุ้มค่าในการตรวจสอบ 'สถานะ' คือตัวแปร 4 ตัว: สตริงสนามรบปัจจุบันดัชนีจากตำแหน่งที่จะพยายามวางเรือรบอ้างอิงไปยังอาร์เรย์ของเรือรบที่เหลือและดัชนีของเรือต่อไปที่จะลอง เริ่มแรกมี 'สถานะ' เดียว - เริ่มต้นของสตริงว่างเรือทั้งหมด ในการแข่งขัน (H หรือ V ดูที่ด้านบน) สถานะปัจจุบันจะถูกผลักเพื่อตรวจสอบในภายหลังสถานะที่อัปเดต (ด้วยการวางเรือรบและตำแหน่งที่เข้าไม่ถึง) จะถูกผลักและบล็อกจะถูกรีสตาร์ท เมื่อถึงจุดสิ้นสุดของสตริงสนามรบโดยไม่ประสบความสำเร็จสถานะที่พร้อมใช้งานถัดไป@Aจะถูกตรวจสอบ (ถ้ามี)

การเพิ่มประสิทธิภาพอื่น ๆ : ไม่รีสตาร์ทจากจุดเริ่มต้นของสตริงพยายามวางเรือรบขนาดใหญ่ก่อนไม่ตรวจสอบเรือรบที่มีขนาดเท่ากันถ้าเรือลำก่อนหน้านี้ล้มเหลวในตำแหน่งเดียวกัน + อาจเป็นอย่างอื่น (เช่นไม่มี$&ตัวแปร ฯลฯ )

$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 มันยังใช้เวลาตลอดไปสำหรับกรณีที่เป็นไปไม่ได้6 5 4 3 2 1ในตัวอย่างข้างต้น บางทีเวอร์ชั่นที่ใช้งานได้จริงควรออกทันทีถ้าน้ำหนักของเรือรวมเกินขีดความสามารถของสนามรบ


2

โซลูชัน 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));

แม้ว่านี่จะเป็นวิธีแก้ปัญหาที่ยอดเยี่ยมและรวดเร็ว แต่ดูเหมือนว่าจะไม่สามารถจัดการกับงานที่แก้ไม่ได้อย่างถูกต้อง ตัวอย่างเช่น size=1 ships={1} moves={"A1"}.
mniip

ฉันขอโทษฉันพลาดเงื่อนไขเมื่อเรือลำต่อไปไม่สามารถวางได้อย่างถูกกฎหมาย ฉันแก้ไขวิธีแก้ปัญหาแล้ว
Dmitry Bychenko

6
เนื่องจากคำถามคือโค้ดกอล์ฟโปรดพยายามรักษาจำนวนตัวละครของคุณให้ต่ำที่สุดเท่าที่จะทำได้ (โดยลบช่องว่างออก) และรวมจำนวนตัวอักษรในรหัสของคุณ
ProgramFOX

จำนวนตัวละครที่เป็นอยู่ตอนนี้คือ 5399
intx13

1

Java, 1178

ใช่นานเกินไป

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);}}}

Ungolfed:

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);
        }

    }
}

ตัวอย่างการป้อนข้อมูล

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

ตัวอย่างเอาท์พุท

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

กับ

  • O ยิงพลาด
  • # เรือส่วนหนึ่ง
  • _ ยิงที่นี่ต่อไป ;-)

ดูที่ideone.com

การจัดการอินพุตคาดว่าจะมีช่องว่างรอบ ๆ ตัวเลข / ;และจะไม่ทำงานเป็นอย่างอื่น

ฉันวางเรือลำใหญ่ก่อนเพราะพวกเขามีที่ให้น้อยลง หากคุณต้องการเปลี่ยนมาใช้รุ่นเล็กก่อนคุณสามารถแทนที่pop()ด้วยremove(0)และpush(s)โดยการadd(0,s)แทนที่แม้แต่หนึ่งในสองข้อเท่านั้นก็ควรที่จะส่งผลให้โปรแกรมที่ถูกต้องใช้งานได้

หากคุณอนุญาตให้เรือรบแตะกันg(int,int)ฟังก์ชั่นนั้นสามารถทำให้ง่ายขึ้นหรือลบออกอย่างมากมาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.