Compare commits
6 Commits
7e5322f738
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
927b166070 | ||
|
|
1fd5290959 | ||
|
|
814091260c | ||
|
|
5cb1600637 | ||
|
|
810c951a29 | ||
|
|
fc9115aafc |
222
harm/cli.py
Normal file
222
harm/cli.py
Normal 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
harm/cli_test.py
Normal file
303
harm/cli_test.py
Normal 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
harm/ctx.py
Normal file
53
harm/ctx.py
Normal 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
harm/ctx_test2.py
Normal file
142
harm/ctx_test2.py
Normal 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"
|
||||
#}
|
||||
316
harm/desktop.py
Normal file
316
harm/desktop.py
Normal file
@@ -0,0 +1,316 @@
|
||||
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)
|
||||
#}
|
||||
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
harm/desktop_Platform.py
Normal file
22
harm/desktop_Platform.py
Normal 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
harm/desktop_SequentialTimer.py
Normal file
35
harm/desktop_SequentialTimer.py
Normal 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
harm/desktop_Window.py
Normal file
32
harm/desktop_Window.py
Normal 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
harm/desktop_aux.py
Normal file
13
harm/desktop_aux.py
Normal 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
harm/gui.py
Normal file
175
harm/gui.py
Normal 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
harm/gui_TextureDescription.py
Normal file
15
harm/gui_TextureDescription.py
Normal 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
harm/gui_aux.py
Normal file
78
harm/gui_aux.py
Normal 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
harm/gui_aux_test.py
Normal file
15
harm/gui_aux_test.py
Normal 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
harm/gui_test.py
Normal file
49
harm/gui_test.py
Normal 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
harm/llm.py
Normal file
22
harm/llm.py
Normal 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
harm/llm_test.py
Normal file
31
harm/llm_test.py
Normal 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
harm/llm_test_Python.py
Normal file
21
harm/llm_test_Python.py
Normal 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
harm/main-gui.py
Normal file
160
harm/main-gui.py
Normal 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
harm/main.py
Normal file
77
harm/main.py
Normal 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
harm/memory.py
Normal file
138
harm/memory.py
Normal 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
harm/memory_Context.py
Normal file
71
harm/memory_Context.py
Normal 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
harm/memory_test.py
Normal file
231
harm/memory_test.py
Normal 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
Normal file
BIN
harm/res/harm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
harm/res/harmful-tiles.png
Normal file
BIN
harm/res/harmful-tiles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
harm/res/harmful-titles.png
Normal file
BIN
harm/res/harmful-titles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
harm/res/splash.png
Normal file
BIN
harm/res/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
2
harm/run-gui-py
Executable file
2
harm/run-gui-py
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
/Users/mk/py3.12venv/bin/python3.12 main-gui.py
|
||||
@@ -49,6 +49,16 @@ def desktop_createSelectedTiles(p):
|
||||
#}
|
||||
#}
|
||||
|
||||
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)
|
||||
@@ -94,6 +104,19 @@ def desktop_displayDesc(p):
|
||||
#}
|
||||
#}
|
||||
|
||||
# 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:
|
||||
@@ -126,6 +149,18 @@ def desktop_displayTitle(p):
|
||||
#}
|
||||
#}
|
||||
|
||||
# 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:
|
||||
@@ -183,6 +218,23 @@ def desktop_loadDescTextures(p):
|
||||
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 = []
|
||||
@@ -227,6 +279,18 @@ def desktop_scheduleDeselectionOfMismatchedTiles(p):
|
||||
#}
|
||||
#}
|
||||
|
||||
# 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:
|
||||
@@ -238,3 +302,16 @@ def desktop_scheduleHidingOfMatchingTiles(p):
|
||||
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)
|
||||
#}
|
||||
#}
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ class desktop_Platform:
|
||||
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()
|
||||
|
||||
@@ -17,6 +17,7 @@ class desktop_Window(arcade.Window):
|
||||
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):
|
||||
|
||||
33
v5/gui.py
33
v5/gui.py
@@ -36,6 +36,39 @@ def gui_generateDescTextureDescriptions(
|
||||
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:
|
||||
|
||||
@@ -68,6 +68,7 @@ ctrl.registerFunctions([
|
||||
# cli_selectItem,
|
||||
# cli_showHelp,
|
||||
gui_generateDescTextureDescriptions,
|
||||
gui_generateSplashTextureDescriptions,
|
||||
gui_generateTextureDescriptions,
|
||||
gui_generateTilePositions,
|
||||
gui_generateTitleTextureDescriptions,
|
||||
@@ -80,7 +81,7 @@ ctrl.registerFunctions([
|
||||
|
||||
def printDbg(c):
|
||||
print(f"Dbg key/value: '{c.recentField}'/'{c.field(c.recentField)}'")
|
||||
#ctrl.registerCallback(printDbg)
|
||||
ctrl.registerCallback(printDbg)
|
||||
ctrl.registerFieldCallback("exit", lambda c: sys.exit(0))
|
||||
|
||||
p = desktop_Platform()
|
||||
@@ -96,11 +97,15 @@ def process(c):
|
||||
# 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)
|
||||
@@ -117,6 +122,12 @@ 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)
|
||||
|
||||
@@ -11,8 +11,10 @@ class memory_Context:
|
||||
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 = ""
|
||||
@@ -29,6 +31,12 @@ class memory_Context:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user