0

我正在努力扩展约束问题(它会因大值和/或如果我尝试优化而不是仅仅寻找任何解决方案而崩溃)。根据之前一些问题的建议,我已经采取了一些步骤来分解搜索空间,但它仍然停滞不前。还有其他技术可以帮助我优化此计算吗?

%%% constants %%%
#const nRounds = 4.
#const nPlayers = 20.
#const nRooms = 4.
#const nDecks = 7.

player(1..nPlayers).
room(1..nRooms).
deck(1..nDecks).
writer(1,1;2,2;3,3;4,4).

% For reference - that's what I started with:
%nRounds { seat(Player, 1..nRooms, 1..nDecks) } nRounds :- player(Player).

% Now instead I'm using a few building blocks
% Each player shall only play nRounds decks
nRounds { what(Player, 1..nDecks) } nRounds :- player(Player).
% Each player shall only play in up to nRounds rooms.
1 { where(Player, 1..nRooms) } nRounds :- player(Player).
% For each deck, 3 or 4 players can play in each room.
3 { who(1..nPlayers, Room, Deck) } 4 :- room(Room), deck(Deck).
% Putting it all together, hopefully, this leads to fewer combinations than the original monolithic choice rule.
{ seat(Player, Room, Deck) } :- what(Player, Deck), where(Player, Room), who(Player, Room, Deck).

% A player can only play a deck in a single room.
:- seat(Player, Room1, Deck), seat(Player, Room2, Deck), Room1 != Room2.
% A player must play nRounds decks overall.
:- player(Player), #count { Room, Deck: seat(Player, Room, Deck) } != nRounds.
% Any deck in any room must be played by 3-4 players.
legal_player_count(3..4).
:- room(Room), deck(Deck),
  Players = #count { Player: seat(Player, Room, Deck) },
  Players > 0,
  not legal_player_count(Players).
% Writers cannot play their own decks.
:- writer(Player, Deck), seat(Player, _, Deck).
% At least one non-playing player per room.
:- deck(Deck),
  Playing = #count { Player, Room: seat(Player, Room, Deck) },
  Rooms = #count { Room: seat(_, Room, Deck) },
  nPlayers - Playing < Rooms.

%:- room(R1), deck(D), room(R2), X = #sum { P: seat(P, R1, D) }, Y = #sum { P: seat(P, R2, D) }, R1 > R2, X > Y.

#minimize { D: decks(D) }.

#show decks/1.
#show seat/3.
% #show common_games/3.

何时或如果这变得可以管理,我希望添加更多优化目标以选择最佳配置:

% Input points(P, R, D, X) to report points.
% winner(P, R, D) :- points(P, R, D, X), X = #max { Y : points(_, R, D, Y) }.
% Compute each player's rank based on each round:
% rank(P, D, R) :- points(P, Room, D, X), winner(Winner, Room, D), D_ = D - 1,
%   rank(P, D_, R_),
%   R = some_combination_of(X, P=Winner, R_).
% latest_rank(P, R) :- D = #max { DD: rank(P, DD, _) }, rank(P, D, R).

% Total number of decks played throughout the night (for minimisation?)
decks(Decks) :- Decks = #count { Deck: seat(_, _, Deck) }.
% Total number of games played together by the same players (for minimisation)
% The total sum of this predicate is invariant
% Minimisation should took place by a superlinear value (e.g. square)
common_games(Player1, Player2, Games) :-
  player(Player1), player(Player2), Player1 != Player2,
  Games = #count { Room, Deck:
    seat(Player1, Room, Deck),
    seat(Player2, Room, Deck)
  }, Games > 0.

% For example:
% common_game_penalty(X) :- X = #sum { Y*Y, P1, P2 : common_games(P1, P2, Y) }.

% Another rank-based penalty needs to be added once the rank mechanics are there

% Then the 2 types of penalties need to be combined and / or passed to the optimiser

更新 - 问题描述

  • P 玩家聚在一起进行问答之夜。D甲板和R房间 可以玩。
  • 每个房间只能容纳 3 或 4 名玩家(由于游戏规则,而不是空间)。
  • 每个套牌最多播放一次,并同时在多个房间播放 - 所以从某种意义上说,套牌是“回合”的代名词。
  • 每个玩家最多只能玩同一个套牌一次。
  • 每个玩家在晚上只能玩 N 次(N 几乎是固定的,为 4)。
  • 因此,如果在晚上玩 9 套牌(即如果有很多玩家在场),则每张牌都会玩这 9 套中的 4 套。
  • 因此,每个玩家没有必要在每个“套牌/回合”中玩。事实上,每一副牌都有一个作家,而且通常是其中一名玩家。
  • 当然,作者不能玩他们自己的套牌,所以他们必须在这一轮中呆在外面。此外,对于每一副牌/回合,必须有人阅读每个房间的问题,因此如果有 16 名玩家在场并且有 4 个房间,那么 16 名玩家不可能全部参与。可以有 4 个房间,每个房间有 3 名玩家(其余 4 名玩家读出问题)或有 3 个房间,每个房间有 4 名玩家(有 3 名玩家读出问题和 1 名旁观者)。

希望这可以消除混淆,如果不是,我可以尝试提供更详细的示例,但基本上,假设您有 4 个房间和 30 个玩家:

  • 你选择了 16 位选手和另外 4 位选手读出问题
  • 然后你有 16 个人玩了他们的 1/4 套牌/回合,还有 14 个人仍然在 0/4
  • 因此,您可以让其他 14 人玩(每个房间 4、4、3、3 名玩家)或继续最大化房间实用性,以便在第二轮之后每个人至少玩一次,并且 2/30 玩家已经玩过 2/ 4场比赛。
  • 然后你继续挑选一些人,直到每个人都玩了 4 副牌/轮。

PS你有2个回合的概念——一个是个人级别的,每个人都有4个可以玩,另一个是联赛级别,有一些甲板数量> 4,每个甲板在在场的每个人眼中都被认为是“一轮” . 据我了解,这是关于设置的最令人困惑的一点,我一开始没有很好地澄清。

4

1 回答 1

0

我已经用你的新规范重写了编码,没有太多的优化来解决问题。

备注:我假设“阅读问题”的人是作者?我保证每个房间有 1 位作家,但我没有说出它的名字。

#const nPlayers = 20.                                                                                                  
#const nRooms = 4.                                                                                                     
#const nDecks = 6.                                                                                                     

player(1..nPlayers).                                                                                                   
room(1..nRooms).                                                                                                       
deck(1..nDecks).                                                                                                       

% player P plays in room R in round D                                                                                  
{plays(P,R,D)} :- deck(D), room(R), player(P).                                                                         

% a player may only play in a single room each round
:- player(P), deck(D), 1 < #sum {1,R : plays(P,R,D)}.                                                                  

% not more than 4 players per room                                                                                     
:- deck(D), room(R), 4 < #sum {1,P : plays(P,R,D)}.                                                                    
% not less than 3 players per room                                                                                     
:- deck(D), room(R), 3 > #sum {1,P : plays(P,R,D)}.                                                                    

plays(P,D) :- plays(P,R,D).                                                                                            
% at least one writer per room (we need at least one player not playing for each room, we do not care who does it)     
:- deck(D), nRooms > #sum {1,P : not plays(P,D), player(P)}.                                                           

% each player only plays 4 times during the night                                                                      
:- player(P), not 4 = #sum {1,D : plays(P,D)}.                                                                         

#show plays/3.                                                                                                         

%%% shortcut if too many decks are used, each player can only play 4 times but at least 3 players have to play in a room (currently there is no conecpt of an empty room)
:- 3*nRooms*nDecks > nPlayers*4. 

请注意,我添加了最后一个约束,因为您的初始配置无法解决(每个玩家必须玩 4 轮,我们有 20 名玩家,这是 80 个人游戏。假设至少 3 名玩家必须在一个房间里,并且我们有 4 个房间和 7 个甲板这是 3 * 4 * 7 = 84,我们至少需要玩 84 场个人游戏)。您可能还可以计算我认为的甲板数量。

于 2021-05-15T08:24:21.980 回答