Code Golf Asked on October 27, 2021
Dungeon Master was one of the first ever real-time role-playing games, originally released in 1987 on the Atari ST. Among other exciting things for the time, it offered a rather sophisticated spell system based on runes.
Your task today is to write a program or function that evaluates the number of Mana points required to cast a given spell in Dungeon Master.
The ‘spell cast’ system is the top right cyan box in the above picture.
Dungeon Master spells are composed of 2 to 4 runes, picked among the following categories, in this exact order:
It means that valid spells are either:
Each category contains 6 runes, and each rune has an associated base Mana cost:
=============================================================================
| Power | Rune | Lo | Um | On | Ee | Pal | Mon |
| +-----------+------+------+------+------+------+------+
| | Base cost | 1 | 2 | 3 | 4 | 5 | 6 |
=============================================================================
| Elemental Influence | Rune | Ya | Vi | Oh | Ful | Des | Zo |
| +-----------+------+------+------+------+------+------+
| | Base cost | 2 | 3 | 4 | 5 | 6 | 7 |
=============================================================================
| Form | Rune | Ven | Ew | Kath | Ir | Bro | Gor |
| +-----------+------+------+------+------+------+------+
| | Base cost | 4 | 5 | 6 | 7 | 7 | 9 |
=============================================================================
| Class / Alignment | Rune | Ku | Ros | Dain | Neta | Ra | Sar |
| +-----------+------+------+------+------+------+------+
| | Base cost | 2 | 2 | 3 | 4 | 6 | 7 |
=============================================================================
The Mana cost of the spell is the sum of the Mana cost of all runes:
The cost of the Power rune always equals its base cost (from 1 to 6).
For the other runes, the following formula applies:
where power is the base cost of the Power rune.
Spell: Lo Ful
Cost : 1 + floor((1 + 1) * 5 / 2) = 1 + 5 = 6
Spell: Um Ful
Cost : 2 + floor((2 + 1) * 5 / 2) = 2 + 7 = 9
Spell: Pal Vi Bro
Cost : 5 + floor((5 + 1) * 3 / 2) + floor((5 + 1) * 7 / 2) = 5 + 9 + 21 = 35
['Lo', 'Ful']
), or just one string with a single-character separator of your choice (e.g. 'Lo Ful'
). Please specify the selected input format in your answer.'Ful'
) 2. All lower case ('ful'
) 3. All upper case ('FUL'
). But you can’t mix different formats.Spell | Output
---------------+-------
Lo Ful | 6
Um Ful | 9
On Ya | 7
Lo Zo Ven | 12
Pal Vi Bro | 35
Ee Ya Bro Ros | 31
On Ful Bro Ku | 31
Lo Zo Kath Ra | 20
On Oh Ew Sar | 35
Ee Oh Gor Dain | 43
Mon Zo Ir Neta | 68
Mon Des Ir Sar | 75
,.Ajax,.Ford,.Page,.Puck,.Romeo,.Act I:.Scene I:.[Enter Romeo and Page]Page:You big big big big big big cat.[Exit Romeo][Enter Ajax]Page:Open thy mind!Ajax:Open thy mind!Open thy mind!You is the sum of Romeo and the sum of a big big cat and a cat.Am I as big as you?If not,let us return to Scene V.Page:You is the sum of a big big cat and a cat.Let us return to Act V.Scene V:.Ajax:You is the sum of you and the sum of a big big big cat and a pig.Am I as big as you?If not,let us return to Scene X.Page:You big cat.Let us return to Act V.Scene X:.Ajax:You is the sum of you and the sum of a big cat and a cat.Am I as big as you?If not,let us return to Scene L.Page:You big big cat.Let us return to Act V.Scene L:.Ajax:You is the sum of you and the sum of a big big cat and a big cat.Am I as big as you?If not,let us return to Scene C.Page:You is the sum of a big cat and a cat.Let us return to Act V.Scene C:.Ajax:Am I as big as the sum of you and a big big big pig?Page:You is the sum of a big big cat and a big cat.If so,you is the sum of you and a cat.Ajax:Open thy mind!Act V:.Scene I:.[Exit Ajax][Enter Ford]Page:Open thy mind!Ford:Open thy mind!Open thy mind!You is the sum of Romeo and the sum of a big big big big cat and a pig.Am I as big as you?If not,let us return to Scene V.Page:You big big cat.Let us return to Act X.Scene V:.Ford:You is the sum of you and the sum of a big big big cat and a pig.Am I as big as you?If not,let us return to Scene X.Page:You is the sum of a big cat and a cat.Let us return to Act X.Scene X:.Ford:You is the sum of you and a big big cat.Am I as big as you?If not,let us return to Scene L.Page:You is the sum of a big big big cat and a pig.Let us return to Act X.Scene L:.Ford:Am I as big as the sum of you and a pig?If not,let us return to Scene C.Page:You big cat.Let us return to Act X.Scene C:.Ford:Am I as big as the sum of Romeo and a big big cat?Page:You is the sum of a big big cat and a cat.If so,you is the sum of you and a cat.Ford:Open thy mind!Act X:.Scene I:.[Exit Page][Enter Puck]Ford:You is the sum of the sum of Ajax and a pig and the quotient between the product of Ajax and I and a big cat.Puck:Open thy mind!Is you as big as a pig?If so,let us return to Act D.[Exit Puck][Enter Page]Ford:Open thy mind!Open thy mind!You is the sum of Romeo and the sum of a big big cat and a cat.Am I as big as you?If not,let us return to Scene V.Page:You is the sum of a big big cat and a cat.Let us return to Act L.Scene V:.Ford:Am I as big as the sum of you and a big big cat?If not,let us return to Scene X.Page:You is the sum of a big big big cat and a pig.Let us return to Act L.Scene X:.Ford:Open thy mind!Am I as big as the sum of Romeo and a big cat?If not,let us return to Scene L.Page:You is the sum of a big big big cat and a pig.Let us return to Act L.Scene L:.Ford:You is the sum of Romeo and the sum of a big big big cat and a pig.Am I as big as you?If not,let us return to Scene C.Page:You is the sum of a big big big cat and a cat.Let us return to Act L.Scene C:.Ford:Am I as big as the sum of you and a big big cat?If so,let us return to Scene D.Page:You big big cat.Let us return to Act L.Scene D:.Page:Open thy mind!You is the sum of a big big cat and a big cat.Act L:.Scene I:.[Exit Page][Enter Puck]Ford:You is the sum of you and the quotient between the product of Ajax and I and a big cat.Puck:Open thy mind!Is you as big as a pig?If so,let us return to Act D.[Exit Puck][Enter Page]Ford:You is the sum of Romeo and a big big cat.Am I as big as you?If not,let us return to Scene V.Page:You is the sum of a big cat and a cat.Let us return to Act C.Scene V:.Ford:You is the sum of you and the sum of a big big big cat and a pig.Am I as big as you?If not,let us return to Scene X.Page:You big cat.Let us return to Act C.Scene X:.Ford:Am I as big as the sum of you and the sum of a big cat and a cat?If not,let us return to Scene L.Page:You big big cat.Let us return to Act C.Scene L:.Ford:Am I as big as the sum of you and a big big big cat?If not,let us return to Scene C.Page:You is the sum of a big big big cat and a pig.Let us return to Act C.Scene C:.Page:Open thy mind!Is you as big as the sum of Romeo and a cat?You big cat.If so,you is the sum of you and a big big cat.Act C:.Scene I:.[Exit Page][Enter Puck]Ford:You is the sum of you and the quotient between the product of Ajax and I and a big cat.Act D:.Scene I:.Ford:Open thy heart![Exeunt]
Takes the input as an uppercase string.
Explanation coming soon... For now, Fun fact: Microsoft
is a negative noun in SPL. All other accepted words appeared in the works of Shakespeare.
Answered by NieDzejkob on October 27, 2021
Using ADTs instead of numerical voodoo.
NOTE: Add 36 for {-# LANGUAGE GADTs,ViewPatterns #-}
-XGADTs -XViewPatterns
data P=Lo|Um|On|Ee|Pal|Mon deriving(Enum,Read,Eq)
data E=Ya|Vi|Oh|Ful|Des|Zo deriving(Enum,Read,Eq)
data F=Ven|Ew|Kath|Ir|Bro|Gor deriving(Enum,Read,Eq)
data C=Ku|Ros|Dain|Neta|Ra|Sar deriving(Enum,Read,Eq)
data S where
S::P->E->S
Q::P->E->F->S
R::P->E->F->C->S
k(a:b:x)=let{p=read a;e=read b}in case x of{[]->S p e;[c]->Q p e(read c);[c,d]->R p e(read c)(read d)}
c,d::Enum a=>a->Int
c=succ.fromEnum
d=(+2).fromEnum
e Bro=7
e x=(+2).d$x
f x|c x`elem`[1,5,6]=d x|2>1=c x
g p f x =(`div`2).(*f x).succ$c p
h(S x y)=c x+g x d y
h(Q x y z)=h(S x y)+g x e z
h(R x y z t)=h(Q x y z)+g x f t
main=print.h.k.words=<<getLine
Input: a single spell as a normal string
e.g.
Lo Ful
Um Ful
Multilining can be done by replacing the last line with
main=interact$unlines.map(show.h.k.words).lines
But this would add bytes to the count
Answered by archaephyrryx on October 27, 2021
k(p:y)=sum$floor<$>c p:map(x->c x*(c p+1)/2)y
c s=read["3764529516342767"!!(foldl(c n->c*94+fromEnum n-9)0s%7086%17)]
(%)=mod
Answered by bartavelle on October 27, 2021
func c(s []string)int{f,l:=strings.IndexByte,len(s)
p:=f("UOEPM",s[0][0])+3
r:=p-1+p*(f("VOFDZ",s[1][0])+3)/2
if l>2{r+=p*(f("war o",s[2][1])+5)/2}
if l>3{r+=p*(f("it Ra",s[3][len(s[3])-2])+3)/2}
return r}
It's a callable function, takes runes as a slice of strings, e.g. []string{"Um", "Ful"}
.
Try it on the Go Playground.
Answered by icza on October 27, 2021
Thanks to @ceilingcat for some very nice pieces of golfing - now even shorter
i;b(r,s)char*r;{for(i=17;i--&&"& ; $ # 4 % ; B * 6 $ 8 6 5 - >3 + A@( . 6 5 "[s+i]-3-(*r^r[1]););return~i?i/2+1:0;}main(n,r)int**r;{n=b(*++r,0);printf("%dn",n-(b(r[1],17)+b(r[2],34)+b(r[3],51))*~n/2);}
A more ungolfed version of my original answer:
#include<stdio.h>
char*a="& ; $ # 4 % "
" ; B * 6 $ 8 "
" 6 5 - >3 +"
" A@( . 6 5 ";
int b(char*r,int s){
for(int i=0;i<17;i++)
if(a[i+s]-3==(r[0]^r[1]))
return i/2+1;
return 0;
}
#define c(p,r,i)(p+1)*b(r[i+1],i*17)/2
int main(int n,char**r){
int x=b(r[1],0);
printf("%dn",x+c(x,r,1)+c(x,r,2)+c(x,r,3));
}
You need to supply four command line arguments - so for the first test case you need to run ./a.out Lo Ful "" ""
Answered by Jerry Jeremiah on October 27, 2021
Gor
9
[ZIBS]w+
7
Mon|Des|Kath|Ra
6
..l|Ew
5
Ee|Oh|Ven|Neta
4
[OVD]w+
3
[UYKR]w+
2
Lo
1
d
$*
(?<=^(1+) .*1)
$1
G1
11
11
Try it online! Link includes test cases. Takes space-separated runes. Explanation: The initial stages simply convert each rune to a digit, which is then converted to unary. The numbers after the first are multiplied by one more than the first number, following which the first number is doubled. The final stage integer divides all the result by 2 and takes the sum.
Answered by Neil on October 27, 2021
Inputs entered in A1
through D1
. Formula in any other cell.
=CHOOSE(MOD(CODE(A1),12),2,,,1,6,,3,5,4)+INT((CHOOSE(MOD(CODE(A1),12),2,,,1,6,,3,5,4)+1)*CHOOSE(MOD(CODE(B1),12),,3,,,2,7,4,6,,5)/2)+INT((CHOOSE(MOD(CODE(A1),12),2,,,1,6,,3,5,4)+1)*CHOOSE(MOD(CODE(C1),12),7,4,6,,,7,,,5,,9)/2)+INT((CHOOSE(MOD(CODE(A1),12),2,,,1,6,,3,5,4)+1)*CHOOSE(MOD(CODE(SUBSTITUTE(D1,"Ra","E")),11),4,3,6,,2,7,,,2,0)/2)
Alternatively, importing as CSV:
,,,
=CHOOSE(MOD(CODE(A1),12),2,,,1,6,,3,5,4)+1
=A2-1+INT(A2*CHOOSE(MOD(CODE(B1),12),,3,,,2,7,4,6,,5)/2)+INT(A2*CHOOSE(MOD(CODE(C1),12),7,4,6,,,7,,,5,,9)/2)+INT(A2*CHOOSE(MOD(CODE(SUBSTITUTE(D1,"Ra","E")),11),4,3,6,,2,7,,,2,0)/2)
Input entered in first row, SPACE
for nulls. Result displayed in A3.
Answered by Wernisch on October 27, 2021
r->{int c[][]={{2,3,4,5,6,7},{4,5,6,7,7,9},{2,2,3,4,6,7}},l=r.length,p="LUOEPM".indexOf(r[0].charAt(0))+1,a=p,i=0;String[]s={"YVOFDZ","VEKIBG","KRDNXS"};for(;i<l-1;)a+=(p+1)*c[i][s[i++].indexOf((l>3?r[i].replace("Ra","X"):r[i]).charAt(0))]/2;return a;}
The runes are input as a String[]
(array of String
), in the first case form (first letter is an uppercase, rest is lowercase).
It's the standard "find the n-th letter" method, with the twist that both Ros
and Ra
exist in the 4th segment. I treated that with an inline and explicit replacement of Ra
to X
.
Answered by Olivier Grégoire on October 27, 2021
Takes input as an array of strings.
a=>a.map(c=>t+=(v=+`27169735020045670435262`[parseInt(c,36)%141%83%50%23],+a?a*v+v>>1:a=v),t=0)|t
Hoo, boy, this is gonna be fun - my explanations to trivial solutions suck at the best of times! Let's give it a go ...
a=>
An anonymous function taking the array as an argument via parameter a
.
a.reduce((t,c)=>,0)
Reduce the elements in the array by passing each through a function; the t
parameter is the running total, the c
parameter is the current string and 0
is the initial value of t
.
parseInt(c,36)
Convert the current element from a base 36 string to a decimal integer.
%141%83%50%23
Perform a few modulo operations on it.
+`27169735 2 4567 435262`[]
Grab the character from the string at that index and convert it to a number.
v=
Assign that number to variable v
.
+a?
Check if variable a
is a number. For the first element a
will be the array of strings, trying to convert that to a number will return NaN
, which is falsey. On each subsequent pass, a
will be a positive integer, which is truthy.
a*v+v>>1
If a
is a number then we multiply it by the value of v
, add the value of v
and shift the bits of the result 1 bit to the right, which gives the same result as dividing by 2 and flooring.
:a=v
If a
is not a number the we assign the value of v
to it, which will also give us a 0
to add to our total on the first pass.
t+
Finally, we add the result from the ternary above to our running total.
a=>a.reduce((t,c)=>t+(p+1)*g(c)/2|0,p=(g=e=>+`123456234567456779223467`["LoUmOnEePaMoYaViOhFuDeZoVeEwKaIrBrGoKuRoDaNeRaSa".search(e[0]+e[1])/2])(a.shift()))
Answered by Shaggy on October 27, 2021
.•Y<εΔ•¹нk©.•M₄P畲нkÌ.•Jrû •³нkD(ië4 3‡4+}.•A1Δ#•I4èkD(ië3LJ012‡Ì})ćsv®>y*;(î(+
-1 thanks to Emigna.
SOOOOOOO ungolfed :(
Explanation:
.•Y<εΔ•¹нk©.•M₄P畲нkÌ.•Jrû •³нkD(ië4 3‡4+}.•A1Δ#•I4èkD(ië3LJ012‡Ì})ćsv®>y*;(î(+ Accepts four runes as separate lines, lowercase. Use Ø for missing runes.
.•Y<εΔ•¹нk© Index first letter of first rune into "aluoepm" ("a" makes 1-indexed)
.•M₄P畲нkÌ Index first letter of second rune into "yvofdz", 2-indexed.
.•Jrû •³нkD(ië4 3‡4+} Index first letter of third rune into "vekibg", 0-indexed, if it's not there pop, else, if index is 4 replace with 3, else keep as-is, then increment by 4.
.•A1Δ#•I4èkD(ië3LJ012‡Ì} Index fourth letter (modular wrapping) of fourth rune into "kodnra", if it's not there pop, else, if index is one of 1, 2 or 3, replace with 0, 1 or 2 respectively, else keep as-is, then increment by 2.
)ćs Wrap all numbers into a list, keeping the power rune behind.
v For each
®>y*;(î( Apply the formula
+ Add to total sum
Answered by Erik the Outgolfer on October 27, 2021
θKKι"LUOEPM”;W:A≤{B"⁶Μ↓§QΕņj“L─"¶Ζq«╝γDyΜ2¶S◄Μ$‘č¹I6nēwι{_Cb:ƧRA=┌*ΚKι=?aIc*»+
Could probably golf a byte or two from redoing everything
Explanation:
θ split on spaces
K pop the 1st item
K pop from the string the 1st character
ι remove the original string from stack
"”;W get the chars index in "LUOEPM"
:A save a copy to variable A
≤ put the power (used as the mana) on the bottom of the stack (with the thing above being the input array)
{ for the leftover items in the input do
B save the current name on B
"..“ push 456779223467234567
L─ base-10 decode it (yes, silly, but it converts it to an array of digits)
".‘ push "VEKIBGKRDN-SYVOFDZ"
č chop to characters
¹ create an array of those two
I rotate clockwise
6n group to an array with sub-arrays of length 6 (so each array in the array contains 3 items, corresponding to the categories, each with 6 arrays with the runes 1st letter (or "-" in the case of Ra) and base cost)
ē push variable e (default = user input number, which errors and defaults to 0) and after that increase it (aka `e++`)
w get that item in the array (the array is 1-indexed and the variable is not, so the array was created shifted (which somehow saves 0.9 ≈ 1 byte in the compression))
ι remove the original array
{ for each in that (current category) array
_ dump all contents on stack (so pushing the runes name and then base cost)
C save pop (base cost) on variable B
b: duplicate the name
ƧRA= push if pop = "RA"
┌* get that many (so 0 or 1) dashes
Κ prepend the "" or "-" to the name
K pop the 1st letter of the name
ι remove the modified name, leaving the 1st letter on the stack
=? if top 2 are equal (one of the dumped items and the 1st letter of the current inputs)
a push variable A (the power)
I increase it
c push variable C (the current base cost)
* multiply
» floor-divide by 2
+ add that to the power
Answered by dzaima on October 27, 2021
This is quite long, probably optimizable, but it was fun to do :)
Input format : space-separated runes in a string. If there is only 2 inputs (like "Lo Ful") my code completes it with while(k.length<4)k:+=""
(so I can save 24 bytes by changing the parameters, if I require it to be "A B C D").
def n(i:Int,p:String):Int={Math.floor(i*((""+p(0)).toInt+1)/2).toInt}
def m(s:String):Int={var k=s.split(' ')
while(k.length<4)k:+=""
k match{case Array(p,i,f,a)=>{p match{case "Lo"=>1+m(1+"/ "+i+" "+f+" "+a)
case "Um"=>2+m(2+"/ "+i+" "+f+" "+a)
case "On"=>3+m(3+"/ "+i+" "+f+" "+a)
case "Ee"=>4+m(4+"/ "+i+" "+f+" "+a)
case "Pal"=>5+m(5+"/ "+i+" "+f+" "+a)
case "Mon"=>6+m(6+"/ "+i+" "+f+" "+a)
case _ if p.contains("/")=>i match{case "Ya"=>n(2,p)+m(p+" / "+f+" "+a)
case "Vi"=>n(3,p)+m(p+" / "+f+" "+a)
case "Oh"=>n(4,p)+m(p+" / "+f+" "+a)
case "Ful"=>n(5,p)+m(p+" / "+f+" "+a)
case "Des"=>n(6,p)+m(p+" / "+f+" "+a)
case "Zo"=>n(7,p)+m(p+" / "+f+" "+a)
case _ if p.contains("/")=>f match{case "Ven"=>n(4,p)+m(p+" / "+"/ "+a)
case "Ew"=>n(5,p)+m(p+" / "+"/ "+a)
case "Kath"=>n(6,p)+m(p+" / "+"/ "+a)
case "Ir"=>n(7,p)+m(p+" / "+"/ "+a)
case "Bro"=>n(7,p)+m(p+" / "+"/ "+a)
case "Gor"=>n(9,p)+m(p+" / "+"/ "+a)
case _ if p.contains("/")=>a match{case "Ku"=>n(2,p)
case "Ros"=>n(2,p)
case "Dain"=>n(3,p)
case "Neta"=>n(4,p)
case "Ra"=>n(6,p)
case "Sar"=>n(7,p)
case _=>0}
case _=>0}
case _=>0}
case _=>0}}}}
Thanks for this superb challenge. Try it online!
Answered by V. Courtois on October 27, 2021
b=[int('27169735 2 4567 435262'[int(x,36)%141%83%50%23])for x in input()]
print b[0]+sum(a*-~b[0]/2for a in b[1:])
Input is list of strings from stdin
Answered by ovs on October 27, 2021
Input Format - List of Strings. Full program:
i=input()
t=[x.split()for x in"Lo Um On Ee Pal Mon|Ya Vi Oh Ful Des Zo|Ven Ew Kath Ir Bro Gor|Ku Ros Dain Neta Ra Sar".split('|')]
c=t[0].index(i[0])+1;r=c+1;s=c+r*(t[1].index(i[1])+2)/2
if len(i)>2:s+=r*(t[2].index(i[2])+4-(i[2]=='Bro'))/2
if len(i)>3:s+=r*(t[3].index(i[3])+1+(i[3]in'KuRaSar'))/2
print(s)
Answered by Mr. Xcoder on October 27, 2021
Straight-forward searching algorithm, the search strings are just contributing to the total bytes.
Code
s=>eval('p=q=+(e=s.map(r=>"1 2 3 4 5 6 2 3 4 5 6 7 4 5 6 7 7 9 2 2 3 4 6 7"["LoUmOnEePalMonYaViOhFulDesZoVenEwKathIrBroGorKuRosDainNetaRaSar".search(r)])).shift();e.map(c=>p+=((q+1)*c)>>1);p')
Input Format
String array, each item is a first-letter-capitalized string. Example: ["Mon", "Zo", "Ir", "Neta"]
Explanation
e=s.map(r=>"1 2 3 4 5 6 2 3 4 5 6 7 4 5 6 7 7 9 2 2 3 4 6 7"["LoUmOnEePalMonYaViOhFulDesZoVenEwKathIrBroGorKuRosDainNetaRaSar".search(r)])
This queries for the basic costs.
p=q=+(/*blah*/).shift()
Initializes 2 variables with the first item from the array result above, and remove that item. Must be cast to number first, otherwise it will be considered as string concatenation in the next part.
e.map(c=>p+=((q+1)*c)>>1);
Adds the costs of the non-power runes to the base power. Shifting is used instead of floor(blah)/2.
eval(/*blah*/;p)
Evaluate the last result. (Credit: Step Hen)
Test Cases
Lo Ful | 6
Um Ful | 9
On Ya | 7
Lo Zo Ven | 12
Pal Vi Bro | 35
Ee Ya Bro Ros | 31
On Ful Bro Ku | 31
Lo Zo Kath Ra | 20
On Oh Ew Sar | 35
Ee Oh Gor Dain | 43
Mon Zo Ir Neta | 68
Mon Des Ir Sar | 75
Edit 1: 212 > 210 - Removed a pair of braces
Edit 2: 210 > 207 - Thanks Step Hen for reminder on JS rules and some hint on using eval() function. Since AS3 forbids the use of eval() I haven't use that for long time
Edit 3: 207 > 206 - Thanks Shaggy for the idea replacing indexOf() with search()
Answered by Shieru Asakoto on October 27, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP