[SOLVED] (Help needed) Elaborate RNG Puzzle game/sequence.

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
Angelo Seraphim
Regular
Posts: 32
Joined: Tue May 21, 2019 8:00 am
Completed: Enamored Risks (NaNoReNo 2020)
Projects: 616 Charagma
Organization: GLSUoA
Deviantart: glsuoa
itch: glsuoa
Location: London, UK
Discord: Just A Concept#9599
Contact:

[SOLVED] (Help needed) Elaborate RNG Puzzle game/sequence.

#1 Post by Angelo Seraphim » Tue Aug 27, 2019 3:30 pm

Hello everyone!
I've spent several hours trying to condense an old function (since it's very clunky and expensive, but it works fine), but I just want to shorten it.
(This is going to be a long post, so bear with me. I'll do my best to explain it in great detail).

Basically, I have a puzzle sequence game which is very dependent on RNG and the player has to input the correct code that is displayed to them, represented as a string (I'll explain that part. It's very simple.)

The puzzle is like a panel with different buttons that can be interacted with. (See image)
Image
Each button has it's own "variable" (Hmm... Perhaps someone might be able to come up with a better solution, but that may mess with how I've got it all set up and how I want it to play out. :wink: Anyhoo...)

Basic defaults for the buttons:

Code: Select all

default la_switch = 0
default lb_switch = 0
default lc_switch = 0
default ld_switch = 0
default la_1 = 0
default la_2 = 0
default la_3 = 0
default la_4 = 0
default lb_1 = 0
default lb_2 = 0
default lb_3 = 0
default lb_4 = 0
default lc_1 = 0
default lc_2 = 0
default lc_3 = 0
default lc_4 = 0
default ld_1 = 0
default ld_2 = 0
default ld_3 = 0
default ld_4 = 0
default le_switch = 0
default lf_switch = 0
default lg_switch = 0
default lh_switch = 0
default le_1 = 0
default le_2 = 0
default le_3 = 0
default le_4 = 0
default lf_1 = 0
default lf_2 = 0
default lf_3 = 0
default lf_4 = 0
default lg_1 = 0
default lg_2 = 0
default lg_3 = 0
default lg_4 = 0
default lh_1 = 0
default lh_2 = 0
default lh_3 = 0
default lh_4 = 0
And with the help of Remix, he came up with this code (below) that will group these together...

Code: Select all

init python:
    def cmpc_matrix(*mtrx):
        vars_matrix = [
            (la_switch, lb_switch, lc_switch, ld_switch),
            (la_1, la_2, la_3, la_4),
            (lb_1, lb_2, lb_3, lb_4),
            (lc_1, lc_2, lc_3, lc_4),
            (ld_1, ld_2, ld_3, ld_4),
            (le_switch, lf_switch, lg_switch, lh_switch),
            (le_1, le_2, le_3, le_4),
            (lf_1, lf_2, lf_3, lf_4),
            (lg_1, lg_2, lg_3, lg_4),
            (lh_1, lh_2, lh_3, lh_4)]

        return all([vars_matrix[l] == mtrx[l]
                    for l in range(10)])
The end result now produces this code:

Code: Select all

## cmpc_matrix((PANEL 1 TOP[0-3]), (COLUMN 'A' left[0/1]), (COLUMN 'B' left[0/1]), (COLUMN 'C' left[0/1]), (COLUMN 'D' left[0/1]),
##                     (PANEL 2 TOP[0-3]), (COLUMN 'A' right[0/1]), (COLUMN 'B' right[0/1]), (COLUMN 'C' right[0/1]), (COLUMN 'D' right[0/1]))

cmpc_matrix((0,3,3,0), (0,0,1,1), (0,0,1,1), (1,1,0,0), (1,1,0,0),
                     (0,0,0,0), (0,1,1,0), (0,1,1,0), (0,1,1,0), (0,1,1,0))
The numbers can be what ever I make it to be. The player just has to put in the right code so that it matches, else (from the design) it will be incorrect.
Note: This is a boolean type (from what I've tested).

I thought I'd go ahead and try to add a dictionary for the different variations of the code.
The 'Identifier' and then the 'code' which is actually a 'boolean' type.
The dictionary has a lot more, but just for a demonstration, I've only included a few.
Here it is:

Code: Select all

cmpc_matrix_dict = {
    "FH1RJ1": cmpc_matrix((3, 0, 0, 0), (1, 1, 1, 1), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0),
                          		(0, 0, 0, 3), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (1, 1, 1, 1)),
    "CE6CGA": cmpc_matrix((0, 3, 3, 0), (0, 1, 1, 0), (1, 0, 0, 1), (1, 0, 0, 1), (0, 1, 1, 0),
                          		(2, 3, 3, 1), (0, 0, 0, 1), (1, 0, 1, 1), (1, 1, 0, 1), (1, 0, 0, 0)),
    "NXUIK8": cmpc_matrix((0, 3, 3, 0), (0, 0, 1, 1), (0, 0, 1, 1), (1, 1, 0, 0), (1, 1, 0, 0),
                          		(0, 0, 0, 0), (0, 1, 1, 0), (0, 1, 1, 0), (0, 1, 1, 0), (0, 1, 1, 0))
				}
# plus many others
This is only a few I'll share as it is very long.

I've tried adding a randomiser that will show and expect the correct result by the player.

Code: Select all

default cmpc_list = renpy.random.choice(list(cmpc_matrix_dict.items()))
Here's the "new" function I've been working on: (Don't laugh :lol:)

Code: Select all

init python:
	def cmpc_matrix_codes_new():
		if list(cmpc_list)[1] is True:
            		return True

        	else:
            		# This is if the code didn't match the required (currently displayed one)
            		return False
       	
       	# And then the display one, which works fine since it's supposed to display the required code (or the 'key' from the dictionary above)
       	def cmpc_serials_new():
        	for i in cmpc_list:
            		return str(i)
I've tried all sorts of methods like using a 'for' loop but it didn't yield the results I wanted.

Here's the old, bulky code (condensed just for demonstration):

Code: Select all

init python:
	cmpc_random = renpy.random.randint(1, 32)
	
	def cmpc_matrix_codes_old(): # This one works from an RNG above

        	# F H 1 R J 1
        	if cmpc_random == 1:
            		if cmpc_matrix((3,0,0,0), (1,1,1,1), (0,0,0,0), (0,0,0,0), (0,0,0,0),
                            		(0,0,0,3), (0,0,0,0), (0,0,0,0), (0,0,0,0), (1,1,1,1)):
                	return True

        	# C E 6 C G A
        	elif cmpc_random == 2:
            		if cmpc_matrix((0,3,3,0), (0,1,1,0), (1,0,0,1), (1,0,0,1), (0,1,1,0),
                           		(2,3,3,1), (0,0,0,1), (1,0,1,1), (1,1,0,1), (1,0,0,0)):
                	return True

        	# N X U I K 8
        	elif cmpc_random == 3:
            		if cmpc_matrix((0,3,3,0), (0,0,1,1), (0,0,1,1), (1,1,0,0), (1,1,0,0),
                            		(0,0,0,0), (0,1,1,0), (0,1,1,0), (0,1,1,0), (0,1,1,0)):
                	return True
        # And many, many more.
The code in the script just jumps to like a 'fake code checker' like this:

Code: Select all

label code_check: ## CHECK THE CODE
	$ renpy.block_rollback()
	if cmpc_matrix_codes_new(): # This function is basically suppose to return True to run is block, else return False and skip.
		# if cmpc_matrix_codes(cmpc_random): # This is the old function, which works but has a .7 delay.
		jump correct
        else:
		$ cmpc_list = renpy.random.choice(list(cmpc_matrix_dict.items()))
		# $ cmpc_random = renpy.random.randint(1, 32) # This is the old RNG
		jump incorrect
# etc
(If this doesn't work, I'm open to trying new codes AND I do have a backup code that works fine but is a little slow and very lengthy.)
If there is anything else you need I'll be more than happy to provide (if I can).


Thanks for taking the time to read this.

All help is appreciated. :D

EDIT: The new function, for some reason returns a False value (I think), so in the label, when it checks it it just comes back as False.
Last edited by Angelo Seraphim on Wed Aug 28, 2019 5:55 am, edited 1 time in total.
Image

User avatar
Kia
Eileen-Class Veteran
Posts: 1011
Joined: Fri Aug 01, 2014 7:49 am
Deviantart: KiaAzad
Discord: Kia#6810
Contact:

Re: (Help needed) Elaborate RNG Puzzle game/sequence.

#2 Post by Kia » Wed Aug 28, 2019 1:06 am

I would start cleaning the code by creating two classes, one for the different items that are placed in the slots, and one to contain the games logic.

and here's how you can loop through a multi level list, you can use it to assign a random object to each slot. this way you don't have to define every possible combination.

Code: Select all

def fill(self):
    for ii in self.map:
        for i in ii:
            pass # do something

User avatar
Angelo Seraphim
Regular
Posts: 32
Joined: Tue May 21, 2019 8:00 am
Completed: Enamored Risks (NaNoReNo 2020)
Projects: 616 Charagma
Organization: GLSUoA
Deviantart: glsuoa
itch: glsuoa
Location: London, UK
Discord: Just A Concept#9599
Contact:

Re: (Help needed) Elaborate RNG Puzzle game/sequence.

#3 Post by Angelo Seraphim » Wed Aug 28, 2019 1:41 am

Kia wrote:
Wed Aug 28, 2019 1:06 am
I would start cleaning the code by creating two classes, one for the different items that are placed in the slots, and one to contain the games logic.

and here's how you can loop through a multi level list, you can use it to assign a random object to each slot. this way you don't have to define every possible combination.

Code: Select all

def fill(self):
    for ii in self.map:
        for i in ii:
            pass # do something
Thanks. I'll give that a try and play around with it. :D
Image

User avatar
Angelo Seraphim
Regular
Posts: 32
Joined: Tue May 21, 2019 8:00 am
Completed: Enamored Risks (NaNoReNo 2020)
Projects: 616 Charagma
Organization: GLSUoA
Deviantart: glsuoa
itch: glsuoa
Location: London, UK
Discord: Just A Concept#9599
Contact:

Re: (Help needed) Elaborate RNG Puzzle game/sequence.

#4 Post by Angelo Seraphim » Wed Aug 28, 2019 5:28 am

Okay, so I couldn't get my head around Kai's method. However, I found a workaround that seems to work a lot better and is exactly what I wanted.
It's is 100% rng now so there are numerous possibilities now with the new code.

Here it is: (Note: This was tested in PyCharm and not RenPy. THIS IS NOT ACTUAL RENPY CODE. I will translate it over to RenPy once I'm happy with it overall.)

Code: Select all

# Here's the class I've created. Works fine. I may have to change the name 'Matrix' as I feel it might mess with something... not sure.
class Matrix:
    def __init__(self, ident, code):
        self.ident = ident
        self.code = code
These are the "1 part" codes: (The numbers represent the defaults I mentioned in the first part of the original post.)

Code: Select all

FH1 = Matrix("FH1", ((3, 0, 0, 0), (1, 1, 1, 1), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)))
FH3 = Matrix("FH3", ((1, 3, 0, 0), (0, 0, 1, 1), (1, 1, 1, 1), (0, 0, 0, 0), (0, 0, 0, 0)))
FH5 = Matrix("FH5", ((0, 1, 1, 0), (0, 0, 0, 0), (0, 0, 1, 1), (0, 0, 1, 1), (0, 0, 0, 0)))
FH7 = Matrix("FH7", ((0, 1, 1, 0), (0, 0, 0, 0), (0, 0, 1, 1), (0, 0, 1, 1), (0, 0, 0, 0)))

CE2 = Matrix("CE2", ((3, 3, 0, 0), (1, 0, 0, 1), (1, 0, 0, 1), (0, 1, 1, 0), (0, 1, 1, 0)))
CE4 = Matrix("CE4", ((0, 0, 3, 3), (0, 1, 1, 0), (0, 1, 1, 0), (1, 0, 0, 1), (1, 0, 0, 1)))
CE6 = Matrix("CE6", ((0, 3, 3, 0), (0, 1, 1, 0), (1, 0, 0, 1), (1, 0, 0, 1), (0, 1, 1, 0)))
CE8 = Matrix("CE8", ((3, 3, 3, 3), (1, 0, 0, 1), (1, 0, 0, 1), (1, 0, 0, 1), (1, 0, 0, 1)))

RJ1 = Matrix("RJ1", ((0, 0, 0, 3), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (1, 1, 1, 1)))
RJ3 = Matrix("RJ3", ((0, 0, 3, 1), (0, 0, 0, 0), (0, 0, 0, 0), (1, 1, 1, 1), (0, 0, 1, 1)))
RJ5 = Matrix("RJ5", ((0, 2, 2, 0), (0, 0, 0, 0), (1, 1, 0, 0), (1, 1, 0, 0), (0, 0, 0, 0)))
RJ7 = Matrix("RJ7", ((1, 2, 1, 2), (0, 0, 1, 1), (1, 1, 0, 0), (0, 0, 1, 1), (1, 1, 0, 0)))

IK2 = Matrix("IK2", ((2, 3, 3, 0), (1, 1, 0, 0), (0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 0, 1)))
IK4 = Matrix("IK4", ((0, 3, 3, 1), (1, 0, 0, 1), (1, 1, 1, 0), (0, 1, 1, 0), (0, 0, 1, 1)))
IK6 = Matrix("IK6", ((3, 0, 0, 3), (1, 0, 0, 1), (0, 1, 1, 0), (0, 1, 1, 0), (1, 0, 0, 1)))
IK8 = Matrix("IK8", ((0, 0, 0, 0), (0, 1, 1, 0), (0, 1, 1, 0), (0, 1, 1, 0), (0, 1, 1, 0)))

CGA = Matrix("CGA", ((2, 3, 3, 1), (0, 0, 0, 1), (1, 0, 1, 1), (1, 1, 0, 1), (1, 0, 0, 0)))
NXU = Matrix("NXU", ((0, 3, 3, 0), (0, 0, 1, 1), (0, 0, 1, 1), (1, 1, 0, 0), (1, 1, 0, 0)))
WOF = Matrix("WOF", ((1, 1, 1, 1), (0, 1, 1, 1), (0, 0, 0, 1), (1, 0, 0, 1), (1, 1, 0, 0)))
YTR = Matrix("YTR", ((3, 1, 2, 3), (1, 1, 1, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 1, 1, 1)))
QSZ = Matrix("QSZ", ((0, 0, 0, 0), (1, 0, 0, 0), (1, 0, 0, 0), (1, 0, 0, 0), (1, 0, 0, 0)))
LMS = Matrix("LMS", ((1, 0, 3, 0), (1, 1, 1, 1), (0, 0, 0, 0), (0, 0, 1, 1), (0, 0, 1, 1)))
TPV = Matrix("TPV", ((1, 1, 2, 3), (0, 1, 1, 0), (1, 1, 0, 0), (1, 0, 1, 0), (0, 0, 0, 0)))
JZA = Matrix("JZA", ((3, 2, 3, 2), (0, 0, 0, 0), (1, 1, 0, 0), (0, 0, 1, 0), (1, 1, 1, 1)))
I threw the "codes" into a 2 part randomiser.

Code: Select all

code_one = random.choice(
        [FH1, FH3, FH5, FH7, CE2, CE4, CE6, CE8, RJ1, RJ3, RJ5,
         RJ7, IK2, IK4, IK6, IK8, CGA, NXU, WOF, YTR, QSZ, LMS,
         TPV, JZA])
code_two = random.choice(
        [FH1, FH3, FH5, FH7, CE2, CE4, CE6, CE8, RJ1, RJ3, RJ5,
         RJ7, IK2, IK4, IK6, IK8, CGA, NXU, WOF, YTR, QSZ, LMS,
         TPV, JZA])
matrix_code = code_one.code + code_two.code # This will return a boolean of those numbers
matrix_ident = str(code_one.ident + code_two.ident) # This will return the strings (code_one and code_two) E.g "FH1CE2"
counter = 0 # Just for visual representation.

print("The search for code, CE8JZA") # Just for testing.
Here's a test loop to see if it works... And it does.

Code: Select all

while matrix_code:

    code_one = random.choice(
        [FH1, FH3, FH5, FH7, CE2, CE4, CE6, CE8, RJ1, RJ3, RJ5,
         RJ7, IK2, IK4, IK6, IK8, CGA, NXU, WOF, YTR, QSZ, LMS,
         TPV, JZA])
    code_two = random.choice(
        [FH1, FH3, FH5, FH7, CE2, CE4, CE6, CE8, RJ1, RJ3, RJ5,
         RJ7, IK2, IK4, IK6, IK8, CGA, NXU, WOF, YTR, QSZ, LMS,
         TPV, JZA])
    matrix_code = code_one.code + code_two.code
    matrix_ident = str(code_one.ident + code_two.ident)
    print("=" * 40)
    print(matrix_code) # Prints the numbers
    print(matrix_ident) # Shows the string
    print("=" * 40)
    if cmpc_matrix(*matrix_code) is True: # This is the function mentioned in the second part of the original post. (Took mee a while to figure this out.)
        print("Code:", cmpc_matrix(*matrix_code)) # Prints 'True' or 'False'
        print("Success! After", counter, "attempts.")
        break

    counter += 1
    print("Code:", cmpc_matrix(*matrix_code)) # Prints 'True' or 'False'
    print("Attempts:", counter)
    time.sleep(.01) # Just for fun. Not really needed.
Now after all of this, I'm happy with it.
HOWEVER, I'm wondering how would I put this into a function that will include "Successes/Win" condition and "Failures"?

I'm kind of thinking something like this perhaps?

Code: Select all

def cmpc_matrix_code_check():
    if cmpc_matrix(*matrix_code):
        # Player succeeds
        return True
    else:
        # Player get penalised
        return False
Image

User avatar
Angelo Seraphim
Regular
Posts: 32
Joined: Tue May 21, 2019 8:00 am
Completed: Enamored Risks (NaNoReNo 2020)
Projects: 616 Charagma
Organization: GLSUoA
Deviantart: glsuoa
itch: glsuoa
Location: London, UK
Discord: Just A Concept#9599
Contact:

Re: [SOLVED] (Help needed) Elaborate RNG Puzzle game/sequence.

#5 Post by Angelo Seraphim » Wed Aug 28, 2019 5:55 am

Nevermind. I've worked it out now. It's working flawlessly. That function worked perfectly.
Image

Post Reply

Who is online

Users browsing this forum: Bing [Bot]