From 95631b7b57545441e75b1c07063b3b4a1fb37caf Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Thu, 16 Jan 2025 22:58:24 +0100 Subject: [PATCH] :sparkles: --- data.json | 12 +++- main.py | 182 +++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 163 insertions(+), 31 deletions(-) diff --git a/data.json b/data.json index 2fce021..cbda3e2 100644 --- a/data.json +++ b/data.json @@ -1,6 +1,8 @@ { "words": [ ["Ansem",0], + ["Mickey",0], + ["Mouse",0], ["Terra",0], ["Terranort",0], ["Xehanort",0], @@ -8,14 +10,22 @@ ["apprentice",1], ["darkness",1], + ["door",1], + ["heart",1], + ["nobody",1], ["seeker",1], + ["shirt",1], ["killed",3], ["possessed",3], + ["ripped",3], + ["less",4], + ["off",4], ["wise",4] ], "pages": [ - "[Xehanort/0] [possessed/3] [Terra/0], which created [Terra/0]-[Xehanort/0], also known as [Terranort/0]. He became an [apprentice/1] to [Ansem/0] the [wise/4], and eventually split into the nobody [Xemnas/0] and the heartless [Ansem/0], [seeker/1] of [darkness/1]." + "[Xehanort/0] [possessed/3] [Terra/0], which created [Terra/0]-[Xehanort/0], also known as [Terranort/0]. He became an [apprentice/1] to [Ansem/0] the [wise/4], and eventually split into the [nobody/1] [Xemnas/0] and the [heart/1][less/4] [Ansem/0], [seeker/1] of [darkness/1].", + "[Mickey/0] [Mouse/0] was [shirt/1][less/4] at the end of Kingdom Hearts because his [shirt/1] had been [ripped/3] [off/4] by [heart/1][less/4] behind the [door/1] to [darkness/1]." ] } \ No newline at end of file diff --git a/main.py b/main.py index 26e3edd..2048ad2 100644 --- a/main.py +++ b/main.py @@ -9,8 +9,10 @@ import re # Colors -BACKGROUND_COLOR = "#d7bfa0" +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" @@ -22,8 +24,6 @@ PAGE_MARGIN = 20 PAGE_BORDER_RADIUS = 40 PAGE_BORDER_WIDTH = 20 -TAB_WIDTH = 80 -TAB_HEIGHT = 80 WORD_WIDTH = 228 WORD_HEIGHT = 55 @@ -39,6 +39,10 @@ GRID_HEIGHT = 18 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 = 80 +TAB_HEIGHT = 80 +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) @@ -51,12 +55,19 @@ TEXT_HEIGHT = TEXT_PAGE_HEIGHT - TEXT_MARGIN*2 WORD_SLOT_SPACING = " "*12 WORD_SLOT_NUDGING = 22 +INDICATOR_SIZE = 40 +INDICATOR_BORDER = 10 +INDICATOR_MARGIN = 30 +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 # Not used for words def color(self): return [ @@ -64,16 +75,34 @@ class WordColor(Enum): "#6a5f31", "#4b7a28", "#297cb7", - "#767978" + "#767978", + "#623a75", + "#f0de50", ][self.value] +class SolvedState(Enum): + NotFinished = 0 + Wrong = 1 + AlmostCorrect = 2 + Correct = 3 + @dataclass class Page(): visible: bool - color: str text: None|str position: Vector2 size: Vector2 + slots: list[tuple[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 == s[0] for s in self.slots]): + return SolvedState.Correct + elif sum([s[1].word.word == s[0] for s in self.slots]) >= len(self.slots)-2: + return SolvedState.AlmostCorrect + else: + return SolvedState.Wrong @dataclass class Word(): @@ -96,7 +125,7 @@ class WordSlot(): def draw_page(page: Page, screen: pygame.surface.Surface, font: pygame.font.Font): pygame.draw.rect( screen, - page.color, + PAGE_BACKGROUND_COLOR, pygame.Rect( page.position.x + PAGE_BORDER_WIDTH, page.position.y + PAGE_BORDER_WIDTH, @@ -121,6 +150,30 @@ def draw_page(page: Page, screen: pygame.surface.Surface, font: pygame.font.Font page.position.y + PAGE_BORDER_WIDTH + TEXT_MARGIN + TEXT_TOP_MARGIN + i*(WORD_FONT_SIZE+TEXT_TOP_MARGIN) )) + 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 draw_word_slot(word_slot: WordSlot, screen: pygame.surface.Surface): pos = word_slot.page.position+word_slot.position @@ -189,6 +242,40 @@ def draw_word(word: Word, screen: pygame.surface.Surface, font: pygame.font.Font 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+PAGE_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() @@ -198,14 +285,14 @@ def main(data: dict): clock = pygame.time.Clock() running = True - word_page = Page(True,BACKGROUND_COLOR,None,Vector2(PAGE_MARGIN,PAGE_MARGIN),Vector2(WORD_PAGE_WIDTH,WORD_PAGE_HEIGHT)) + word_page = Page(True,None,Vector2(PAGE_MARGIN,PAGE_MARGIN),Vector2(WORD_PAGE_WIDTH,WORD_PAGE_HEIGHT),[]) pages = [word_page] + [ Page( False, - BACKGROUND_COLOR, [p], TEXT_PAGE_POS, - Vector2(TEXT_PAGE_WIDTH,TEXT_PAGE_HEIGHT) + Vector2(TEXT_PAGE_WIDTH,TEXT_PAGE_HEIGHT), + [] ) for p in data["pages"] ] if len(pages) > 1: @@ -240,7 +327,7 @@ def main(data: dict): new_text = [""] text_words = p.text[0].split(" ") for w in text_words: - res = re.findall(r"\[(.*?)\/(\d)\](.)?",w) + res = re.findall(r"\[(.*?)\/(\d)\]([^\[])?",w) if res == []: new_text = add_to_text(new_text,w) else: @@ -258,7 +345,9 @@ def main(data: dict): ) # if new_text[-1] != WORD_SLOT_SPACING+slot[2]: pos.x += WORD_SLOT_NUDGING - word_slots.append(WordSlot(WordColor(int(slot[1])),p,pos)) + new_slot = WordSlot(WordColor(int(slot[1])),p,pos) + word_slots.append(new_slot) + p.slots.append((slot[0],new_slot)) p.text = new_text @@ -278,19 +367,33 @@ def main(data: dict): 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, - pos.y - WORD_MARGIN, - WORD_WIDTH + WORD_MARGIN*2, - WORD_HEIGHT + WORD_MARGIN*2 + 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+PAGE_MARGIN)*i,0) + rect = pygame.Rect( + pos.x - PAGE_MARGIN//2, + pos.y - PAGE_MARGIN//2, + TAB_WIDTH + PAGE_MARGIN, + TAB_HEIGHT + PAGE_MARGIN + ) + if rect.collidepoint(scaled_xy): + return i+1 + return None - def click(): + def click_slot(): nonlocal held_word slot = None x, y = pygame.mouse.get_pos() @@ -298,49 +401,63 @@ def main(data: dict): 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, - pos.y - WORD_MARGIN, - WORD_WIDTH + WORD_MARGIN*2, - WORD_HEIGHT + WORD_MARGIN*2 + 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.color is not None: + words.remove(held_word) + held_word = None return if held_word is None and slot.word is not None: - if slot.color is None: - held_word = slot.word - held_word.page = None - else: - words.remove(slot.word) + held_word = slot.word + held_word.page = None slot.word = None elif held_word is not None and slot.word is None: if slot.color is not None and slot.color != held_word.color: return slot.word = held_word - if slot.color is not None: + if slot.color is not None and held_word.slot.color 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) - slot.word.position = slot.position - slot.word.page = slot.page - slot.word.slot = slot + + if slot.word.slot.color is None or slot.color 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 while running: for event in pygame.event.get(): if event.type == pygame.MOUSEBUTTONUP: - click() + click_slot() + i = focused() + if isinstance(i,int): + pages[visible_page].visible = False + visible_page = i + pages[visible_page].visible = True elif event.type == pygame.QUIT: running = False @@ -376,6 +493,11 @@ def main(data: dict): 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)