Created
July 23, 2021 10:39
-
-
Save cryptoleek-eth/bc79f416549f09414da1612a0e1fa831 to your computer and use it in GitHub Desktop.
Chubbies Generation Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
The MIT License | |
Copyright (c) 2021 Chubbies NFT | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
DEALINGS IN THE SOFTWARE. | |
''' | |
# This is the exact code used to generate the gifs for all 10000 Chubbies NFT and the json for properties for OpenSea. | |
# It will need some editing to work for another project as the code was meant to work for Chubbies' needs specifically. | |
from PIL import Image | |
import json | |
import random | |
import sys | |
import os | |
import time | |
# TODO | |
# [x] Function to generate the rare pool | |
# [x] Function to divide rare arrays into 10 and replace indices in each bucket | |
# [x] Function to analyze the array and report on the traits. | |
# [x] Deduplicate Chubbies | |
# Create output paths if it don't exist | |
if not os.path.exists('output'): | |
os.makedirs('output') | |
os.makedirs('output/json') | |
os.makedirs('output/gifs') | |
# Special Treatment Chubbies, like Mewtwo | |
SPECIAL_LAB_CHUBBY_0 = 0 | |
SPECIAL_LAB_CHUBBY_9999 = 9999 | |
# Directory paths | |
background_path = "./chubbies/background/" | |
shadow_path = "./chubbies/shadow/" | |
face_path = "./chubbies/face/" | |
bottom_path = "./chubbies/bottom/" | |
head_path = "./chubbies/head/" | |
top_path = "./chubbies/top/" | |
accessories_path = "./chubbies/accessories/" | |
filetype = ".png" | |
# Field Names | |
TOP_COSTUME_NAME = "Top Costume" | |
BOTTOM_COSTUME_NAME = "Bottom Costume" | |
HEAD_RACE_NAME = "Head Race" | |
BOTTOM_RACE_NAME = "Bottom Race" | |
FACE_NAME = "Face" | |
HAIRSTYLE_NAME = "Hairstyle" | |
HUMAN_SKIN_TONE_NAME = "Human Skin Tone" | |
CAT_COLOR_TYPE_NAME = "Cat Color Type" | |
ACCESSORIES_NAME = "Accessories" | |
SHININESS_NAME = "Shininess" | |
BACKGROUND_NAME = "Background" | |
HUMAN_BOTTOM_NAME = "Human Bottom" | |
COSTUME_TOKEN_NAME = "Token" | |
METHOD_NAME = "Method" | |
METHOD_LAB_GROWN = "Lab-Grown" | |
METHOD_NATURAL = "Natural" | |
METHOD_GODMODE = "God Mode" | |
SET_NAME = "Set" | |
SET_MATCHED_NAME = "Yay" | |
SET_MISMATCHED_NAME = "Nah" | |
SET_TYPE_NAME = "Set Type" | |
SET_TYPE_HUMAN_RACE_NAME = "Human Race" | |
SET_TYPE_NON_HUMAN_RACE_NAME = "Non-Human Race" | |
SET_TYPE_COSTUME_NAME = "Costume" | |
BACKGROUND_NORMAL_RARITY = 8 | |
bottom_with_skin_tone = {"Human_Duck Tube", "Banana", "Human_Duck Tube_shiny", "Banana_shiny", "Human_Jeans", "Human_Jeans_shiny"} | |
HUMAN_RACE_NAME = "Human" | |
CAT_RACE_NAME = "Cat" | |
#### Rarity Chart | |
# RACE | |
HEAD_RACE_OPTIONS = {"Alien": 50, "Ape": 250, "Monkey": 1000, "Robot": 700, "Snowman": 100, "Squid": 300, "Zombie": 200, CAT_RACE_NAME: 1000, HUMAN_RACE_NAME: 6500} | |
BOTTOM_RACE_OPTIONS = {"Alien": 50, "Snowman": 100, "Ape": 250, "Squid": 400, "Robot": 700, "Monkey": 800, "Zombie": 200, CAT_RACE_NAME: 1000, HUMAN_RACE_NAME: 6500} | |
# COSTUMES | |
TOP_COSTUME_OPTIONS = {"Apple": 200, "Astronaut": 50, "Avocado": 400, "Banana": 200, "Cat": 800, "Chicken": 500, "Kaiju": 250, "Kuma": 800, "Milk Cow": 500, "Monkey": 800, "Penguin": 500, "Pig": 500, "Raccoon": 500, "Shiba": 800, "Special Monkey": 10} | |
BOTTOM_COSTUME_OPTIONS = {"Apple": 100, "Astronaut": 50, "Avocado": 300, "Banana": 200, "Cat": 800, "Chicken": 500, "Kaiju": 250, "Kuma": 800, "Milk Cow" : 500, "Monkey": 800, "Penguin": 500, "Pig": 500, "Raccoon": 500, "Shiba": 800} | |
# FACE | |
FACE_OPTIONS = {"-_-": 3, "-_- Blushed": 3, "+w+": 1, "|_|": 3, "|_| Blushed": 3, "Alien": 1, "Angry": 3, "Ape": 1, "Cat": 3, "Cat Blushed": 3, "o_o": 3, "o_o Blushed": 3, "Zombie": 1 | |
} | |
# ACCESSORIES | |
ACCESSORIES_OPTIONS = {"": 850, "Butterfly": 25, "Diamond Hands": 25, "Propeller Hat": 25, "My Wifes Sunglasses": 25, "Sunglasses": 25, "Crown": 25} | |
SHININESS_OPTIONS = {"shiny": 1, "": 50} | |
COSTUME_TOKEN_OPTIONS = {"": 1, "Heart": 1, "Skull": 1} | |
# HUMAN-ONLY | |
HUMAN_SKIN_TONE_OPTIONS = {"light": 1, "medium": 1, "brown": 1, "dark": 1} | |
HUMAN_BOTTOM_OPTIONS = {"Duck Tube": 1, "Jeans": 5} | |
HAIRSTYLE_OPTIONS = {"Afro": 1, "Long": 2, "Short": 3} | |
# CAT-ONLY | |
CAT_COLOR_TYPE_OPTIONS = {"Black": 3, "Pusheen": 7} | |
# BACKGROUNDS | |
BACKGROUND_OPTIONS = {"Ao English": BACKGROUND_NORMAL_RARITY, "Celeste": BACKGROUND_NORMAL_RARITY, "Chocolate Web": BACKGROUND_NORMAL_RARITY, "Disco": 1, "Eerie Black": BACKGROUND_NORMAL_RARITY, "French Violet": BACKGROUND_NORMAL_RARITY, "Indigo": BACKGROUND_NORMAL_RARITY, "Lavender Blue": BACKGROUND_NORMAL_RARITY, "Medium Champagne": BACKGROUND_NORMAL_RARITY, "Melon": BACKGROUND_NORMAL_RARITY, "Night Club": BACKGROUND_NORMAL_RARITY, "Nyanza": BACKGROUND_NORMAL_RARITY, "Orange Yellow": BACKGROUND_NORMAL_RARITY, "Pastel Pink": BACKGROUND_NORMAL_RARITY, "Rainbow": 1, "Resting Lab": BACKGROUND_NORMAL_RARITY, "Ruby Red": BACKGROUND_NORMAL_RARITY, "Sapphire": BACKGROUND_NORMAL_RARITY, "Secret Forest": 1, "Silver": BACKGROUND_NORMAL_RARITY, "Sky": 1, "Space": 1, "White": BACKGROUND_NORMAL_RARITY, "Working Lab": 1 | |
} | |
final_version_skin_properties = [] | |
###################################################################################################### | |
def is_fruit_costume(name): | |
return name in ["Banana", "Apple", "Avocado", "Astronaut"] | |
# Concatenate image | |
def image_cat(background, bottom, bottom_skintone, is_human, head, top, face, face_color, skin_tone, accessories, shiny): | |
medium_skin_tone = (250, 206, 171, 255) | |
light_skin_tone = (255, 225, 201, 255) | |
brown_skin_tone = (213, 157, 103, 255) | |
dark_skin_tone = (111, 63, 60, 255) | |
medium_skin_shadow = (231, 170, 154, 255) | |
light_skin_shadow = (255, 188, 157, 255) | |
brown_skin_shadow = (172, 110, 53, 255) | |
dark_skin_shadow = (89, 44, 48, 255) | |
black = (0, 0, 0, 255) | |
white = (255, 255, 255, 255) | |
short_head_medium_skin_shadow = (205, 162, 118, 255) | |
image = Image.open(background) | |
pix = image.load() | |
width, height = image.size | |
skin_properties = [bottom, head, top, face] | |
for current in range(len(skin_properties)): | |
if skin_properties[current] == "": | |
continue | |
elif skin_properties[current] == top and not is_human: | |
new_image = Image.open(skin_properties[current]).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j][3] != 0: | |
if new_pix[i, j] == medium_skin_tone or new_pix[i, j] == medium_skin_shadow or new_pix[i, j] == short_head_medium_skin_shadow: | |
continue | |
else: | |
pix[i, j] = new_pix[i, j] | |
elif skin_properties[current] == top or skin_properties[current] == head or (skin_properties[current] == bottom and bottom_skintone): | |
new_image = Image.open(skin_properties[current]).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j][3] != 0: | |
if new_pix[i, j] == medium_skin_tone: | |
if skin_tone == "light": | |
pix[i, j] = light_skin_tone | |
elif skin_tone == "brown": | |
pix[i, j] = brown_skin_tone | |
elif skin_tone == "dark": | |
pix[i, j] = dark_skin_tone | |
elif skin_tone == "medium": | |
pix[i, j] = medium_skin_tone | |
else: | |
continue | |
elif new_pix[i, j] == medium_skin_shadow or new_pix[i, j] == short_head_medium_skin_shadow: | |
if skin_tone == "light": | |
pix[i, j] = light_skin_shadow | |
elif skin_tone == "brown": | |
pix[i, j] = brown_skin_shadow | |
elif skin_tone == "dark": | |
pix[i, j] = dark_skin_shadow | |
elif skin_tone == "medium": | |
pix[i, j] = new_pix[i, j] | |
else: | |
continue | |
else: | |
pix[i, j] = new_pix[i, j] | |
else: | |
new_image = Image.open(skin_properties[current]).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j][3] != 0: | |
pix[i, j] = new_pix[i, j] | |
if face_color == "white": | |
new_image = Image.open(face).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j] == black: | |
pix[i, j] = white | |
if accessories != "": | |
new_image = Image.open(accessories).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j][3] != 0: | |
pix[i, j] = new_pix[i, j] | |
if shiny != "": | |
new_image = Image.open(shiny).convert("RGBA") | |
new_pix = new_image.load() | |
for i in range(width): | |
for j in range(height): | |
if new_pix[i, j][3] != 0: | |
pix[i, j] = new_pix[i, j] | |
return image | |
def gen_all_properties(num_tokens): | |
total_tokens = num_tokens * 5 | |
random_use_bottom_costumes = random.choices([0, 1], weights=[50, 50], k=total_tokens) | |
# Races | |
random_head_races = random.choices(list(HEAD_RACE_OPTIONS.keys()), weights=HEAD_RACE_OPTIONS.values(), k=total_tokens) | |
random_top_costumes = random.choices(list(TOP_COSTUME_OPTIONS.keys()), weights=TOP_COSTUME_OPTIONS.values(), k=total_tokens) | |
random_bottom_races = random.choices(list(BOTTOM_RACE_OPTIONS.keys()), weights=BOTTOM_RACE_OPTIONS.values(), k=total_tokens) | |
random_bottom_costumes = random.choices(list(BOTTOM_COSTUME_OPTIONS.keys()), weights=BOTTOM_COSTUME_OPTIONS.values(), k=total_tokens) | |
random_faces = random.choices(list(FACE_OPTIONS.keys()), weights=FACE_OPTIONS.values(), k=total_tokens) | |
random_shininess = random.choices(list(SHININESS_OPTIONS.keys()), weights=SHININESS_OPTIONS.values(), k=total_tokens) | |
random_accessories = random.choices(list(ACCESSORIES_OPTIONS.keys()), weights=ACCESSORIES_OPTIONS.values(), k=total_tokens) | |
random_backgrounds = random.choices(list(BACKGROUND_OPTIONS.keys()), weights=BACKGROUND_OPTIONS.values(), k=total_tokens) | |
# Human only | |
random_skin_tones = random.choices(list(HUMAN_SKIN_TONE_OPTIONS.keys()), weights=HUMAN_SKIN_TONE_OPTIONS.values(), k=total_tokens) | |
random_hair_styles = random.choices(list(HAIRSTYLE_OPTIONS.keys()), weights=HAIRSTYLE_OPTIONS.values(), k=total_tokens) | |
random_human_bottoms = random.choices(list(HUMAN_BOTTOM_OPTIONS.keys()), weights=HUMAN_BOTTOM_OPTIONS.values(), k=total_tokens) | |
# Cats only | |
random_cat_colors = random.choices(list(CAT_COLOR_TYPE_OPTIONS.keys()), weights=CAT_COLOR_TYPE_OPTIONS.values(), k=total_tokens) | |
random_costume_badges = random.choices(list(COSTUME_TOKEN_OPTIONS.keys()), weights=COSTUME_TOKEN_OPTIONS.values(), k=total_tokens) | |
property_maps = [] | |
dedup_set = set() | |
# Generate GIFs | |
for i in range(total_tokens): | |
property_map = { | |
TOP_COSTUME_NAME: random_top_costumes[i], | |
BOTTOM_COSTUME_NAME: random_bottom_costumes[i] if random_use_bottom_costumes[i] else "", | |
HEAD_RACE_NAME: random_head_races[i], | |
BOTTOM_RACE_NAME: random_bottom_races[i] if not random_use_bottom_costumes[i] else "", | |
FACE_NAME: random_faces[i], | |
SHININESS_NAME: random_shininess[i], | |
ACCESSORIES_NAME: random_accessories[i], | |
BACKGROUND_NAME: random_backgrounds[i], | |
HUMAN_BOTTOM_NAME: random_human_bottoms[i] if random_bottom_races[i] == HUMAN_RACE_NAME else "", | |
HAIRSTYLE_NAME: random_hair_styles[i] if random_head_races[i] == HUMAN_RACE_NAME else "", | |
HUMAN_SKIN_TONE_NAME: random_skin_tones[i] if random_head_races[i] == HUMAN_RACE_NAME or random_bottom_races[i] == HUMAN_RACE_NAME or random_bottom_costumes[i] == "Banana" else "", | |
CAT_COLOR_TYPE_NAME: random_cat_colors[i] if random_head_races[i] == CAT_RACE_NAME or random_bottom_races[i] == CAT_RACE_NAME else "", | |
COSTUME_TOKEN_NAME: random_costume_badges[i] if (random_bottom_costumes[i] in BOTTOM_COSTUME_OPTIONS) and not is_fruit_costume(random_bottom_costumes[i]) else "", | |
METHOD_NAME: METHOD_NATURAL, | |
} | |
criteria = "".join(property_map.values()) | |
if not duplicate(property_map, dedup_set): | |
dedup_set.add(criteria) | |
property_maps.append(property_map) | |
if (len(property_maps) == num_tokens): | |
break | |
return (property_maps, dedup_set) | |
# gen all the sets and distribute them equally into buckets | |
def gen_all_sets(property_maps, dedup_set, num_buckets): | |
costume_set_maps = [] | |
race_set_maps =[] | |
shiny_costume_set_maps = [] | |
shiny_race_set_maps = [] | |
rare_dedup_index_set = set() | |
rare_dedup_index_set.add(SPECIAL_LAB_CHUBBY_0) | |
rare_dedup_index_set.add(SPECIAL_LAB_CHUBBY_9999) | |
for option in TOP_COSTUME_OPTIONS.keys(): | |
if option in BOTTOM_COSTUME_OPTIONS.keys(): | |
new_property_map = {METHOD_NAME: METHOD_LAB_GROWN} | |
new_property_map[TOP_COSTUME_NAME] = option | |
new_property_map[BOTTOM_COSTUME_NAME] = option | |
new_property_map[BOTTOM_RACE_NAME] = "" | |
if not is_fruit_costume(option): | |
new_property_map[COSTUME_TOKEN_NAME] = random.choices(list(COSTUME_TOKEN_OPTIONS.keys()), weights=COSTUME_TOKEN_OPTIONS.values(), k=1)[0] | |
if option == "Banana": | |
new_property_map[HUMAN_SKIN_TONE_NAME] = "dark" | |
for i in range(6): | |
costume_set_maps.append(new_property_map) | |
for option in HEAD_RACE_OPTIONS.keys(): | |
if option in BOTTOM_RACE_OPTIONS.keys(): | |
new_property_map = {METHOD_NAME: METHOD_LAB_GROWN} | |
new_property_map[HEAD_RACE_NAME] = option | |
new_property_map[BOTTOM_RACE_NAME] = option | |
new_property_map[TOP_COSTUME_NAME] = "" | |
new_property_map[BOTTOM_COSTUME_NAME] = "" | |
if option == HUMAN_RACE_NAME: | |
for human_bottom_option in HUMAN_BOTTOM_OPTIONS: | |
for hair_style_option in HAIRSTYLE_OPTIONS: | |
for skin_tone_option in HUMAN_SKIN_TONE_OPTIONS: | |
new_property_map[HAIRSTYLE_NAME] = hair_style_option | |
new_property_map[HUMAN_BOTTOM_NAME] = human_bottom_option | |
new_property_map[HUMAN_SKIN_TONE_NAME] = skin_tone_option | |
race_set_maps.append(new_property_map) | |
elif option == CAT_RACE_NAME: | |
for cat_color_option in CAT_COLOR_TYPE_OPTIONS: | |
new_property_map[CAT_COLOR_TYPE_NAME] = cat_color_option | |
race_set_maps.append(new_property_map) | |
else: | |
for i in range(6): | |
race_set_maps.append(new_property_map) | |
for option in TOP_COSTUME_OPTIONS.keys(): | |
if option in BOTTOM_COSTUME_OPTIONS.keys(): | |
new_property_map = {METHOD_NAME: METHOD_LAB_GROWN} | |
new_property_map[TOP_COSTUME_NAME] = option | |
new_property_map[BOTTOM_COSTUME_NAME] = option | |
new_property_map[BOTTOM_RACE_NAME] = "" | |
new_property_map[SHININESS_NAME] = "shiny" | |
if not is_fruit_costume(option): | |
new_property_map[COSTUME_TOKEN_NAME] = random.choice(list(COSTUME_TOKEN_OPTIONS.keys())) | |
if option == "Banana": | |
new_property_map[HUMAN_SKIN_TONE_NAME] = "dark" | |
shiny_costume_set_maps.append(new_property_map) | |
print("Generating Shiny sets") | |
for option in HEAD_RACE_OPTIONS.keys(): | |
if option in BOTTOM_RACE_OPTIONS.keys(): | |
new_property_map = {METHOD_NAME: METHOD_LAB_GROWN} | |
new_property_map[HEAD_RACE_NAME] = option | |
new_property_map[BOTTOM_RACE_NAME] = option | |
new_property_map[TOP_COSTUME_NAME] = "" | |
new_property_map[BOTTOM_COSTUME_NAME] = "" | |
new_property_map[SHININESS_NAME] = "shiny" | |
if option == HUMAN_RACE_NAME: | |
for human_bottom_option in HUMAN_BOTTOM_OPTIONS: | |
for hair_style_option in HAIRSTYLE_OPTIONS: | |
for skin_tone_option in HUMAN_SKIN_TONE_OPTIONS: | |
new_property_map[HAIRSTYLE_NAME] = hair_style_option | |
new_property_map[HUMAN_BOTTOM_NAME] = human_bottom_option | |
new_property_map[HUMAN_SKIN_TONE_NAME] = skin_tone_option | |
shiny_race_set_maps.append(new_property_map) | |
elif option == CAT_RACE_NAME: | |
for cat_color_option in CAT_COLOR_TYPE_OPTIONS: | |
new_property_map[CAT_COLOR_TYPE_NAME] = cat_color_option | |
shiny_race_set_maps.append(new_property_map) | |
else: | |
shiny_race_set_maps.append(new_property_map) | |
shiny_race_set_maps.append(new_property_map) | |
rares = [costume_set_maps, race_set_maps, shiny_costume_set_maps, shiny_race_set_maps] | |
print("Distributing Sets") | |
for rare_set in rares: | |
random.shuffle(rare_set) | |
distribute_to_buckets(property_maps, rare_set, num_buckets, dedup_set, rare_dedup_index_set) | |
print(f"Added {len(rare_set)} rare items") | |
def gen_gif(index, property_maps): | |
images = [] | |
property_map = property_maps[index] | |
for i in range(1, 6): | |
shiny_extension = "_shiny" if property_map[SHININESS_NAME] != "" else "" | |
# Special treatment | |
bottom_property = property_map[BOTTOM_RACE_NAME] if len(property_map[BOTTOM_RACE_NAME]) > 0 else property_map[BOTTOM_COSTUME_NAME] | |
bottom_filename = bottom_property | |
head_property = property_map[HEAD_RACE_NAME] | |
head_filename = head_property | |
if (property_map[HEAD_RACE_NAME] == HUMAN_RACE_NAME): | |
head_filename += "_" + property_map[HAIRSTYLE_NAME] | |
if (property_map[BOTTOM_RACE_NAME] == HUMAN_RACE_NAME): | |
bottom_filename += "_" + property_map[HUMAN_BOTTOM_NAME] | |
if (property_map[HEAD_RACE_NAME] == CAT_RACE_NAME): | |
head_filename += "_" + property_map[CAT_COLOR_TYPE_NAME] | |
if (property_map[BOTTOM_RACE_NAME] == CAT_RACE_NAME): | |
bottom_filename += "_" + property_map[CAT_COLOR_TYPE_NAME] | |
if (COSTUME_TOKEN_NAME in property_map) and (len(property_map[COSTUME_TOKEN_NAME]) > 0) and (len(property_map[BOTTOM_COSTUME_NAME]) > 0) and (not is_fruit_costume(property_map[BOTTOM_COSTUME_NAME])): | |
bottom_filename += "_" + property_map[COSTUME_TOKEN_NAME] | |
# def image_cat(background, bottom, bottom_skintone, is_human, head, top, face, face_color, skin_tone, accessories, shiny): | |
currentimage = image_cat( | |
background_path + property_map[BACKGROUND_NAME] + str(i) + filetype, | |
bottom_path + bottom_filename + shiny_extension + str(i) + filetype, | |
bottom_filename in bottom_with_skin_tone, | |
property_map[HEAD_RACE_NAME] == HUMAN_RACE_NAME, | |
head_path + head_filename + shiny_extension + str(i) + filetype, | |
top_path + property_map[TOP_COSTUME_NAME] + shiny_extension + str(i) + filetype if property_map[TOP_COSTUME_NAME] != "" else "", | |
face_path + property_map[FACE_NAME] + str(i) + filetype, | |
"white" if property_map[HEAD_RACE_NAME] == CAT_RACE_NAME and property_map[CAT_COLOR_TYPE_NAME] == "Black" and property_map[SHININESS_NAME] != "shiny" else "black", | |
property_map[HUMAN_SKIN_TONE_NAME] if HUMAN_SKIN_TONE_NAME in property_map.keys() else "", | |
accessories_path + property_map[ACCESSORIES_NAME] + str(i) + filetype if property_map[ACCESSORIES_NAME] != "" else "", | |
accessories_path + "shiny" + str(i) + filetype if property_map[SHININESS_NAME] == "shiny" else "" | |
) | |
images.append(currentimage) | |
images[0].save("./output/gifs/" +str(index) + '.gif', save_all=True, append_images=images[1:], duration=150, loop=0) | |
def gen_all_gifs(property_maps): | |
for index in range(len(property_maps)): | |
if index % 20 == 0: | |
print(index) | |
gen_gif(index, property_maps) | |
# Like Epidemic Cards in Pandemic | |
def distribute_to_buckets(property_maps, distribute_maps, num_buckets, dedup_set, rare_dedup_index_set): | |
num_tokens = len(property_maps) #10000 | |
bucket_size = int(num_tokens/num_buckets) #1000 | |
num_per_bucket = int(len(distribute_maps) / num_buckets) | |
num_per_bucket = 1 if num_per_bucket == 0 else num_per_bucket | |
# print(f"len(distribute_maps): {len(distribute_maps)}") | |
# print(f"bucket_size Size: {bucket_size}") | |
# print(f"num_per_bucket: {bucket_size}") | |
for distribute_map_index in range(len(distribute_maps)): | |
bucket_index = int(distribute_map_index / num_per_bucket) | |
if bucket_index >= num_buckets: | |
bucket_index = num_buckets - 1 | |
while True: | |
target_index = int(bucket_index * bucket_size + random.choice(range(bucket_size))) | |
#print(f"target_index: {target_index}") | |
if (target_index >= len(property_maps)): | |
continue | |
new_property_map = property_maps[target_index] | distribute_maps[distribute_map_index] | |
if not (target_index in rare_dedup_index_set and duplicate(new_property_map, dedup_set)): | |
break | |
property_maps[target_index] = new_property_map | |
rare_dedup_index_set.add(target_index) | |
dedup_set.add(get_duplicate_criteria(new_property_map)) | |
def get_duplicate_criteria(property_map): | |
return "".join(property_map.values()) | |
# Check Duplicates | |
def duplicate(property_map, dedup_set): | |
return get_duplicate_criteria(property_map)in dedup_set | |
# Just to make sure | |
def duplicate_sanity_check(property_maps): | |
new_sanity_dedup_set = set() | |
for i in range(len(property_maps)): | |
property_map = property_maps[i] | |
if duplicate(property_map, new_sanity_dedup_set): | |
print("MAYDAY, there's a duplicate Chubby who sneaked in!!! SOMETHING IS VERY WRONG.") | |
sys.exit() | |
# Print Analytics | |
def print_insights(property_maps, num_buckets): | |
num_tokens = len(property_maps) | |
bucket_size = int(num_tokens/num_buckets) | |
property_rarity_counts = [{ | |
"race sets": 0, | |
"costume sets": 0, | |
"lab-grown": 0, | |
"natural": 0 | |
} for x in range(num_buckets)] | |
for index in range(num_tokens): | |
bucket_index = int(index / bucket_size) | |
property_map = property_maps[index] | |
if property_map[TOP_COSTUME_NAME] == property_map[BOTTOM_COSTUME_NAME]: | |
property_rarity_counts[bucket_index]["costume sets"] += 1 | |
if property_map[HEAD_RACE_NAME] == property_map[BOTTOM_RACE_NAME]: | |
property_rarity_counts[bucket_index]["race sets"] += 1 | |
for index in range(len(property_rarity_counts)): | |
num_race_set = property_rarity_counts[index]["race sets"] | |
num_costumes_set = property_rarity_counts[index]["costume sets"] | |
print(f"Bucket {index}: {num_race_set} race sets {num_costumes_set} costume sets") | |
# Creating Mewtwos | |
def incubate_lab_grown_chubby_gods(property_maps, dedup_set): | |
# Husband's pick | |
property_maps[SPECIAL_LAB_CHUBBY_0] = { | |
TOP_COSTUME_NAME: "Astronaut", | |
BOTTOM_COSTUME_NAME: "Astronaut", | |
HEAD_RACE_NAME: "Alien", | |
BOTTOM_RACE_NAME: "", | |
FACE_NAME: "Alien", | |
SHININESS_NAME: "shiny", | |
ACCESSORIES_NAME: "Diamond Hands", | |
BACKGROUND_NAME: "Space", | |
METHOD_NAME: METHOD_GODMODE, | |
} | |
# Wife's pick | |
property_maps[SPECIAL_LAB_CHUBBY_9999] = { | |
TOP_COSTUME_NAME: "Pig", | |
BOTTOM_COSTUME_NAME: "", | |
HEAD_RACE_NAME: "Human", | |
BOTTOM_RACE_NAME: "Human", | |
FACE_NAME: "Cat Blushed", | |
SHININESS_NAME: "shiny", | |
ACCESSORIES_NAME: "Propeller Hat", | |
BACKGROUND_NAME: "Sky", | |
HUMAN_BOTTOM_NAME: "Duck Tube", | |
HAIRSTYLE_NAME: "Afro", | |
HUMAN_SKIN_TONE_NAME: "light", | |
METHOD_NAME: METHOD_GODMODE, | |
} | |
def output_json(property_maps, image_url): | |
for index in range(len(property_maps)): | |
property_map = property_maps[index] | |
data = {} | |
data["attributes"] = [] | |
if property_map[HEAD_RACE_NAME] != HUMAN_RACE_NAME and property_map[BOTTOM_RACE_NAME] != HUMAN_RACE_NAME: | |
property_map[HUMAN_SKIN_TONE_NAME] = "" | |
if (property_map[BOTTOM_RACE_NAME] != "" and property_map[BOTTOM_RACE_NAME] != HUMAN_RACE_NAME) or (property_map[BOTTOM_RACE_NAME] == "" and property_map[BOTTOM_COSTUME_NAME] != ""): | |
property_map[HUMAN_BOTTOM_NAME] = "" | |
if property_map[BOTTOM_RACE_NAME] != "" or is_fruit_costume(property_map[BOTTOM_COSTUME_NAME]): | |
property_map[COSTUME_TOKEN_NAME] = "" | |
if property_map[HEAD_RACE_NAME] != CAT_RACE_NAME and property_map[BOTTOM_RACE_NAME] != CAT_RACE_NAME: | |
property_map[CAT_COLOR_TYPE_NAME] = "" | |
if property_map[HEAD_RACE_NAME] != HUMAN_RACE_NAME: | |
property_map[HAIRSTYLE_NAME] = "" | |
is_race_set = (HEAD_RACE_NAME in property_map) and (BOTTOM_RACE_NAME in property_map) and (property_map[HEAD_RACE_NAME] == property_map[BOTTOM_RACE_NAME]) | |
is_costume_set = (TOP_COSTUME_NAME in property_map) and (BOTTOM_COSTUME_NAME in property_map) and (property_map[TOP_COSTUME_NAME] == property_map[BOTTOM_COSTUME_NAME]) and property_map[TOP_COSTUME_NAME] != "" | |
is_human_race_set = is_race_set and property_map[BOTTOM_RACE_NAME] == HUMAN_RACE_NAME | |
is_non_human_race_set = is_race_set and property_map[BOTTOM_RACE_NAME] != HUMAN_RACE_NAME | |
is_set = is_race_set or is_costume_set | |
property_map[SET_NAME] = SET_MATCHED_NAME if is_set else SET_MISMATCHED_NAME | |
if is_set: | |
if is_costume_set: | |
property_map[SET_TYPE_NAME] = SET_TYPE_COSTUME_NAME | |
elif is_human_race_set: | |
property_map[SET_TYPE_NAME] = SET_TYPE_HUMAN_RACE_NAME | |
elif is_non_human_race_set: | |
property_map[SET_TYPE_NAME] = SET_TYPE_NON_HUMAN_RACE_NAME | |
else: | |
property_map[SET_TYPE_NAME] = "" | |
else: | |
property_map[SET_TYPE_NAME] = "" | |
for key in property_map.keys(): | |
data["attributes"].append({ | |
"trait_type": key, | |
"value": property_map[key] | |
}) | |
data["description"] = "Chubbies are 10000 programmatically generated cute things living on the Ethereum Blockchain. Chubbies are cute and cuteness is justice, so Chubbies are JUSTICE." | |
data["external_url"] = "https://chubbies.io" | |
data["image"] = str(image_url) + str(index) + ".gif" | |
data["name"] = "Chubbies #" + str(index) | |
with open("./output/json/" + str(index), 'w') as f: | |
json.dump(data, f) | |
def main(): | |
num_tokens = 10000 #input("Enter number of GIFS to generate: ") | |
tic = time.perf_counter() | |
num_buckets = 10 | |
random.seed(0) | |
# Generate all properties | |
(property_maps, dedup_set) = gen_all_properties(int(num_tokens)) | |
print(f"We have {len(property_maps)} Chubbies ready to be made.") | |
print("Distributing all Lab-grown Sets....") | |
gen_all_sets(property_maps, dedup_set, num_buckets) | |
print("Creating Gods....") | |
incubate_lab_grown_chubby_gods(property_maps, dedup_set) | |
print("Duplicate Sanity Check....") | |
duplicate_sanity_check(property_maps) | |
# Generate all gifs | |
gen_all_gifs(property_maps) | |
print_insights(property_maps, num_buckets) | |
toc = time.perf_counter() | |
print(f"Ran Chubbies GIF generation in {toc - tic:0.4f} seconds") | |
# Ask for Image URL to override the external | |
image_url = "https://gateway.pinata.cloud/ipfs/QmNdNTQVE4BUpERFwVTxX2RwZNbTCSwQr5pZ83EJJsBfWW/" #input("Enter Image URL Prefix: ") | |
output_json(property_maps, image_url) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment