% % A program to solve the logic puzzle from % https://www.ahapuzzles.com/logic/zebra/epic-rpg-adventure/ % % Author: Joachim Schimpf, 2024 % Creative Commons Attribution 4.0 International License. % % ?- go. % character(ember, orange, gnome, dagger, plant, stealth) % character(riven, yellow, giant, wand, humanoid, wisdom) % character(jade, blue, orc, bow, dragon, intelligence) % character(solstice, pink, troll, spear, fey, charisma) % character(horizon, red, dwarf, hammer, beast, dexterity) % Yes (0.00s cpu, solution 1, maybe more) % No (0.01s cpu) % :- lib(ic_symbolic). :- lib(ic). :- import alldifferent/1, element/3, indomain/1 from ic_symbolic. :- local domain(names(ember,horizon,jade,riven,solstice)), domain(armor(blue,orange,pink,red,yellow)), domain(race(dwarf,giant,gnome,orc,troll)), domain(weapon(bow,dagger,hammer,spear,wand)), domain(monster(beast,dragon,fey,humanoid,plant)), domain(ability(charisma,dexterity,intelligence,stealth,wisdom)). go :- N = 5, length(Name, N), Name &:: names, alldifferent(Name), length(Armor, N), Armor &:: armor, alldifferent(Armor), length(Race, N), Race &:: race, alldifferent(Race), length(Weapon, N), Weapon &:: weapon, alldifferent(Weapon), length(Monster, N), Monster &:: monster, alldifferent(Monster), length(Ability, N), Ability &:: ability, alldifferent(Ability), % Solstice is the one wearing Pink Ability. % Solstice has the trait that is Charisma. % Solstice is a Troll. same_pos([Name:solstice, Armor:pink, Ability:charisma, Race:troll]), % The character wielding a Hammer has Dexterity. same_pos([Weapon:hammer, Ability:dexterity]), % The Red armored character is also wielding a Hammer. same_pos([Armor:red, Weapon:hammer]), % Jade is wielding a Bow. same_pos([Name:jade, Weapon:bow]), % The Pink armored character is also fighting a Fey. same_pos([Armor:pink, Monster:fey]), % The Pink armored character is somewhere to the left of the character fighting a Beast. element(PinkPos, Armor, pink), element(BeastPos, Monster, beast), PinkPos #< BeastPos, % Riven is wielding a Wand. % Riven is fighting a Humanoid. same_pos([Name:riven, Weapon:wand, Monster:humanoid]), % The character wearing Yellow armor has Wisdom. same_pos([Armor:yellow, Ability:wisdom]), % The player with Intelligence is somewhere between the player wielding a Dagger and the player with Dexterity, in that order. element(IntelPos, Ability, intelligence), element(DaggerPos, Weapon, dagger), element(DextPos, Ability, dexterity), DaggerPos #< IntelPos, IntelPos #< DextPos, % Ember is next to Riven. element(EmberPos, Name, ember), element(RivenPos, Name, riven), EmberPos-RivenPos #= +-1, % Horizon is somewhere to the right of the Orange armored character. element(HorizonPos, Name, horizon), element(OrangePos, Armor, orange), OrangePos #< HorizonPos, % The Gnome has the ability of Stealth. same_pos([Race:gnome, Ability:stealth]), % The Blue armored character is immediately after the character with Wisdom. element(BluePos, Armor, blue), element(WisdomPos, Ability, wisdom), BluePos-WisdomPos #= 1, % The character fighting a Dragon is next to the character wearing Pink armor. element(DragonPos, Monster, dragon), DragonPos-PinkPos #= +-1, % The Giant has Wisdom. same_pos([Race:giant, Ability:wisdom]), % The Archer is somewhere between the character with Wisdom and the one fighting with a Spear, in that order. element(ArcherPos, Weapon, bow), element(WisdomPos, Ability, wisdom), element(SpearPos, Weapon, spear), WisdomPos #< ArcherPos, ArcherPos #< SpearPos, % The character with Wisdom is next to the one fighting a Dragon. WisdomPos-DragonPos #= +-1, % The player wielding a Wand is right before the Orc. element(WandPos, Weapon, wand), element(OrcPos, Race, orc), OrcPos-WandPos #= 1, % Labeling ( foreach(Xs, [Name,Armor,Race,Weapon,Monster,Ability]) >> foreach(X, Xs) do indomain(X) ), % Result ( foreach(N,Name), foreach(C,Armor), foreach(R,Race), foreach(W,Weapon), foreach(M,Monster), foreach(A,Ability) do writeln(character(N,C,R,W,M,A)) ). % An auxiliary convenience predicate, with the meaning % same_pos([Vector_1:Value_1,...,Vector_n:Value_n]) iff % there is an Index such that Vector_i[Index] = Value_i for all i same_pos(VectorsValues) :- ( foreach(Vector:Value,VectorsValues), param(_I) do element(_I, Vector, Value) ).