Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Best Method to Make a Quiz

A topic by Salty P. Slug created 91 days ago Views: 518 Replies: 14
Viewing posts 1 to 6
(1 edit) (+3)

Hello all,

I am embarking on a journey to make a little personality quiz within Decker. The premise of the quiz is, “what legendary 2000s skateboarding video are you?”

I want to present the user with an odd-number of questions, let’s say a total of 5 for theoretical purposes. Preferably, I would like the questions to exist on their own separate cards rather than mashed into one. Each potential result of the quiz would have a corresponding answer in each question, but obviously I would need to track which one was chosen the MOST out of the questions. After they answer the questions, the logic should spit out the video result corresponding to that weighted variable.

What would be the best type of logic/widgets to use for this, or is there a module I could bend to do this easier?

My apologies, I don’t have much of a programming background. I am good with laying out the logic in my head, but I have a hard time getting it on the proverbial page.

(+4)

So basically you'd want to have counters for each result tracking each time they're picked - so like starting them all at 0 and then adding 1 each time the answer is picked. I like to use sliders for storing numeric values with a constrained range - since you know the maximum value possible is 5 as there's only 5 questions in the hypothetical you'd just need a range from 0 to 5.  You can put the sliders on a hidden card that the player won't ever see. Then let's say you have a button for each answer on a card and and you can put something like this in the "on click"

cardwithsliders.widgets.slider1.value: cardwithsliders.widgets.slider1.value + 1
go["question2"]

And then at the end you'd just need to check which slider has the highest value and go to an appropriate ending page. There may be a smarter way to do this but it's early here so I'd just go with like a bunch of if statements.

if (cardwithsliders.widgets.slider1.value > cardwithsliders.widgets.slider2.value) & 
   (cardwithsliders.widgets.slider1.value > cardwithsliders.widgets.slider3.value) &
   (cardwithsliders.widgets.slider1.value > cardwithsliders.widgets.slider4.value)
 go["ending1"]
elseif #all the other ways around
end

(apologies if any of my code is wonky, I'm just writing this off the top of my head haha)

You may not have much of a programming background but dabbling in stuff like this is a great way to learn! If you can work out the logic in a "do this then do that" and "if this then we do this, otherwise we do that" then it's just a matter of translating it into the syntax you need

Developer(+5)

Supposing you have several sliders on a card:


The easiest way to find the slider with the highest value would be to write a query which sorts the sliders by value (descending) and then extract their names:

extract value..name orderby value..value desc from likesDogs,likesCats,likesFish,likesChickens

In the above example, this would yield a list of widget names like so:

("likesChickens","likesDogs","likesFish","likesCats")

The "first" of such a list would be the highest-ranked (with ties naturally broken in order of appearance).

(+3)

Thank you both for the reply. I honestly was completely defeated by these responses and felt way in over my head with the programming, but I’m going to try again with your feedback.

Developer(+2)

If you find yourself struggling to apply these ideas, let us know what you've tried and I can create a more complete example for you to study and tinker with. There are a fair number of concepts at play, but you don't need to learn everything at once. :)

(1 edit) (+1)

I’ve actually had the structure in place for some time. I have each question on a separate card, a counter card with the sliders that count up based on the answers, as well as a button (btnResult) on the final question that (on click) runs the query you recommended.

The problem is, I don’t really know how to finalize it. How would I take the highest value returned by clicking the button and use that result to navigate to the intended “quiz result” card?

Developer(+2)

You could make a dictionary that maps slider names to result cards and "go[]" to the card corresponding to the top-ranked result:

on click do
 sliders:likesDogs,likesCats,likesFish,likesChickens
 order:extract value..name orderby value..value desc from sliders
 results.likesDogs:"TheDogCard"
 results.likesCats:"TheCatCard"
 results.likesFish:"TheFishCard"
 results.likesChickens:"TheChickensCard"
 go[results[first order]]
end

If your quiz result cards are named to correspond to the sliders, you could skip the dictionary and "go[]" to a card by name:

on click do
 sliders:likesDogs,likesCats,likesFish,likesChickens
 order:extract value..name orderby value..value desc from sliders
 go[first order]
end

(Using consistent naming conventions for cards and widgets can often make scripts a good bit simpler!)

If the sliders aren't on the same card as the result-calculating button, you'll need to reference them through their container card. Say the card with the counters is named "counters":

on click do
 sliders:counters.widgets.likesDogs,
         counters.widgets.likesCats,
         counters.widgets.likesFish,
         counters.widgets.likesChickens
 order:extract value..name orderby value..value desc from sliders
 go[first order]
end

Or- more concisely-

on click do
 sliders:counters.widgets @ "likesDogs","likesCats","likesFish","likesChickens"
 order:extract value..name orderby value..value desc from sliders
 go[first order]
end

Or, if the sliders are the only widgets on that card:

on click do
 sliders:range counters.widgets
 order:extract value..name orderby value..value desc from sliders
 go[first order]
end

Does that help at all?

(1 edit) (+3)

Oh my god, thank you! That first one is exactly what I needed. I was missing the “results” part of each line but had figured the rest out. I really appreciate your help; the documentation for the coding language is great, it’s just very overwhelming to me for whatever reason.

I will try these solutions tonight and report back.

(+3)

I really like the slider suggestion. A nice thing about it is that you can go to that card and manipulate the sliders yourself to test your logic, or hop over while going through your quiz to see that the sliders are as you expect.

Here's a card. If you copy this and paste it into a deck, it'll add a new card with three sliders, a personality field, and a grid of tests and results:

%%CRD0{"c":{"name":"home","script":"on quiz do\n on f t do eval[t (\"cat\",\"dog\",\"duck\") dict (cat,dog,duck)..value] end\n p:first extract result where (f@test)..value from logic.value\n personality.text:\"\" fuse \"You \", p\nend","widgets":{"cat":{"type":"slider","size":[100,25],"pos":[80,32],"script":"on change val do\n quiz[]\nend","interval":[0,5],"format":"cat: %f","style":"bar"},"dog":{"type":"slider","size":[100,25],"pos":[80,64],"script":"on change val do\n quiz[]\nend","interval":[0,5],"format":"dog: %f","style":"bar"},"duck":{"type":"slider","size":[100,25],"pos":[80,96],"script":"on change val do\n quiz[]\nend","interval":[0,5],"format":"duck: %f","style":"bar"},"personality":{"type":"field","size":[192,16],"pos":[224,64],"value":"You are an animal hater?!"},"logic":{"type":"grid","size":[448,160],"pos":[32,160],"bycell":1,"format":"ss","value":{"test":["0=cat+dog+duck","(0,0,1)~0=cat,dog,duck","(0,1,0)~0=cat,dog,duck","(0,1,1)~0=cat,dog,duck","(1,0,0)~0=cat,dog,duck","(1,0,1)~0=cat,dog,duck","(1,1,0)~0=cat,dog,duck","15=cat+dog+duck","1"],"result":["are an animal hater?!","only like mammals","only dislike dogs","only like cats","only dislike cats","only like dogs","only like ducks","are a true friend to all creatures","have unexpected tastes! Sorry!"]},"row":6,"col":1}}},"d":{}}

Room for improvement: if you like all the animals just a little, like 1,1,1, then the personality is "You have unexpected tastes! Sorry!". Also, if you change the logic table so that three different tests all pass, then you still only get the first result. You could check the number and do something about ambiguous results like that.

Or, maybe that quiz code is too clever. Here's something else that still uses that logic grid:

on quiz do
 vars.cat:cat.value
 vars.dog:dog.value
 vars.duck:duck.value
 i:0
 while i < count logic.value
  test:logic.value[i].test
  if eval[test vars].value then
   personality.text:"" fuse "You ", logic.value[i].result
   i:count logic.value # stop here
  end
  i:i+1
 end
end

And, here's a totally different way to do it:

%%CRD0{"c":{"name":"card1","script":"on quiz do\n personality.text:\"You have unexpected tastes! Sorry!\"\n (extract value where \"button\"=typeof@value from card.widgets)..event[\"click\"]\nend","widgets":{"cat":{"type":"slider","size":[100,25],"pos":[80,32],"script":"on change val do\n quiz[]\nend","interval":[0,5],"format":"cat: %f","style":"bar"},"dog":{"type":"slider","size":[100,25],"pos":[80,64],"script":"on change val do\n quiz[]\nend","interval":[0,5],"format":"dog: %f","style":"bar"},"duck":{"type":"slider","size":[100,25],"pos":[80,96],"script":"on change val do\n quiz[]\nend","interval":[0,5],"value":5,"format":"duck: %f","style":"bar"},"personality":{"type":"field","size":[192,16],"pos":[224,64],"value":"You only like ducks"},"button1":{"type":"button","size":[96,32],"pos":[32,160],"script":"on click do\n if me.value:0=sum (cat,dog,duck)..value then\n  personality.text:\"You're an animal hater?!\"\n end\nend","text":"likes none","style":"check","value":0},"button2":{"type":"button","size":[96,32],"pos":[144,160],"script":"on click do\n if me.value:(1,0,0)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only like cats\"\n end\nend","text":"only cats","style":"check","value":0},"button3":{"type":"button","size":[96,32],"pos":[32,208],"script":"on click do\n if me.value:15=sum (cat,dog,duck)..value then\n  personality.text:\"You're a true friend to all creatures\"\n end\nend","text":"loves all","style":"check","value":0},"button4":{"type":"button","size":[96,32],"pos":[144,208],"script":"on click do\n if me.value:(0,1,0)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only like dogs\"\n end\nend","text":"only dogs","style":"check","value":0},"button5":{"type":"button","size":[96,32],"pos":[144,256],"script":"on click do\n if me.value:(0,0,1)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only like ducks\"\n end\nend","text":"only ducks","style":"check","value":1},"button6":{"type":"button","size":[96,32],"pos":[256,160],"script":"on click do\n if me.value:(0,1,1)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only dislike cats\"\n end\nend","text":"all but cats","style":"check","value":0},"button7":{"type":"button","size":[96,32],"pos":[256,208],"script":"on click do\n if me.value:(1,0,1)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only dislike dogs\"\n end\nend","text":"all but dogs","style":"check","value":0},"button8":{"type":"button","size":[96,32],"pos":[256,256],"script":"on click do\n if me.value:(1,1,0)~((cat,dog,duck)..value)>0 then\n  personality.text:\"You only like mammals\"\n end\nend","text":"all but ducks","style":"check","value":0}}},"d":{}}

This has the same sliders and personality field, but the 'quiz' just clicks every button on the card. Each button is a checkbox that sets itself to the value of a test and sets the personality if that value is true. This method makes the logic a little harder to see, as it's in each individual button, but when messing with sliders you can directly see what tests succeed or not, and with meaningful button names you could have other cards perform logic based on what's checked so far in the quiz

Thank you so much. These have been most helpful to me, as I’m a “see something already implemented and then tweak” kindof learner.

I got nothing for you code-wise but if CKY2k isn’t on that list, I’m spending the rest of 2025 trying to cancel you.

It’s not, but Baker 3 is :P

(+2)

There's a "what job are you" quiz in RevInc, and the deck isn't locked, so you can plunder that for ideas if you like: https://annarcana.itch.io/revolution-inc

The short version is I just have a bunch of question widgets, and then a script in the "Calculate!" button polls all those widgets to generate a score for each job based on some simple math. 

(+1)

Thank you! I am very much a “learn by scouring a pre-existing thing” person so this is so helpful to me. I hope I can figure it out this time around.

Developer(+4)

I did some pondering and tried to come up with an approach that minimizes the amount of scripting needed:

http://beyondloom.com/decker/goofs/petquiz.html

The structure of the deck is as follows:


  • Question cards are named with a "q_" prefix.
  • Quiz results each have their own sensibly-named card.
  • The options on question cards are each a checkbox whose name corresponds to the name of one of the result cards.
  • The checkboxes can appear in different orders on each question cards, and not all possible results must be present.
  • The checkboxes on question cards are marked as volatile, so that they can all be reset with "deck.purge[]", as a convenience.
  • Clicking a checkbox simply advances to the next card. Since they all have the same behavior, we can put the following in the card script for each question (or, if we're feeling feisty, we could even define it once in the deck-level script):
on click do
 go["Next"]
end

When we get to the last card of the quiz, the user clicks a button to discover their result. The script there will find all the question cards based on the "q_" naming convention, look at all their checkboxes, and count up the number of checks for a given result name. The name which had the most checks will be the name of our result card:

on click do
 cards:extract value where value..name like "q_*" from deck.cards
 counts:sum each card in cards
  raze select key value..value where value..type="button" from card.widgets
 end
 go[first extract key orderby value desc from counts]
end

This is probably a bit daunting. Using the Listener, we can break this script down step-by-step; assume we're on the card "decide" and we've already filled out our quiz responses.

Find the question cards:

cards:extract value where value..name like "q_*" from deck.cards
# (<card>,<card>,<card>)

For now, consider only the first card. Find the button widgets and form a table from their names ("key") and checked status ("value..value"):

select key value..value where value..type="button" from cards[0].widgets
# +-----------+-------+
# | key       | value |
# +-----------+-------+
# | "chicken" | 1     |
# | "fish"    | 0     |
# | "dog"     | 0     |
# | "cat"     | 0     |
# +-----------+-------+

Razing a table forms a dictionary mapping its first column to its second column:

raze select key value..value where value..type="button" from cards[0].widgets
# {"chicken":1,"fish":0,"dog":0,"cat":0}

We'll need to do this process for each card, not just the first one:

each card in cards
 raze select key value..value where value..type="button" from card.widgets
end
# ({"chicken":1,"fish":0,"dog":0,"cat":0},{"fish":0,"cat":1,"chicken":0,"dog":0},{"dog":0,"chicken":1,"cat":0,"fish":0})

If we sum a list of dictionaries, we'll get a dictionary with the union of the keys in each dictionary and the sum of all the corresponding values:

counts:sum each card in cards
 raze select key value..value where value..type="button" from card.widgets
end
# {"chicken":2,"fish":0,"dog":0,"cat":1}

To find the key with the largest value, we'll sort the keys by the values (descending):

extract key orderby value desc from counts
# ("chicken","cat","fish","dog")

The first element of that list is our answer:

first extract key orderby value desc from counts
# "chicken"

So we can go[] to the corresponding card by name:

go[first extract key orderby value desc from counts]

This query doesn't care about how many results exist, how many questions are in the quiz, or how many answers are available for each question; you can easily add to the quiz or make an entirely different quiz without modifying the query.

(Note: this quiz won't work right if your checkboxes are named inconsistently. If you seem to get goofy results, you can try the above step-by-step in the Listener to see if you get any unexpected options in this result list!)

Does that make sense?