Михаил Капелько 4 months ago
parent
commit
814091260c
27 changed files with 2224 additions and 0 deletions
  1. +222
    -0
      harm/cli.py
  2. +303
    -0
      harm/cli_test.py
  3. +53
    -0
      harm/ctx.py
  4. +142
    -0
      harm/ctx_test2.py
  5. +317
    -0
      harm/desktop.py
  6. +22
    -0
      harm/desktop_Platform.py
  7. +35
    -0
      harm/desktop_SequentialTimer.py
  8. +32
    -0
      harm/desktop_Window.py
  9. +13
    -0
      harm/desktop_aux.py
  10. +175
    -0
      harm/gui.py
  11. +15
    -0
      harm/gui_TextureDescription.py
  12. +78
    -0
      harm/gui_aux.py
  13. +15
    -0
      harm/gui_aux_test.py
  14. +49
    -0
      harm/gui_test.py
  15. +22
    -0
      harm/llm.py
  16. +31
    -0
      harm/llm_test.py
  17. +21
    -0
      harm/llm_test_Python.py
  18. +160
    -0
      harm/main-gui.py
  19. +77
    -0
      harm/main.py
  20. +138
    -0
      harm/memory.py
  21. +71
    -0
      harm/memory_Context.py
  22. +231
    -0
      harm/memory_test.py
  23. BIN
      harm/res/harm.png
  24. BIN
      harm/res/harmful-tiles.png
  25. BIN
      harm/res/harmful-titles.png
  26. BIN
      harm/res/splash.png
  27. +2
    -0
      harm/run-gui-py

+ 222
- 0
harm/cli.py View File

@@ -0,0 +1,222 @@
from memory_Context import *
from llm import *

# Exit
#
# Conditions:
# 1. `e`, `exit`, `q`, or `quit` was entered
# 2. Victory has just been reported
@llm_by_value
def cli_exit(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "input" and
(
c.input == "e" or
c.input == "exit" or
c.input == "q" or
c.input == "quit"
)
):
c.exit = True
c.recentField = "exit"
return c
#}
if (
c.recentField == "outputVictory"
):
c.exit = True
c.recentField = "exit"
return c
#}
c.recentField = "none"
return c
#}

# Ask user to go on
#
# Conditions:
# 1. Items have just matched and there are still items left to select
@llm_by_value
def cli_goOn(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "outputMatchedItems" and
len(c.hiddenItems) != len(c.playfieldItems)
):
c.outputGoOn = "Go on:"
c.recentField = "outputGoOn"
return c
#}
c.recentField = "none"
return c
#}

# Greet the user
#
# Conditions:
# 1. Just launched
@llm_by_value
def cli_greetUser(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "didLaunch" and
c.didLaunch == True
):
c.outputGreeting = "OGS Memory Command Line Interface"
c.recentField = "outputGreeting"
return c
#}
c.recentField = "none"
return c
#}

# Ask user to select second item to have a pair of selected items
#
# Conditions:
# 1. Single item has just been selected
@llm_by_value
def cli_promptSecondItemSelection(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "selectedItems" and
len(c.selectedItems) == 1
):
c.outputPromptSelection = "Select the second item now:"
c.recentField = "outputPromptSelection"
return c
#}
c.recentField = "none"
return c
#}

# Report matched items
#
# Conditions:
# 1. Items were hidden (i.e., they matched)
@llm_by_value
def cli_reportMatchedItems(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "hiddenItems"
):
c.outputMatchedItems = "Items matched!"
c.recentField = "outputMatchedItems"
return c
#}
c.recentField = "none"
return c
#}

# Report victory
@llm_by_value
def cli_reportVictory(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "victory"
):
c.outputVictory = "VICTORY! The game is over now"
c.recentField = "outputVictory"
return c
#}
c.recentField = "none"
return c
#}

# Select item
#
# Conditions:
# 1. Id is digit
@llm_by_value
def cli_selectItem(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "input" and
llm_isDigit(c.input)
):
# CLI ids start with 1 while memory module has ids starting with 0
# Convert CLI id to memory id
c.selectedId = llm_strToInt(c.input) - 1
c.recentField = "selectedId"
return c
#}
c.recentField = "none"
return c
#}

# Show help (aka commands)
#
# Conditions:
# 1. Just launched
# 1. `h` or `help` was entered
@llm_by_value
def cli_showHelp(
c: memory_Context
) -> memory_Context:
if (
(
c.recentField == "didLaunch" and
c.didLaunch == True
) or
(
c.recentField == "input" and
c.input == "h"
) or
(
c.recentField == "input" and
c.input == "help"
)
):
c.outputHelp = "Commands:\n\te, exit, q, quit\n\t\tExit\n\th, help\n\t\tList commands\n\t1, 2, 3, ...\n\t\tSelect item\nEnter your choice:"
c.recentField = "outputHelp"
return c
#}
c.recentField = "none"
return c
#}

# Report mismatched items
@llm_by_value
def cli_reportMismatchedItems(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "mismatchedItems"
):
c.outputMismatchedItems = "Wrong! Try again:"
c.recentField = "outputMismatchedItems"
return c
#}
c.recentField = "none"
return c
#}

## Report selection of invalid item ids
##
## Conditions:
## 1. Index out of bounds: less than minimum
## 2. Index out of bounds: greater than maximum
## 3. Item is already hidden
##@llm_by_value
##def cli_shouldReportInvalidItemSelection(
## c: cli_Context
##) -> cli_Context:
## if (
## c.recentField == "cMemory" and
## c.cMemory.recentField == "selectedItems" and
## len(c.cMemory.selectedItems) == 1
## ):
## c.outputPromptSelection = "Select the second item now:"
## c.recentField = "outputPromptSelection"
## return c
## #}
## c.recentField = "none"
## return c
###}

+ 303
- 0
harm/cli_test.py View File

@@ -0,0 +1,303 @@
from cli import *
from memory import *
from memory_Context import *

def cli_test_exit_e(
) -> str:
c = memory_createContext()
c.input = "e"
c.recentField = "input"
c = cli_exit(c)
if (
c.recentField == "exit"
):
return "OK: cli_exit_e"
#}
return "ERR: cli_exit_e"
#}

def cli_test_exit_exit(
) -> str:
c = memory_createContext()
c.input = "exit"
c.recentField = "input"
c = cli_exit(c)
if (
c.recentField == "exit"
):
return "OK: cli_exit_exit"
#}
return "ERR: cli_exit_e"
#}

def cli_test_exit_victory(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Match the first pair of tiles.
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "2"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)

# Match the second pair of tiles.
c.input = "3"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "4"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)
c = memory_detectVictory(c)
c = cli_reportVictory(c)
c = cli_exit(c)

if (
c.recentField == "exit"
):
return "OK: cli_exit_victory"
#}
return "ERR: cli_exit_victory"
#}

def cli_test_exit_q(
) -> str:
c = memory_createContext()
c.input = "q"
c.recentField = "input"
c = cli_exit(c)
if (
c.recentField == "exit"
):
return "OK: cli_exit_q"
#}
return "ERR: cli_exit_q"
#}

def cli_test_exit_quit(
) -> str:
c = memory_createContext()
c.input = "quit"
c.recentField = "input"
c = cli_exit(c)
if (
c.recentField == "exit"
):
return "OK: cli_exit_quit"
#}
return "ERR: cli_exit_quit"
#}

def cli_test_goOn(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Match the first pair of items.
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "2"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)
c = cli_reportMatchedItems(c)

c = cli_goOn(c)
if (
c.recentField == "outputGoOn"
):
return "OK: cli_goOn"
#}
return "ERR: cli_goOn"
#}

def cli_test_greetUser(
) -> str:
c = memory_createContext()
c.didLaunch = True
c.recentField = "didLaunch"
c = cli_greetUser(c)
if (
c.recentField == "outputGreeting"
):
return "OK: cli_greetUser"
#}
return "ERR: cli_greetUser"
#}

def cli_test_promptSecondItemSelection(
) -> str:
c = memory_createContext()
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = cli_promptSecondItemSelection(c)
if (
c.recentField == "outputPromptSelection"
):
return "OK: cli_promptSecondItemSelection"
#}
return "ERR: cli_promptSecondItemSelection"
#}

def cli_test_reportMatchedItems(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "2"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)
c = cli_reportMatchedItems(c)
if (
c.recentField == "outputMatchedItems"
):
return "OK: cli_reportMatchedItems"
#}
return "ERR: cli_reportMatchedItems"
#}

def cli_test_reportMismatchedItems(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "3"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_detectMismatchedItems(c)
c = cli_reportMismatchedItems(c)
if (
c.recentField == "outputMismatchedItems"
):
return "OK: cli_reportMismatchedItems"
#}
return "ERR: cli_reportMismatchedItems"
#}

def cli_test_selectItem(
) -> str:
c = memory_createContext()
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
if (
c.recentField == "selectedId" and
c.selectedId == 0
):
return "OK: cli_selectItem"
#}
return "ERR: cli_selectItem"
#}

def cli_test_showHelp_h(
) -> str:
c = memory_createContext()
c.input = "h"
c.recentField = "input"
c = cli_showHelp(c)
if (
c.recentField == "outputHelp"
):
return "OK: cli_showHelp_h"
#}
return "ERR: cli_showHelp_h"
#}

def cli_test_showHelp_help(
) -> str:
c = memory_createContext()
c.input = "help"
c.recentField = "input"
c = cli_showHelp(c)
if (
c.recentField == "outputHelp"
):
return "OK: cli_showHelp_help"
#}
return "ERR: cli_showHelp_help"
#}

def cli_test_reportVictory(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Match the first pair of tiles.
c.input = "1"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "2"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)

# Match the second pair of tiles.
c.input = "3"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c.input = "4"
c.recentField = "input"
c = cli_selectItem(c)
c = memory_selectItem(c)
c = memory_hideMatchingItems(c)
c = memory_detectVictory(c)
c = cli_reportVictory(c)

if (
c.recentField == "outputVictory"
):
return "OK: cli_reportVictory"
#}
return "ERR: cli_reportVictory"
#}

#def cli_test_shouldReportIvalidItemSelection_outOfBoundsMin(
#) -> str:
# c = cli_createContext()
# c.cMemory = memory_createContext()
# c.input = "0"
# c = cli_selectItem(c)
# c = cli_shouldReportInvalidItemSelection(c)
# if (
# c.recentField == "outputInvalidItemSelection"
# ):
# return "OK: cli_shouldReportInvalidItemSelection"
# #}
# return "ERR: cli_shouldReportInvalidItemSelection"
##}
#

+ 53
- 0
harm/ctx.py View File

@@ -0,0 +1,53 @@
import copy

class ctx_Controller:
def __init__(self, c):
self.callbacks = []
self.context = c
self.functions = []
self.isProcessingQueue = False
self.queue = []
def executeFunctions(self):
c = self.queue.pop(0)
for f in self.functions:
ctx = f(c)
if ctx.recentField != "none":
self.queue.append(ctx)

self.context.recentField = c.recentField
self.context.setField(c.recentField, c.field(c.recentField))
self.reportContext()

def processQueue(self):
# Decline recursion.
if self.isProcessingQueue:
return
self.isProcessingQueue = True
while len(self.queue) > 0:
self.executeFunctions()
self.isProcessingQueue = False

def registerCallback(self, cb):
self.callbacks.append(cb)

def registerFieldCallback(self, fieldName, cb):
self.callbacks.append(lambda c: cb(c) if c.recentField == fieldName else None)

def registerFunction(self, f):
self.functions.append(f)

def registerFunctions(self, funcs):
for f in funcs:
self.functions.append(f)

def reportContext(self):
for cb in self.callbacks:
cb(self.context)

def set(self, fieldName, value):
c = copy.deepcopy(self.context)
c.setField(fieldName, value)
c.recentField = fieldName
self.queue.append(c)
self.processQueue()

+ 142
- 0
harm/ctx_test2.py View File

@@ -0,0 +1,142 @@
from ctx import *
from memory import *
from memory_Context import *

def ctx_test_Controller_executeFunctions_registerFunction_set(
) -> str:
c = memory_createContext()
ctrl = ctx_Controller(c)
# Disable automatic invocation of executeFunctions.
ctrl.isProcessingQueue = True
ctrl.set("input", "123")

@llm_by_value
def processInput(c):
if (
c.recentField == "input"
):
c.outputHelp = "Checked"
c.recentField = "outputHelp"
return c
#}
c.recentField = "none"
return c
#}

ctrl.registerFunction(processInput)
# Apply 'input'.
ctrl.executeFunctions()
# Apply 'outputHelp'.
ctrl.executeFunctions()
if (
c.input == "123" and
c.outputHelp == "Checked"
):
return "OK: ctx_Controller_executeFunctions_set"
#}
return "ERR: ctx_Controller_executeFunctions_set"
#}

def ctx_test_Controller_processQueue(
) -> str:
c = memory_createContext()
ctrl = ctx_Controller(c)

@llm_by_value
def processInput(c):
if (
c.recentField == "input"
):
c.outputHelp = "Checked"
c.recentField = "outputHelp"
return c
#}
c.recentField = "none"
return c
#}

ctrl.registerFunction(processInput)
ctrl.set("input", "abc");
if (
c.input == "abc" and
c.outputHelp == "Checked"
):
return "OK: ctx_Controller_processQueue"
#}
return "ERR: ctx_Controller_processQueue"
#}

def ctx_test_Controller_registerFieldCallback_match(
) -> str:
c = memory_createContext()
ctrl = ctx_Controller(c)
c.input = "123"
c.recentField = "input"
globals()["callbackInput"] = ""
def setCallbackInput(c):
if (
c.recentField == "input"
):
globals()["callbackInput"] = c.input

ctrl.registerFieldCallback("input", setCallbackInput)
ctrl.reportContext()
if (
c.input == globals()["callbackInput"]
):
return "OK: ctx_Controller_registerFieldCallback_match"
#}
return "ERR: ctx_Controller_registerFieldCallback_match"
#}

def ctx_test_Controller_registerFieldCallback_mismatch(
) -> str:
c = memory_createContext()
ctrl = ctx_Controller(c)
c.input = "123"
c.outputHelp = "you"
# A field other than 'input' is marked recent.
c.recentField = "outputHelp"

globals()["callbackInput"] = ""
def setCallbackInput(c):
if (
c.recentField == "input"
):
globals()["callbackInput"] = c.input

ctrl.registerFieldCallback("input", setCallbackInput)
ctrl.reportContext()
if (
globals()["callbackInput"] == ""
):
return "OK: ctx_Controller_registerFieldCallback_mismatch"
#}
return "ERR: ctx_Controller_registerFieldCallback_mismatch"
#}

def ctx_test_memoryContext_field(
) -> str:
c = memory_createContext()
c.input = "abc"
if (
c.field("input") == "abc"
):
return "OK: ctx_memoryContext_field"
#}
return "ERR: ctx_memoryContext_field"
#}

def ctx_test_memoryContext_setField(
) -> str:
c = memory_createContext()
c.input = "abc"
c.setField("input", "123")
if (
c.input == "123"
):
return "OK: ctx_memoryContext_setField"
#}
return "ERR: ctx_memoryContext_setField"
#}

+ 317
- 0
harm/desktop.py View File

@@ -0,0 +1,317 @@
import arcade
from gui_aux import *
from desktop_Platform import *

def desktop_createDesc(p):
p.desc = arcade.Sprite()
p.descSprites.append(p.desc)
p.desc.texture = p.descTextures[0]
# Position.
pos = gui_aux_cellScreenPosition(p.c, p.c.descPosition)
p.desc.left = pos[0]
p.desc.top = pos[1]
# Invisible by default.
p.desc.visible = False
#}

def desktop_createDeselectedTiles(p):
for (id, pos) in enumerate(p.c.tilePositions):
tile = arcade.AnimatedTimeBasedSprite()
p.deselectedTiles.append(tile)
p.deselectedSprites.append(tile)

tile.guid = id
tile.texture = p.textures[0]
# Animation between two textures.
a1 = arcade.sprite.AnimationKeyframe(0, 700, p.textures[0])
a2 = arcade.sprite.AnimationKeyframe(1, 700, p.textures[1])
tile.frames.append(a1)
tile.frames.append(a2)
# Position.
tile.left = pos[0]
tile.top = pos[1]
#}
#}

def desktop_createSelectedTiles(p):
for (id, pos) in enumerate(p.c.tilePositions):
tile = arcade.Sprite()
p.selectedTiles.append(tile)
p.selectedSprites.append(tile)

tile.guid = id
tile.texture = p.textures[2 + p.c.playfieldItems[id]]
# Position.
tile.left = pos[0]
tile.top = pos[1]
# Invisible by default.
tile.visible = False
#}
#}

def desktop_createSplash(p):
p.splash = arcade.Sprite()
p.splashSprites.append(p.splash)
p.splash.texture = p.splashTextures[0]
# Position.
pos = gui_aux_cellScreenPosition(p.c, [0, 0])
p.splash.left = pos[0]
p.splash.top = pos[1]
#}

def desktop_createTitle(p):
p.title = arcade.Sprite()
p.titleSprites.append(p.title)
p.title.texture = p.titleTextures[0]
# Position.
pos = gui_aux_cellScreenPosition(p.c, p.c.titlePosition)
p.title.left = pos[0]
p.title.top = pos[1]
# Invisible by default.
p.title.visible = False
#}

# Deselect mismatched tiles
#
# Conditions:
# 1. Time to deselect mismatched items
def desktop_deselectMismatchedTiles(p):
if (
p.c.recentField == "deselectMismatchedTiles"
):
for id in p.c.mismatchedItems:
p.deselectedTiles[id].visible = True
p.selectedTiles[id].visible = False
#}
#}
#}

# Display description for the first selected tile
#
# Conditions:
# 1. tile has just been selected and it's the first one in pair
def desktop_displayDesc(p):
if (
p.c.recentField == "selectedId" and
(
len(p.c.selectedItems) == 0 or
len(p.c.selectedItems) == 2
)
):
gid = p.c.playfieldItems[p.c.selectedId]
p.desc.texture = p.descTextures[gid]
p.desc.visible = True
#}
#}

# Display ending splash screen
#
# Conditions:
# 1. Time to display victory screen
def desktop_displayEndingSplashScreen(p):
if (
p.c.recentField == "displayEndingSplashScreen"
):
p.splash.texture = p.splashTextures[1]
p.splash.visible = True
#}
#}

# Hide deselected tile and show selected one
#
# Conditions:
# 1. tile has just been selected
def desktop_displaySelectedTile(p):
if (
p.c.recentField == "selectedId"
):
id = p.c.selectedId
p.deselectedTiles[id].visible = False
p.selectedTiles[id].visible = True
#}
#}

# Display title for the first selected tile
#
# Conditions:
# 1. tile has just been selected and it's the first one in pair
def desktop_displayTitle(p):
if (
p.c.recentField == "selectedId" and
(
len(p.c.selectedItems) == 0 or
len(p.c.selectedItems) == 2
)
):
gid = p.c.playfieldItems[p.c.selectedId]
p.title.texture = p.titleTextures[gid]
p.title.visible = True
#}
#}

# Hide beginning splash screen
#
# Conditions:
# 1. Time to hide
def desktop_hideBeginningSplashScreen(p):
if (
p.c.recentField == "hideBeginningSplashScreen"
):
p.splash.visible = False
#}
#}

# Hide description
#
# Conditions:
# 1. tiles has been mismatched or timed out to to hide after matching
def desktop_hideDesc(p):
if (
p.c.recentField == "hideMatchingTiles" or
p.c.recentField == "mismatchedItems"
):
p.desc.visible = False
#}
#}

# Hide matching tiles
#
# Conditions:
# 1. Time to hide matching items
def desktop_hideMatchingTiles(p):
if (
p.c.recentField == "hideMatchingTiles"
):
for id in p.c.selectedItems:
p.deselectedTiles[id].visible = False
p.selectedTiles[id].visible = False
#}
#}
#}

# Hide title
#
# Conditions:
# 1. tiles has been mismatched or timed out to to hide after matching
def desktop_hideTitle(p):
if (
p.c.recentField == "hideMatchingTiles" or
p.c.recentField == "mismatchedItems"
):
p.title.visible = False
#}
#}

# Load description textures
def desktop_loadDescTextures(p):
texs = []
for (id, td) in enumerate(p.c.descTextureDescriptions):
tex = arcade.load_texture(
td.fileName,
x = td.x,
y = td.y,
width = td.width,
height = td.height
)
texs.append(tex)
#}
p.descTextures = texs
#}

# Load beginning and ending textures
def desktop_loadSplashTextures(p):
texs = []
for (id, td) in enumerate(p.c.splashTextureDescriptions):
tex = arcade.load_texture(
td.fileName,
x = td.x,
y = td.y,
width = td.width,
height = td.height
)
texs.append(tex)
print(f"desktop_loadST: '{tex}'")
#}
p.splashTextures = texs
#}

# Load tile textures
def desktop_loadTextures(p):
texs = []
for (id, td) in enumerate(p.c.textureDescriptions):
tex = arcade.load_texture(
td.fileName,
x = td.x,
y = td.y,
width = td.width,
height = td.height
)
texs.append(tex)
#}
p.textures = texs
#}

# Load tiTLe textures
def desktop_loadTitleTextures(p):
texs = []
for (id, td) in enumerate(p.c.titleTextureDescriptions):
tex = arcade.load_texture(
td.fileName,
x = td.x,
y = td.y,
width = td.width,
height = td.height
)
texs.append(tex)
#}
p.titleTextures = texs
#}

# Postpone deselection of mismatched tiles for better UX
#
# Conditions:
# 1. a pair of tiles has been mismatched
def desktop_scheduleDeselectionOfMismatchedTiles(p):
if (
p.c.recentField == "mismatchedItems"
):
p.sequentialTimer.schedule("deselectMismatchedTiles", True, p.c.deselectMismatchedTilesDelay)
#}
#}

# Postpone display of the ending splash screen
#
# Conditions:
# 1. just finished removing all tiles
def desktop_scheduleDisplayOfEndingSplashScreen(p):
if (
p.c.recentField == "victory"
):
p.sequentialTimer.schedule("displayEndingSplashScreen", True, p.c.splashEndDelay)
#}
#}

# Postpone hiding of matching tiles for better UX
#
# Conditions:
# 1. a pair of tiles has been matched
def desktop_scheduleHidingOfMatchingTiles(p):
if (
p.c.recentField == "hiddenItems"
):
p.sequentialTimer.schedule("hideMatchingTiles", True, p.c.hideMatchingTilesDelay)
#}
#}

# Postpone hiding of the beginning splash screen
#
# Conditions:
# 1. just launched the game
def desktop_scheduleHidingOfBeginningSplashScreen(p):
if (
p.c.recentField == "splashBeginTimeout"
):
p.sequentialTimer.schedule("hideBeginningSplashScreen", True, p.c.splashBeginTimeout)
#}
#}


+ 22
- 0
harm/desktop_Platform.py View File

@@ -0,0 +1,22 @@
import arcade

class desktop_Platform:
def __init__(self):
self.c = None
self.ctrl = None
self.desc = None
self.descSprites = arcade.SpriteList()
self.descTextures = []
self.deselectedSprites = arcade.SpriteList()
self.deselectedTiles = []
self.mousePosition = []
self.selectedTiles = []
self.sequentialTimer = None
self.selectedSprites = arcade.SpriteList()
self.splash = None
self.splashSprites = arcade.SpriteList()
self.splashTextures = []
self.textures = []
self.title = None
self.titleSprites = arcade.SpriteList()
self.titleTextures = []

+ 35
- 0
harm/desktop_SequentialTimer.py View File

@@ -0,0 +1,35 @@
import time

class desktop_SequentialTimer():
def __init__(self):
self.activeTimeout = None
self.callback = None
self.queue = []
#}

def update(self):
# Get current time in milliseconds.
now = time.time_ns() // 1000000

# Schedule an item.
if (
self.activeTimeout == None and
len(self.queue) > 0
):
self.activeTimeout = now + self.queue[0][0]
elif (
self.activeTimeout != None and
now >= self.activeTimeout
):
# Report when the time is up.
key = self.queue[0][1]
value = self.queue[0][2]
self.queue.pop(0)
self.activeTimeout = None
self.callback(key, value)
#}
#}

def schedule(self, key, value, timeout):
self.queue.append([timeout, key, value])
#}

+ 32
- 0
harm/desktop_Window.py View File

@@ -0,0 +1,32 @@
import arcade
from desktop_aux import *

class desktop_Window(arcade.Window):
def __init__(self, p):
super().__init__(
p.c.windowWidth,
p.c.windowHeight,
p.c.windowTitle,
)
self.antialiasing = p.c.windowAntialiasing
self.background_color = arcade.color_from_hex_string(p.c.windowBackgroundColor)
self.p = p

def on_draw(self):
arcade.start_render()
self.p.descSprites.draw()
self.p.deselectedSprites.draw()
self.p.selectedSprites.draw()
self.p.splashSprites.draw()
self.p.titleSprites.draw()

def on_mouse_press(self, x, y, button, key_modifiers):
id = desktop_aux_tileIdAt(self.p, x, y)
if (
id != None
):
self.p.ctrl.set("selectedId", id)

def on_update(self, delta):
self.p.deselectedSprites.update_animation()
self.p.sequentialTimer.update()

+ 13
- 0
harm/desktop_aux.py View File

@@ -0,0 +1,13 @@
import arcade

# Find a visible tile id at the specified location
def desktop_aux_tileIdAt(p, x, y):
sprites = arcade.get_sprites_at_point([x, y], p.deselectedSprites)
if (
len(sprites) != 0 and
sprites[0].visible
):
return sprites[0].guid
#}
return None
#}

+ 175
- 0
harm/gui.py View File

@@ -0,0 +1,175 @@
from gui_aux import *
from gui_TextureDescription import *
from llm import *
from memory_Context import *

# Generate texture descriptions for harm description
#
# Conditions:
# 1.descImage, descImageCount, descImageHeight, or descImageWidth has just changed
@llm_by_value
def gui_generateDescTextureDescriptions(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "descImage" or
c.recentField == "descImageCount" or
c.recentField == "descImageHeight" or
c.recentField == "descImageWidth"
):
tds: list[gui_TextureDescription] = []
for id in range(0, c.descImageCount):
td = gui_createTextureDescription()
td.fileName = c.descImage
td.height = c.descImageHeight
td.width = c.descImageWidth
td.x = id * c.descImageWidth
td.y = 0
tds.append(td)
#}
c.descTextureDescriptions = tds
c.recentField = "descTextureDescriptions"
return c
#}

c.recentField = "none"
return c
#}

# Generate texture descriptions for splash screens
#
# Conditions:
# 1.splashImage, splashImageCount, splashImageHeight, or splashImageWidth has just changed
@llm_by_value
def gui_generateSplashTextureDescriptions(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "splashImage" or
c.recentField == "splashImageCount" or
c.recentField == "splashImageHeight" or
c.recentField == "splashImageWidth"
):
tds: list[gui_TextureDescription] = []
for id in range(0, c.splashImageCount):
td = gui_createTextureDescription()
td.fileName = c.splashImage
td.height = c.splashImageHeight
td.width = c.splashImageWidth
td.x = id * c.splashImageWidth
td.y = 0
tds.append(td)
#}
c.splashTextureDescriptions = tds
c.recentField = "splashTextureDescriptions"
return c
#}

c.recentField = "none"
return c
#}

# Generate texture descriptions for tiles
#
# Conditions:
# 1. tileImage or tileImageCount or tileImageHeight or tileImageWidth has just changed
@llm_by_value
def gui_generateTextureDescriptions(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "tileImage" or
c.recentField == "tileImageCount" or
c.recentField == "tileImageHeight" or
c.recentField == "tileImageWidth"
):
tds: list[gui_TextureDescription] = []
for id in range(0, c.tileImageCount):
td = gui_createTextureDescription()
td.fileName = c.tileImage
td.height = c.tileImageHeight
td.width = c.tileImageWidth
td.x = id * c.tileImageWidth
td.y = 0
tds.append(td)
#}
c.textureDescriptions = tds
c.recentField = "textureDescriptions"
return c
#}

c.recentField = "none"
return c
#}

# Generate tile positions
#
# Conditions:
# 1. cellSize, playField, windowHeight, or windowWidth has changed and none of them is zero
@llm_by_value
def gui_generateTilePositions(
c: memory_Context
) -> memory_Context:
if (
(
c.recentField != "cellPositions" and
c.recentField != "cellSize" and
c.recentField != "playfieldSize" and
c.recentField != "windowHeight" and
c.recentField != "windowWidth"
) or
(
len(c.cellPositions) == 0 or
c.cellSize == 0 or
c.playfieldSize == 0 or
c.windowHeight == 0 or
c.windowWidth == 0
)
):
c.recentField = "none"
return c
#}

ps = []
for i in range(0, len(c.cellPositions)):
p = gui_aux_cellScreenPosition(c, c.cellPositions[i])
ps.append(p)
#}

c.tilePositions = ps
c.recentField = "tilePositions"
return c
#}

# Generate texture descriptions for tiTLes
#
# Conditions:
# 1. titleImage, titleImageCount, titleImageHeight, or titleImageWidth has just changed
@llm_by_value
def gui_generateTitleTextureDescriptions(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "titleImage" or
c.recentField == "titleImageCount" or
c.recentField == "titleImageHeight" or
c.recentField == "titleImageWidth"
):
tds: list[gui_TextureDescription] = []
for id in range(0, c.titleImageCount):
td = gui_createTextureDescription()
td.fileName = c.titleImage
td.height = c.titleImageHeight
td.width = c.titleImageWidth
td.x = id * c.titleImageWidth
td.y = 0
tds.append(td)
#}
c.titleTextureDescriptions = tds
c.recentField = "titleTextureDescriptions"
return c
#}

c.recentField = "none"
return c
#}

+ 15
- 0
harm/gui_TextureDescription.py View File

@@ -0,0 +1,15 @@
class gui_TextureDescription:
def __init__(self):
self.fileName = ""
self.height = 0
self.width = 0
self.x = 0
self.y = 0
def __repr__(self):
return self.__str__()

def __str__(self):
return f"gui_TextureD(fileN/height/width/x/y: '{self.fileName}'/'{self.height}'/'{self.width}'/'{self.x}'/'{self.y}')"

def gui_createTextureDescription():
return gui_TextureDescription()

+ 78
- 0
harm/gui_aux.py View File

@@ -0,0 +1,78 @@
from memory_Context import *

# Generate grid positions in cell dimensions
#
# Conditions:
# 1. 2x2 grid
# 2. 4x4 grid
def gui_aux_cellGridPositions(
size: int
) -> [[int]]:
if (
size == 2
):
return [
[14, 7],
[19, 7],
[14, 13],
[19, 13],
]
#}

if (
size == 4
):
return [
[9, 1],
[14, 1],
[19, 1],
[24, 1],

[9, 7],
[14, 7],
[19, 7],
[24, 7],

[9, 13],
[14, 13],
[19, 13],
[24, 13],

[9, 19],
[14, 19],
[19, 19],
[24, 19],
]
#}
#}

# Generate positions in cell dimensions for Harm game
def gui_aux_cellHarmPositions(
) -> [[int]]:
return [
[4, 6],
[9, 6],
[14, 6],
[19, 6],
[24, 6],
[29, 6],

[4, 12],
[9, 12],
[14, 12],

[4, 18],
[9, 18],
[14, 18],
]
#}

# Convert cell position to screen position
def gui_aux_cellScreenPosition(
c: memory_Context,
pos: [int]
) -> [int]:
x = pos[0] * c.cellSize
y = c.windowHeight - pos[1] * c.cellSize
return [x, y]
#}

+ 15
- 0
harm/gui_aux_test.py View File

@@ -0,0 +1,15 @@
from gui_aux import *

def test_gui_aux_cellGridPositions(
) -> str:
items2x2 = gui_aux_cellGridPositions(2)
items4x4 = gui_aux_cellGridPositions(4)

if (
len(items2x2) == 4 and
len(items4x4) == 16
):
return "OK: gui_aux_cellGridPositions"
#}
return "ERR: gui_aux_cellGridPositions"
#}

+ 49
- 0
harm/gui_test.py View File

@@ -0,0 +1,49 @@
from gui import *
from gui_TextureDescription import *
from memory_Context import *

def test_gui_generateTextureDescriptions(
) -> str:
c = memory_createContext()
c.tileImage = "res/img.png"
c.tileImageCount = 3
c.tileImageHeight = 35
c.tileImageWidth = 20
c.recentField = "tileImageWidth"
c = gui_generateTextureDescriptions(c)
if (
c.recentField == "textureDescriptions" and
len(c.textureDescriptions) == 3 and
c.textureDescriptions[0].fileName == "res/img.png" and
c.textureDescriptions[0].height == 35 and
c.textureDescriptions[0].width == 20 and
c.textureDescriptions[0].x == 0 and
c.textureDescriptions[1].x == 20 and
c.textureDescriptions[2].x == 40
):
return "OK: gui_generateTextureDescriptions"
#}
return "ERR: gui_generateTextureDescriptions"
#}

def test_gui_generateTilePositions(
) -> str:
c = memory_createContext()

c.cellSize = 10
c.playfieldSize = 2
c.cellPositions = gui_aux_cellGridPositions(c.playfieldSize)
c.windowHeight = 200
c.windowWidth = 200
c.recentField = "windowWidth"

c = gui_generateTilePositions(c)
if (
c.recentField == "tilePositions" and
len(c.tilePositions) == 4 and
c.tilePositions[0][0] == 140
):
return "OK: gui_generateTilePositions"
#}
return "ERR: gui_generateTilePositions"
#}

+ 22
- 0
harm/llm.py View File

@@ -0,0 +1,22 @@
import copy

# Make deep copies of arguments to treat the arguments as structs.
# https://stackoverflow.com/a/15398021
def llm_by_value(f):
def _f(*args, **kwargs):
argsCopy = copy.deepcopy(args)
kwargsCopy = copy.deepcopy(kwargs)
return f(*argsCopy, **kwargsCopy)
return _f

# Tell if string is a digit
def llm_isDigit(s):
return s.isdigit()

# Tell if string starts with certain prefix.
def llm_startsWith(s, prefix):
return s.startswith(prefix)

# Convert string to integer
def llm_strToInt(s):
return int(s)

+ 31
- 0
harm/llm_test.py View File

@@ -0,0 +1,31 @@
from llm import *

def llm_test_isDigit_digit(
) -> str:
if (
llm_isDigit("123")
):
return "OK: llm_isDigit_digit"
#}
return "ERR: llm_isDigit_digit"
#}

def llm_test_isDigit_notDigit(
) -> str:
if (
llm_isDigit("abc")
):
return "ERR: llm_isDigit_notDigit"
#}
return "OK: llm_isDigit_notDigit"
#}

def llm_test_strToInt(
) -> str:
if (
llm_strToInt("123") == 123
):
return "OK: llm_strToInt"
#}
return "ERR: llm_strToInt"
#}

+ 21
- 0
harm/llm_test_Python.py View File

@@ -0,0 +1,21 @@
from llm import *
from memory_Context import *

def llm_test_Python_copyByValue(
) -> str:
c = memory_createContext()
c.input = "abc"

@llm_by_value
def alterValue(c):
c.input = "alteredValue"

alterValue(c)

if (
c.input == "abc"
):
return "OK: llm_Python_copyByValue"
#}
return "ERR: llm_Python_copyByValue"
#}

+ 160
- 0
harm/main-gui.py View File

@@ -0,0 +1,160 @@
import arcade
from cli import *
from cli_test import *
from ctx import *
from ctx_test2 import *
from desktop import *
from desktop_Platform import *
from desktop_SequentialTimer import *
from desktop_Window import *
from gui import *
from gui_aux import *
from gui_aux_test import *
from gui_test import *
from llm_test import *
from llm_test_Python import *
from memory_test import *
import sys

print(ctx_test_Controller_executeFunctions_registerFunction_set())
print(ctx_test_Controller_processQueue())
print(ctx_test_Controller_registerFieldCallback_match())
print(ctx_test_Controller_registerFieldCallback_mismatch())
print(ctx_test_memoryContext_field())
print(ctx_test_memoryContext_setField())

print(llm_test_Python_copyByValue())
print(llm_test_isDigit_digit())
print(llm_test_isDigit_notDigit())
print(llm_test_strToInt())

print(memory_test_detectMismatchedItems())
print(memory_test_detectMismatchedItems_itemTwice())
print(memory_test_detectVictory())
print(memory_test_generateConstPlayfield())
print(memory_test_hideMatchingItems())
print(memory_test_selectItem_1x())
print(memory_test_selectItem_2x())
print(memory_test_selectItem_3x())

print(cli_test_exit_e())
print(cli_test_exit_exit())
print(cli_test_exit_victory())
print(cli_test_exit_q())
print(cli_test_exit_quit())
print(cli_test_goOn())
print(cli_test_greetUser())
print(cli_test_showHelp_h())
print(cli_test_showHelp_help())
print(cli_test_selectItem())
print(cli_test_promptSecondItemSelection())
print(cli_test_reportMatchedItems())
print(cli_test_reportMismatchedItems())
print(cli_test_reportVictory())

print(test_gui_aux_cellGridPositions())
print(test_gui_generateTextureDescriptions())
print(test_gui_generateTilePositions())

ctrl = ctx_Controller(memory_createContext())
ctrl.registerFunctions([
# cli_exit,
# cli_goOn,
# cli_greetUser,
# cli_promptSecondItemSelection,
# cli_reportMatchedItems,
# cli_reportMismatchedItems,
# cli_reportVictory,
# cli_selectItem,
# cli_showHelp,
gui_generateDescTextureDescriptions,
gui_generateSplashTextureDescriptions,
gui_generateTextureDescriptions,
gui_generateTilePositions,
gui_generateTitleTextureDescriptions,
memory_detectMismatchedItems,
memory_detectVictory,
memory_generateConstPlayfield,
memory_hideMatchingItems,
memory_selectItem,
])

def printDbg(c):
print(f"Dbg key/value: '{c.recentField}'/'{c.field(c.recentField)}'")
ctrl.registerCallback(printDbg)
ctrl.registerFieldCallback("exit", lambda c: sys.exit(0))

p = desktop_Platform()
p.ctrl = ctrl
p.sequentialTimer = desktop_SequentialTimer()
p.sequentialTimer.callback = lambda key, value: ctrl.set(key, value)

# Bind platform to context changes.
def process(c):
# Copy context to platform.
p.c = c
# Perform context dependent calls of desktop functions.
# Similar to context functions, but no platform is returned.
desktop_deselectMismatchedTiles(p)
desktop_displayDesc(p)
desktop_displayEndingSplashScreen(p)
desktop_displaySelectedTile(p)
desktop_displayTitle(p)
desktop_hideBeginningSplashScreen(p)
desktop_hideDesc(p)
desktop_hideMatchingTiles(p)
desktop_hideTitle(p)
desktop_scheduleDisplayOfEndingSplashScreen(p)
desktop_scheduleHidingOfBeginningSplashScreen(p)
desktop_scheduleHidingOfMatchingTiles(p)
desktop_scheduleDeselectionOfMismatchedTiles(p)
ctrl.registerCallback(process)

ctrl.set("didLaunch", True)
ctrl.set("playfieldSize", 6)

ctrl.set("cellPositions", gui_aux_cellHarmPositions())
ctrl.set("cellSize", 25)
ctrl.set("deselectMismatchedTilesDelay", 500)
ctrl.set("descImage", "res/harm.png")
ctrl.set("descImageCount", 6)
ctrl.set("descImageHeight", 250)
ctrl.set("descImageWidth", 375)
ctrl.set("descPosition", [19, 12])
ctrl.set("hideMatchingTilesDelay", 500)
ctrl.set("splashBeginTimeout", 2000)
ctrl.set("splashEndDelay", 100)
ctrl.set("splashImage", "res/splash.png")
ctrl.set("splashImageCount", 2)
ctrl.set("splashImageHeight", 600)
ctrl.set("splashImageWidth", 900)
ctrl.set("tileImage", "res/harmful-tiles.png")
ctrl.set("tileImageCount", 8)
ctrl.set("tileImageHeight", 100)
ctrl.set("tileImageWidth", 75)
ctrl.set("titleImage", "res/harmful-titles.png")
ctrl.set("titleImageCount", 6)
ctrl.set("titleImageHeight", 100)
ctrl.set("titleImageWidth", 700)
ctrl.set("titlePosition", [4, 1])
ctrl.set("windowWidth", 900)
ctrl.set("windowHeight", 600)
ctrl.set("windowAntialiasing", False)
ctrl.set("windowBackgroundColor", "#ffffff")
ctrl.set("windowTitle", "Вредные продукты")

desktop_loadTextures(p)
desktop_createDeselectedTiles(p)
desktop_createSelectedTiles(p)

desktop_loadTitleTextures(p)
desktop_createTitle(p)

desktop_loadDescTextures(p)
desktop_createDesc(p)

desktop_loadSplashTextures(p)
desktop_createSplash(p)

wnd = desktop_Window(p)
arcade.run()

+ 77
- 0
harm/main.py View File

@@ -0,0 +1,77 @@
from cli import *
from cli_test import *
from ctx import *
from ctx_test2 import *
#from ctx_test import *
#from ctx_test_Python import *
from llm_test import *
from llm_test_Python import *
from memory_test import *
import sys

print(ctx_test_Controller_executeFunctions_registerFunction_set())
print(ctx_test_Controller_processQueue())
print(ctx_test_Controller_registerFieldCallback_match())
print(ctx_test_Controller_registerFieldCallback_mismatch())
print(ctx_test_memoryContext_field())
print(ctx_test_memoryContext_setField())

print(llm_test_Python_copyByValue())
print(llm_test_isDigit_digit())
print(llm_test_isDigit_notDigit())
print(llm_test_strToInt())

print(memory_test_detectMismatchedItems())
print(memory_test_detectMismatchedItems_itemTwice())
print(memory_test_detectVictory())
print(memory_test_generateConstPlayfield())
print(memory_test_hideMatchingItems())
print(memory_test_selectItem_1x())
print(memory_test_selectItem_2x())
print(memory_test_selectItem_3x())

print(cli_test_exit_e())
print(cli_test_exit_exit())
print(cli_test_exit_victory())
print(cli_test_exit_q())
print(cli_test_exit_quit())
print(cli_test_goOn())
print(cli_test_greetUser())
print(cli_test_showHelp_h())
print(cli_test_showHelp_help())
print(cli_test_selectItem())
print(cli_test_promptSecondItemSelection())
print(cli_test_reportMatchedItems())
print(cli_test_reportMismatchedItems())
print(cli_test_reportVictory())

ctrl = ctx_Controller(memory_createContext())
ctrl.registerFunctions([
cli_exit,
cli_goOn,
cli_greetUser,
cli_promptSecondItemSelection,
cli_reportMatchedItems,
cli_reportMismatchedItems,
cli_reportVictory,
cli_selectItem,
cli_showHelp,
memory_detectMismatchedItems,
memory_detectVictory,
memory_generateConstPlayfield,
memory_hideMatchingItems,
memory_selectItem,
])

def printOutput(c):
if c.recentField.startswith("output"):
print(c.field(c.recentField))
ctrl.registerCallback(printOutput)
ctrl.registerFieldCallback("exit", lambda c: sys.exit(0))

ctrl.set("didLaunch", True)
ctrl.set("playfieldSize", 2)

for line in sys.stdin:
ln = line.rstrip()
ctrl.set("input", ln)

+ 138
- 0
harm/memory.py View File

@@ -0,0 +1,138 @@
from memory_Context import *
from llm import *

# Detect mismatched items
#
# Conditions:
# 0. Two items has just been selected
# 1. The same item has been selected twice
# 2. Selected items are of different groups
@llm_by_value
def memory_detectMismatchedItems(
c: memory_Context
) -> memory_Context:
if not (
c.recentField == "selectedItems" and
len(c.selectedItems) == 2
):
c.recentField = "none"
return c
#}
if (
c.selectedItems[0] == c.selectedItems[1]
):
c.mismatchedItems.clear()
c.mismatchedItems.append(c.selectedItems[0])
c.recentField = "mismatchedItems"
return c
#}
if (
c.playfieldItems[c.selectedItems[0]] != c.playfieldItems[c.selectedItems[1]]
):
c.mismatchedItems.clear()
c.mismatchedItems.append(c.selectedItems[0])
c.mismatchedItems.append(c.selectedItems[1])
c.recentField = "mismatchedItems"
return c
#}
c.recentField = "none"
return c
#}

# Detect victory
#
# Conditions:
# 1. Matching items have just been hidden and all items are hidden now
@llm_by_value
def memory_detectVictory(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "hiddenItems" and
len(c.hiddenItems) == len(c.playfieldItems)
):
c.victory = True
c.recentField = "victory"
return c
#}
c.recentField = "none"
return c
#}

# Generate constant playfield
#
# Conditions:
# 1. Size has just been specified
#
# Both ids and group ids start with 0
@llm_by_value
def memory_generateConstPlayfield(
c: memory_Context
) -> memory_Context:
if not (
c.recentField == "playfieldSize"
):
c.recentField = "none"
return c
#}

idGroups: dict[int, int] = { }
id = 0
for gid in range(0, c.playfieldSize):
idGroups[id] = gid
id += 1
idGroups[id] = gid
id += 1
#}
c.playfieldItems = idGroups
c.recentField = "playfieldItems"
return c
#}

# Hide matching selected items
#
# Conditions:
# 1. Two items are selected and they are of the same group
@llm_by_value
def memory_hideMatchingItems(
c: memory_Context
) -> memory_Context:
if (
c.recentField == "selectedItems" and
len(c.selectedItems) == 2 and
c.playfieldItems[c.selectedItems[0]] == c.playfieldItems[c.selectedItems[1]]
):
c.hiddenItems.append(c.selectedItems[0])
c.hiddenItems.append(c.selectedItems[1])
c.recentField = "hiddenItems"
return c
#}
c.recentField = "none"
return c
#}

# Select item
#
# Conditions:
# 1. Id has just been specified for selection
@llm_by_value
def memory_selectItem(
c: memory_Context
) -> memory_Context:
if not (
c.recentField == "selectedId"
):
c.recentField = "none"
return c
#}

if (
len(c.selectedItems) == 2
):
c.selectedItems.clear()
#}
c.selectedItems.append(c.selectedId)
c.recentField = "selectedItems"
return c
#}


+ 71
- 0
harm/memory_Context.py View File

@@ -0,0 +1,71 @@
class memory_Context:
def __init__(self):
self.cellPositions = []
self.cellSize = 0
self.descImage = ""
self.descImageCount = 0
self.descImageHeight = 0
self.descImageWidth = 0
self.descPosition = []
self.descTextureDescriptions = []
self.deselectMismatchedTiles = False
self.deselectMismatchedTilesDelay = 0
self.didLaunch = False
self.displayEndingSplashScreen = False
self.exit = False
self.hiddenItems = []
self.hideBeginningSplashScreen = False
self.hideMatchingTiles = False
self.hideMatchingTilesDelay = 0
self.input = ""
self.mismatchedItems = []
self.outputGoOn = ""
self.outputGreeting = ""
self.outputHelp = ""
self.outputMatchedItems = ""
self.outputMismatchedItems = ""
self.outputPromptSelection = ""
self.outputVictory = ""
self.playfieldItems = {}
self.playfieldSize = 0
self.recentField = "none"
self.selectedId = -1
self.selectedItems = []
self.splashBeginTimeout = 0
self.splashEndDelay = 0
self.splashImage = ""
self.splashImageCount = 0
self.splashImageHeight = 0
self.splashImageWidth = 0
self.textureDescriptions = []
self.tileImage = ""
self.tileImageCount = 0
self.tileImageHeight = 0
self.tileImageWidth = 0
self.tilePositions = []
self.titleImage = ""
self.titleImageCount = 0
self.titleImageHeight = 0
self.titleImageWidth = 0
self.titlePosition = []
self.titleTextureDescriptions = []
self.windowBackgroundColor = "#000000"
self.windowHeight = 0
self.windowTitle = ""
self.windowWidth = 0
self.victory = False

def field(self, fieldName):
return getattr(self, fieldName)

def setField(self, fieldName, value):
setattr(self, fieldName, value)

def __repr__(self):
return self.__str__()

def __str__(self):
return f"memory_Context(playfieldI/playfieldS/recentF/selectedId/selectedI: '{self.playfieldItems}'/'{self.playfieldSize}'/'{self.recentField}'/'{self.selectedId}'/'{self.selectedItems}')"

def memory_createContext():
return memory_Context()

+ 231
- 0
harm/memory_test.py View File

@@ -0,0 +1,231 @@
from memory import *
from memory_Context import *

def memory_test_detectMismatchedItems(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select two items of different groups.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 2
c.recentField = "selectedId"
c = memory_selectItem(c)

# Detect mismatching.
c = memory_detectMismatchedItems(c)

# See if the two selected items do not match.
if (
c.recentField == "mismatchedItems" and
len(c.mismatchedItems) == 2 and
c.mismatchedItems[0] == 0 and
c.mismatchedItems[1] == 2
):
return "OK: memory_detectMismatchedItems"
#}
return "ERR: memory_detectMismatchedItems"
#}

def memory_test_detectMismatchedItems_itemTwice(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select the same item twice.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)

# Detect mismatching.
c = memory_detectMismatchedItems(c)

# See if the two selected items do not match.
if (
c.recentField == "mismatchedItems" and
len(c.mismatchedItems) == 1 and
c.mismatchedItems[0] == 0
):
return "OK: memory_detectMismatchedItems_itemTwice"
#}
return "ERR: memory_detectMismatchedItems_itemTwice"
#}

def memory_test_detectVictory(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select the first two items of the same group.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 1
c.recentField = "selectedId"
c = memory_selectItem(c)

# Hide the first pair.
c = memory_hideMatchingItems(c)

# Select the last two items of the same group.
c.selectedId = 2
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 3
c.recentField = "selectedId"
c = memory_selectItem(c)

# Hide the second pair.
c = memory_hideMatchingItems(c)

# Detect victory.
c = memory_detectVictory(c)

# See if victory has been detected.
if (
c.recentField == "victory" and
c.victory == True
):
return "OK: memory_detectVictory"
#}
return "ERR: memory_detectVictory"
#}

def memory_test_generateConstPlayfield(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)
if (
c.recentField == "playfieldItems" and
len(c.playfieldItems) == 4 and
c.playfieldItems[0] == 0 and
c.playfieldItems[1] == 0 and
c.playfieldItems[2] == 1 and
c.playfieldItems[3] == 1
):
return "OK: memory_generateConstPlayfield"
#}
return "ERR: memory_generateConstPlayfield"
#}

def memory_test_hideMatchingItems(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select two items of the same group.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 1
c.recentField = "selectedId"
c = memory_selectItem(c)

# Hide matching items.
c = memory_hideMatchingItems(c)

# See if the two selected items match.
if (
c.recentField == "hiddenItems" and
len(c.hiddenItems) == 2 and
c.hiddenItems[0] == 0 and
c.hiddenItems[1] == 1
):
return "OK: memory_hideMatchingItems"
#}
return "ERR: memory_hideMatchingItems"
#}

def memory_test_selectItem_1x(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select the first item.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)

# See if it's in selectedItems now.
if (
c.recentField == "selectedItems" and
len(c.selectedItems) == 1 and
c.selectedItems[0] == 0
):
return "OK: memory_selectItem_1x"
#}
return "ERR: memory_selectItem_1x"
#}

def memory_test_selectItem_2x(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select the first two items.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 1
c.recentField = "selectedId"
c = memory_selectItem(c)

# See if both items are selected now.
if (
c.recentField == "selectedItems" and
len(c.selectedItems) == 2 and
c.selectedItems[0] == 0 and
c.selectedItems[1] == 1
):
return "OK: memory_selectItem_2x"
#}
return "ERR: memory_selectItem_2x"
#}

def memory_test_selectItem_3x(
) -> str:
c = memory_createContext()
c.playfieldSize = 2
c.recentField = "playfieldSize"
c = memory_generateConstPlayfield(c)

# Select three items.
c.selectedId = 0
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 1
c.recentField = "selectedId"
c = memory_selectItem(c)
c.selectedId = 2
c.recentField = "selectedId"
c = memory_selectItem(c)

# See if only one (last) item is selected now.
if (
c.recentField == "selectedItems" and
len(c.selectedItems) == 1 and
c.selectedItems[0] == 2
):
return "OK: memory_selectItem_3x"
#}
return "ERR: memory_selectItem_3x"
#}

BIN
harm/res/harm.png View File

Before After
Width: 2250  |  Height: 250  |  Size: 76KB

BIN
harm/res/harmful-tiles.png View File

Before After
Width: 600  |  Height: 100  |  Size: 18KB

BIN
harm/res/harmful-titles.png View File

Before After
Width: 4200  |  Height: 100  |  Size: 45KB

BIN
harm/res/splash.png View File

Before After
Width: 1800  |  Height: 600  |  Size: 58KB

+ 2
- 0
harm/run-gui-py View File

@@ -0,0 +1,2 @@
#!/bin/bash
/Users/mk/py3.12venv/bin/python3.12 main-gui.py

Loading…
Cancel
Save