613 lines
18 KiB
Python
613 lines
18 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
import json
|
|
import pygame
|
|
from pygame import Vector2
|
|
import re
|
|
|
|
|
|
# Colors
|
|
PAGE_BACKGROUND_COLOR = "#d7bfa0"
|
|
NOT_SELECTED_COLOR = "#7f7260"
|
|
PAGE_BORDER_COLOR = "#c19d62"
|
|
BORDER_NOT_SELECTED_COLOR = "#76603c"
|
|
WORD_BORDER_COLOR = "#fffcf2"
|
|
WORD_SHADOW_COLOR = "#000000"
|
|
|
|
# Drawing constants
|
|
SCREEN_WIDTH = 5120
|
|
SCREEN_HEIGHT = 2880
|
|
|
|
PAGE_MARGIN = 30
|
|
PAGE_BORDER_RADIUS = 80
|
|
PAGE_BORDER_WIDTH = 20
|
|
|
|
WORD_WIDTH = 432
|
|
WORD_HEIGHT = 90
|
|
WORD_MARGIN = 20
|
|
WORD_BORDER_RADIUS = 60
|
|
WORD_BORDER_WIDTH = 8
|
|
WORD_FONT_SIZE = 44
|
|
WORD_SHADOW_SIZE = 8
|
|
|
|
GRID_WIDTH = 6
|
|
GRID_HEIGHT = 25
|
|
|
|
WORD_PAGE_WIDTH = PAGE_BORDER_WIDTH*2+(WORD_WIDTH+WORD_MARGIN)*GRID_WIDTH+WORD_MARGIN
|
|
WORD_PAGE_HEIGHT = SCREEN_HEIGHT-PAGE_MARGIN*2
|
|
|
|
TAB_WIDTH = 120
|
|
TAB_HEIGHT = 160
|
|
TAB_MARGIN = 30
|
|
TAB_POS = Vector2(WORD_PAGE_WIDTH+PAGE_MARGIN*2,PAGE_MARGIN)
|
|
|
|
TEXT_PAGE_POS = Vector2(WORD_PAGE_WIDTH+PAGE_MARGIN*2,TAB_HEIGHT+PAGE_MARGIN*2)
|
|
TEXT_PAGE_WIDTH = SCREEN_WIDTH-(WORD_PAGE_WIDTH+PAGE_MARGIN*3)
|
|
TEXT_PAGE_HEIGHT = SCREEN_HEIGHT-(TAB_HEIGHT+PAGE_MARGIN*3)
|
|
|
|
TEXT_MARGIN = 40
|
|
TEXT_TOP_MARGIN = 68
|
|
TEXT_WIDTH = TEXT_PAGE_WIDTH - PAGE_BORDER_WIDTH*2 - TEXT_MARGIN*2
|
|
TEXT_HEIGHT = TEXT_PAGE_HEIGHT - PAGE_BORDER_WIDTH*2 - TEXT_MARGIN*2
|
|
|
|
WORD_SLOT_SPACING = " "*16
|
|
WORD_SLOT_NUDGING = 25
|
|
WORD_SLOT_NUDGE_DOWN = -5
|
|
SLANT = 80
|
|
|
|
INDICATOR_SIZE = 80
|
|
INDICATOR_BORDER = 20
|
|
INDICATOR_MARGIN = 60
|
|
INDICATOR_POS = Vector2(TEXT_PAGE_WIDTH-(INDICATOR_SIZE+INDICATOR_MARGIN),TEXT_PAGE_HEIGHT-(INDICATOR_SIZE+INDICATOR_MARGIN))
|
|
|
|
class WordColor(Enum):
|
|
Red = 0 # Names
|
|
Green = 1 # Nouns
|
|
Lime = 2 # Numbers and such
|
|
Blue = 3 # Verbs
|
|
Grey = 4 # Other
|
|
Purple = 5 # Places
|
|
Yellow = 6 # Titles
|
|
Orange = 7 # Classes
|
|
|
|
def color(self):
|
|
return [
|
|
"#b03334",
|
|
"#6a5f31",
|
|
"#62a032",
|
|
"#297cb7",
|
|
"#767978",
|
|
"#623a75",
|
|
"#bda627",
|
|
"#b76c2d",
|
|
][self.value]
|
|
|
|
class SolvedState(Enum):
|
|
NotFinished = 0
|
|
Wrong = 1
|
|
AlmostCorrect = 2
|
|
Correct = 3
|
|
|
|
@dataclass
|
|
class Page():
|
|
visible: bool
|
|
text: None|str
|
|
position: Vector2
|
|
size: Vector2
|
|
slots: list[tuple[list[str],WordSlot]]
|
|
|
|
def solved(self):
|
|
if any([s[1].word is None for s in self.slots]):
|
|
return SolvedState.NotFinished
|
|
elif all([s[1].word.word in s[0] for s in self.slots]):
|
|
return SolvedState.Correct
|
|
elif sum([s[1].word.word in s[0] for s in self.slots]) >= len(self.slots)-2:
|
|
return SolvedState.AlmostCorrect
|
|
else:
|
|
return SolvedState.Wrong
|
|
|
|
@dataclass
|
|
class Word():
|
|
word: str
|
|
color: WordColor
|
|
page: None|Page
|
|
position: Vector2
|
|
slot: None|WordSlot = None
|
|
|
|
def copy(self):
|
|
return Word(self.word,self.color,self.page,self.position,self.slot)
|
|
|
|
@dataclass
|
|
class WordSlot():
|
|
colors: None|list[WordColor]
|
|
page: Page
|
|
position: Vector2
|
|
word: None|Word = None
|
|
|
|
def draw_page(page: Page, screen: pygame.surface.Surface, font: pygame.font.Font):
|
|
pygame.draw.rect(
|
|
screen,
|
|
PAGE_BACKGROUND_COLOR,
|
|
pygame.Rect(
|
|
page.position.x + PAGE_BORDER_WIDTH,
|
|
page.position.y + PAGE_BORDER_WIDTH,
|
|
page.size.x - PAGE_BORDER_WIDTH*2,
|
|
page.size.y - PAGE_BORDER_WIDTH*2
|
|
),
|
|
border_radius=PAGE_BORDER_RADIUS//2
|
|
)
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
PAGE_BORDER_COLOR,
|
|
pygame.Rect(page.position.x,page.position.y,page.size.x,page.size.y),
|
|
PAGE_BORDER_WIDTH, PAGE_BORDER_RADIUS
|
|
)
|
|
|
|
if page.text is not None:
|
|
for i, t in enumerate(page.text):
|
|
text = font.render(t,False,"#000000")
|
|
pos = Vector2(
|
|
page.position.x + PAGE_BORDER_WIDTH + TEXT_MARGIN,
|
|
page.position.y + PAGE_BORDER_WIDTH + TEXT_MARGIN + TEXT_TOP_MARGIN + i*(WORD_FONT_SIZE+TEXT_TOP_MARGIN)
|
|
)
|
|
if i == 0:
|
|
width,_ = text.get_size()
|
|
text = pygame.transform.scale2x(text)
|
|
pos.y = page.position.y + PAGE_BORDER_WIDTH + TEXT_MARGIN
|
|
pos.x = page.position.x + PAGE_BORDER_WIDTH + TEXT_MARGIN + (TEXT_WIDTH-width*2)//2
|
|
screen.blit(text,pos)
|
|
|
|
if page.slots != []:
|
|
pygame.draw.circle(
|
|
screen,
|
|
"#000000",
|
|
page.position + INDICATOR_POS,
|
|
INDICATOR_SIZE
|
|
)
|
|
status = page.solved()
|
|
if status == SolvedState.Correct:
|
|
color = WordColor.Lime.color()
|
|
elif status == SolvedState.AlmostCorrect:
|
|
color = WordColor.Yellow.color()
|
|
elif status == SolvedState.Wrong:
|
|
color = WordColor.Red.color()
|
|
else:
|
|
color = "#000000"
|
|
|
|
pygame.draw.circle(
|
|
screen,
|
|
color,
|
|
page.position + INDICATOR_POS,
|
|
INDICATOR_SIZE-INDICATOR_BORDER
|
|
)
|
|
|
|
|
|
def play_sound(page: Page):
|
|
click = pygame.mixer.Sound("click.wav")
|
|
click.set_volume(0.8)
|
|
click.play()
|
|
|
|
if page.slots != []:
|
|
status = page.solved()
|
|
if status == SolvedState.Correct:
|
|
sound = pygame.mixer.Sound("correct.wav")
|
|
elif status == SolvedState.AlmostCorrect:
|
|
sound = pygame.mixer.Sound("incorrect.wav")
|
|
elif status == SolvedState.Wrong:
|
|
sound = pygame.mixer.Sound("incorrect.wav")
|
|
else:
|
|
return
|
|
|
|
sound.play()
|
|
|
|
|
|
def draw_word_slot(word_slot: WordSlot, screen: pygame.surface.Surface):
|
|
pos = word_slot.page.position+word_slot.position
|
|
|
|
if word_slot.colors is None:
|
|
color = "#00000000"
|
|
else:
|
|
color = word_slot.colors[0].color()
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
color,
|
|
pygame.Rect(
|
|
pos.x + WORD_BORDER_WIDTH,
|
|
pos.y + WORD_BORDER_WIDTH,
|
|
WORD_WIDTH - WORD_BORDER_WIDTH*2,
|
|
WORD_HEIGHT - WORD_BORDER_WIDTH*2
|
|
),
|
|
border_radius=WORD_BORDER_RADIUS
|
|
)
|
|
|
|
if len(word_slot.colors) > 1:
|
|
pygame.draw.rect(
|
|
screen,
|
|
word_slot.colors[1].color(),
|
|
pygame.Rect(
|
|
pos.x + WORD_BORDER_WIDTH + WORD_WIDTH//4,
|
|
pos.y + WORD_BORDER_WIDTH,
|
|
(WORD_WIDTH*3)//4 - WORD_BORDER_WIDTH*2,
|
|
WORD_HEIGHT - WORD_BORDER_WIDTH*2
|
|
),
|
|
border_radius=WORD_BORDER_RADIUS
|
|
)
|
|
|
|
pygame.draw.polygon(
|
|
screen,
|
|
color,
|
|
[
|
|
(
|
|
pos.x + WORD_BORDER_WIDTH + WORD_WIDTH//4,
|
|
pos.y + WORD_BORDER_WIDTH
|
|
),
|
|
(
|
|
pos.x + WORD_BORDER_WIDTH + WORD_WIDTH//2 + SLANT//2,
|
|
pos.y + WORD_BORDER_WIDTH
|
|
),
|
|
(
|
|
pos.x + WORD_BORDER_WIDTH + WORD_WIDTH//2 - SLANT//2,
|
|
pos.y + WORD_BORDER_WIDTH + WORD_HEIGHT - WORD_BORDER_WIDTH*2 - 1
|
|
),
|
|
(
|
|
pos.x + WORD_BORDER_WIDTH + WORD_WIDTH//4,
|
|
pos.y + WORD_BORDER_WIDTH + WORD_HEIGHT - WORD_BORDER_WIDTH*2 - 1
|
|
),
|
|
]
|
|
)
|
|
|
|
def draw_word(word: Word, screen: pygame.surface.Surface, font: pygame.font.Font):
|
|
if word.page is not None:
|
|
pos = word.page.position+word.position
|
|
else:
|
|
pos = word.position
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
WORD_SHADOW_COLOR,
|
|
pygame.Rect(
|
|
pos.x,
|
|
pos.y + WORD_SHADOW_SIZE,
|
|
WORD_WIDTH,
|
|
WORD_HEIGHT
|
|
),
|
|
border_radius=WORD_BORDER_RADIUS
|
|
)
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
word.color.color(),
|
|
pygame.Rect(
|
|
pos.x + WORD_BORDER_WIDTH//2,
|
|
pos.y + WORD_BORDER_WIDTH//2,
|
|
WORD_WIDTH - WORD_BORDER_WIDTH,
|
|
WORD_HEIGHT - WORD_BORDER_WIDTH
|
|
),
|
|
border_radius=WORD_BORDER_RADIUS
|
|
)
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
WORD_BORDER_COLOR,
|
|
pygame.Rect(
|
|
pos.x,
|
|
pos.y,
|
|
WORD_WIDTH,WORD_HEIGHT
|
|
),
|
|
WORD_BORDER_WIDTH, WORD_BORDER_RADIUS
|
|
)
|
|
|
|
text = font.render(word.word,False,"#ffffff")
|
|
x,y = text.get_size()
|
|
screen.blit(text,(
|
|
pos.x+(WORD_WIDTH-x)//2,
|
|
pos.y+(WORD_HEIGHT-y)//2+1
|
|
))
|
|
|
|
def draw_tab(n: int, screen: pygame.surface.Surface, font: pygame.font.Font, selected: bool):
|
|
pos = TAB_POS + Vector2((TAB_WIDTH+TAB_MARGIN)*n,0)
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
PAGE_BACKGROUND_COLOR if selected else NOT_SELECTED_COLOR,
|
|
pygame.Rect(
|
|
pos.x+PAGE_BORDER_WIDTH//2,
|
|
pos.y+PAGE_BORDER_WIDTH//2,
|
|
TAB_WIDTH-PAGE_BORDER_WIDTH,
|
|
TAB_HEIGHT-PAGE_BORDER_WIDTH
|
|
)
|
|
)
|
|
|
|
pygame.draw.rect(
|
|
screen,
|
|
PAGE_BORDER_COLOR if selected else BORDER_NOT_SELECTED_COLOR,
|
|
pygame.Rect(
|
|
pos.x,
|
|
pos.y,
|
|
TAB_WIDTH,
|
|
TAB_HEIGHT
|
|
),
|
|
PAGE_BORDER_WIDTH//2, PAGE_BORDER_RADIUS//2
|
|
)
|
|
|
|
text = font.render(str(n+1),False,"#000000")
|
|
x,y = text.get_size()
|
|
screen.blit(text,(
|
|
pos.x+(TAB_WIDTH-x)//2,
|
|
pos.y+(TAB_HEIGHT-y)//2+1
|
|
))
|
|
|
|
|
|
def main(data: dict):
|
|
pygame.init()
|
|
pygame.font.init()
|
|
|
|
# music
|
|
pygame.mixer.music.load("Slight Delay.mp3")
|
|
pygame.mixer.music.set_volume(0.1)
|
|
pygame.mixer.music.play(-1)
|
|
|
|
font = pygame.font.SysFont("Comic Code",WORD_FONT_SIZE,True)
|
|
print(font.size(WORD_SLOT_SPACING))
|
|
screen = pygame.display.set_mode((1280, 720),pygame.RESIZABLE)
|
|
drawer = pygame.surface.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
clock = pygame.time.Clock()
|
|
running = True
|
|
|
|
word_page = Page(True,None,Vector2(PAGE_MARGIN,PAGE_MARGIN),Vector2(WORD_PAGE_WIDTH,WORD_PAGE_HEIGHT),[])
|
|
pages = [word_page] + [
|
|
Page(
|
|
False,
|
|
p,
|
|
TEXT_PAGE_POS,
|
|
Vector2(TEXT_PAGE_WIDTH,TEXT_PAGE_HEIGHT),
|
|
[]
|
|
) for p in data["pages"]
|
|
]
|
|
if len(pages) > 1:
|
|
pages[1].visible = True
|
|
visible_page = 1
|
|
else:
|
|
visible_page = 0
|
|
|
|
held_word = None
|
|
|
|
word_slots: list[WordSlot] = []
|
|
for y in range(GRID_HEIGHT):
|
|
for x in range(GRID_WIDTH):
|
|
word_slots.append(WordSlot(
|
|
None,
|
|
word_page,
|
|
Vector2(
|
|
PAGE_BORDER_WIDTH+WORD_MARGIN+(WORD_WIDTH+WORD_MARGIN)*x,
|
|
PAGE_BORDER_WIDTH+WORD_MARGIN+(WORD_HEIGHT+WORD_MARGIN)*y
|
|
)
|
|
))
|
|
|
|
def add_to_text(text,word,space=" "):
|
|
width, _ = font.size(text[-1]+space+word)
|
|
if width > TEXT_WIDTH:
|
|
return text+[word]
|
|
else:
|
|
if text[-1] == "":
|
|
space = ""
|
|
text[-1] += space+word
|
|
return text
|
|
|
|
for p in pages[1:]:
|
|
new_text = []
|
|
for t in p.text:
|
|
new_text.append("")
|
|
text_words = t.split(" ")
|
|
for w in text_words:
|
|
res = re.findall(r"([^\] ]*)\[(.*?)\/([\d\+]+)\]([^\[ ]*)",w)
|
|
if res == []:
|
|
new_text = add_to_text(new_text,w)
|
|
else:
|
|
if new_text[0] != "":
|
|
new_text = add_to_text(new_text,"")
|
|
|
|
for slot in res:
|
|
new_text = add_to_text(new_text,slot[0]+WORD_SLOT_SPACING+slot[3],"")
|
|
height = WORD_FONT_SIZE*len(new_text)
|
|
width, _ = font.size(new_text[-1])
|
|
extra_width, _ = font.size(slot[3])
|
|
pos = Vector2(
|
|
TEXT_MARGIN + width - extra_width - WORD_WIDTH,
|
|
TEXT_MARGIN + height - WORD_HEIGHT//2 + TEXT_TOP_MARGIN*len(new_text) + WORD_SLOT_NUDGE_DOWN
|
|
)
|
|
# if new_text[-1] != WORD_SLOT_SPACING+slot[2]:
|
|
pos.x += WORD_SLOT_NUDGING
|
|
new_slot = WordSlot([WordColor(int(i)) for i in slot[2].split("+")],p,pos)
|
|
word_slots.append(new_slot)
|
|
p.slots.append((slot[1].replace("%"," ").split("+"),new_slot))
|
|
|
|
p.text = new_text
|
|
|
|
|
|
words: list[Word] = []
|
|
for i,w in enumerate(data["words"]):
|
|
slot = word_slots[i]
|
|
word = Word(w[0],WordColor(w[1]),word_page,Vector2(slot.position.x,slot.position.y))
|
|
slot.word = word
|
|
word.slot = slot
|
|
words.append(word)
|
|
|
|
all_words = [w.word for w in words]
|
|
for p in pages:
|
|
not_present = [word for s in p.slots for word in s[0] if word not in all_words]
|
|
if not_present:
|
|
print(not_present)
|
|
|
|
def focused():
|
|
x, y = pygame.mouse.get_pos()
|
|
ratio_x = (screen.get_width() / drawer.get_width())
|
|
ratio_y = (screen.get_height() / drawer.get_height())
|
|
scaled_xy = (x/ratio_x,y/ratio_y)
|
|
for w in words:
|
|
if w.page is None:
|
|
return w
|
|
if not w.page.visible:
|
|
continue
|
|
|
|
pos = w.page.position+w.position
|
|
rect = pygame.Rect(
|
|
pos.x - WORD_MARGIN//2,
|
|
pos.y - WORD_MARGIN//2,
|
|
WORD_WIDTH + WORD_MARGIN,
|
|
WORD_HEIGHT + WORD_MARGIN
|
|
)
|
|
if rect.collidepoint(scaled_xy):
|
|
return w
|
|
|
|
for i in range(len(pages)-1):
|
|
pos = TAB_POS + Vector2((TAB_WIDTH+TAB_MARGIN)*i,0)
|
|
rect = pygame.Rect(
|
|
pos.x - TAB_MARGIN//2,
|
|
pos.y - TAB_MARGIN//2,
|
|
TAB_WIDTH + TAB_MARGIN,
|
|
TAB_HEIGHT + TAB_MARGIN
|
|
)
|
|
if rect.collidepoint(scaled_xy):
|
|
return i+1
|
|
|
|
return None
|
|
|
|
def click_slot():
|
|
nonlocal held_word
|
|
slot = None
|
|
x, y = pygame.mouse.get_pos()
|
|
ratio_x = (screen.get_width() / drawer.get_width())
|
|
ratio_y = (screen.get_height() / drawer.get_height())
|
|
scaled_xy = (x/ratio_x,y/ratio_y)
|
|
for w in word_slots:
|
|
if not w.page.visible:
|
|
continue
|
|
|
|
pos = w.page.position+w.position
|
|
rect = pygame.Rect(
|
|
pos.x - WORD_MARGIN//2,
|
|
pos.y - WORD_MARGIN//2,
|
|
WORD_WIDTH + WORD_MARGIN,
|
|
WORD_HEIGHT + WORD_MARGIN
|
|
)
|
|
if rect.collidepoint(scaled_xy):
|
|
slot = w
|
|
break
|
|
|
|
if slot is None:
|
|
if held_word is not None and held_word.slot.colors is not None:
|
|
words.remove(held_word)
|
|
held_word = None
|
|
return
|
|
|
|
if held_word is None and slot.word is not None:
|
|
held_word = slot.word
|
|
held_word.page = None
|
|
slot.word = None
|
|
elif held_word is not None and slot.word is None:
|
|
if slot.colors is not None and held_word.color not in slot.colors:
|
|
return
|
|
|
|
slot.word = held_word
|
|
if slot.colors is not None and held_word.slot.colors is None:
|
|
new_word = slot.word.copy()
|
|
new_word.page = slot.word.slot.page
|
|
new_word.position = slot.word.slot.position
|
|
new_word.slot = slot.word.slot
|
|
new_word.slot.word = new_word
|
|
words.append(new_word)
|
|
|
|
if slot.word.slot.colors is None or slot.colors is not None:
|
|
slot.word.position = slot.position
|
|
slot.word.page = slot.page
|
|
slot.word.slot = slot
|
|
else:
|
|
words.remove(slot.word)
|
|
slot.word = None
|
|
|
|
held_word = None
|
|
|
|
play_sound(slot.page)
|
|
|
|
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
click_slot()
|
|
i = focused()
|
|
if isinstance(i,int):
|
|
page_sound = pygame.mixer.Sound("page.wav")
|
|
page_sound.set_volume(0.7)
|
|
page_sound.play()
|
|
pages[visible_page].visible = False
|
|
visible_page = i
|
|
pages[visible_page].visible = True
|
|
elif event.type == pygame.QUIT:
|
|
running = False
|
|
|
|
# fill the screen with a color to wipe away anything from last frame
|
|
drawer.fill("#4d2905")
|
|
|
|
# Held word
|
|
if held_word is not None:
|
|
x, y = pygame.mouse.get_pos()
|
|
ratio_x = (screen.get_width() / drawer.get_width())
|
|
ratio_y = (screen.get_height() / drawer.get_height())
|
|
scaled_xy = (x/ratio_x,y/ratio_y)
|
|
held_word.position = Vector2(scaled_xy) - Vector2(WORD_WIDTH//2,WORD_HEIGHT//2)
|
|
|
|
# render pages
|
|
for p in pages:
|
|
if not p.visible:
|
|
continue
|
|
|
|
draw_page(p, drawer, font)
|
|
|
|
# drawing word slots
|
|
for w in word_slots:
|
|
if not w.page.visible or w.colors is None:
|
|
continue
|
|
|
|
draw_word_slot(w, drawer)
|
|
|
|
# drawing words
|
|
for w in words:
|
|
if w.page is not None and not w.page.visible and w != held_word:
|
|
continue
|
|
|
|
draw_word(w, drawer, font)
|
|
|
|
# drawing tabs
|
|
for i in range(len(pages)-1):
|
|
draw_tab(i,drawer,font,visible_page==i+1)
|
|
|
|
# drawing held word
|
|
if held_word is not None:
|
|
draw_word(held_word, drawer, font)
|
|
|
|
# Draw everything to the screen
|
|
frame = pygame.transform.scale(drawer,screen.get_size())
|
|
screen.blit(frame,frame.get_rect())
|
|
|
|
# if focused() is not None:
|
|
# pygame.mouse.set_cursor(*pygame.cursors.tri_left)
|
|
# else:
|
|
# pygame.mouse.set_cursor(*pygame.cursors.arrow)
|
|
|
|
# flip() the display to put your work on screen
|
|
pygame.display.flip()
|
|
|
|
clock.tick(60) # limits FPS to 60
|
|
|
|
pygame.quit()
|
|
|
|
if __name__ == "__main__":
|
|
with open("data.json","r") as file_pointer:
|
|
data = json.load(file_pointer)
|
|
|
|
main(data) |