我正在努力扩展约束问题(它会因大值和/或如果我尝试优化而不是仅仅寻找任何解决方案而崩溃)。根据之前一些问题的建议,我已经采取了一些步骤来分解搜索空间,但它仍然停滞不前。还有其他技术可以帮助我优化此计算吗?
%%% 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,每个甲板在在场的每个人眼中都被认为是“一轮” . 据我了解,这是关于设置的最令人困惑的一点,我一开始没有很好地澄清。