Files
go-nkode/internal/models/user_interface.go
2024-11-26 11:31:46 -06:00

195 lines
4.5 KiB
Go

package models
import (
"go-nkode/config"
"go-nkode/internal/security"
"go-nkode/internal/utils"
"log"
)
type UserInterface struct {
IdxInterface IdxInterface
SvgId SvgIdInterface
Kp *KeypadDimension
}
func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) {
idxInterface := security.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{
IdxInterface: idxInterface,
SvgId: svgId,
Kp: kp,
}
if err := userInterface.RandomShuffle(); err != nil {
return nil, err
}
return &userInterface, nil
}
func (u *UserInterface) RandomShuffle() error {
err := u.shuffleKeys()
keypadView, err := u.InterfaceMatrix()
if err != nil {
return err
}
setView, err := security.MatrixTranspose(keypadView)
if err != nil {
return err
}
for idx, set := range setView {
err := security.FisherYatesShuffle(&set)
if err != nil {
return nil
}
setView[idx] = set
}
keypadView, err = security.MatrixTranspose(setView)
if err != nil {
return err
}
u.IdxInterface = security.MatrixToList(keypadView)
return nil
}
func (u *UserInterface) InterfaceMatrix() ([][]int, error) {
return security.ListToMatrix(u.IdxInterface, u.Kp.AttrsPerKey)
}
func (u *UserInterface) SetViewMatrix() ([][]int, error) {
keypadView, err := u.InterfaceMatrix()
if err != nil {
return nil, err
}
return security.MatrixTranspose(keypadView)
}
func (u *UserInterface) DisperseInterface() error {
if !u.Kp.IsDispersable() {
return config.ErrInterfaceNotDispersible
}
err := u.shuffleKeys()
if err != nil {
return err
}
err = u.randomAttributeRotation()
if err != nil {
return err
}
return nil
}
func (u *UserInterface) shuffleKeys() error {
userInterfaceMatrix, err := security.ListToMatrix(u.IdxInterface, u.Kp.AttrsPerKey)
if err != nil {
return err
}
err = security.FisherYatesShuffle[[]int](&userInterfaceMatrix)
if err != nil {
return err
}
u.IdxInterface = security.MatrixToList(userInterfaceMatrix)
return nil
}
func (u *UserInterface) randomAttributeRotation() error {
userInterface, err := u.InterfaceMatrix()
if err != nil {
return err
}
transposeUserInterface, err := security.MatrixTranspose(userInterface)
attrRotation, err := security.RandomPermutation(len(transposeUserInterface))
if err != nil {
return err
}
for idx, attrSet := range transposeUserInterface {
rotation := attrRotation[idx]
transposeUserInterface[idx] = append(attrSet[rotation:], attrSet[:rotation]...)
}
userInterface, err = security.MatrixTranspose(transposeUserInterface)
if err != nil {
return err
}
u.IdxInterface = security.MatrixToList(userInterface)
return nil
}
func (u *UserInterface) AttributeAdjacencyGraph() (map[int]utils.Set[int], error) {
interfaceKeypad, err := u.InterfaceMatrix()
if err != nil {
return nil, err
}
graph := make(map[int]utils.Set[int])
for _, key := range interfaceKeypad {
keySet := utils.NewSetFromSlice(key)
for _, attr := range key {
attrAdjacency := keySet.Copy()
attrAdjacency.Remove(attr)
graph[attr] = attrAdjacency
}
}
return graph, nil
}
func (u *UserInterface) PartialInterfaceShuffle() error {
err := u.shuffleKeys()
if err != nil {
return err
}
numbOfSelectedSets := u.Kp.AttrsPerKey / 2
if u.Kp.AttrsPerKey&1 == 1 {
numbOfSelectedSets += security.Choice[int]([]int{0, 1})
}
setIdxs, err := security.RandomPermutation(u.Kp.AttrsPerKey)
if err != nil {
return err
}
selectedSets := utils.NewSetFromSlice[int](setIdxs[:numbOfSelectedSets])
keypadSetView, err := u.SetViewMatrix()
if err != nil {
return err
}
interfaceBySet := make([][]int, u.Kp.AttrsPerKey)
for idx, attrs := range keypadSetView {
if selectedSets.Contains(idx) {
err = security.FisherYatesShuffle[int](&attrs)
if err != nil {
return err
}
}
interfaceBySet[idx] = attrs
}
keypadView, err := security.MatrixTranspose(interfaceBySet)
if err != nil {
return err
}
u.IdxInterface = security.MatrixToList(keypadView)
return nil
}
func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) {
if keyNumb < 0 || u.Kp.NumbOfKeys <= keyNumb {
log.Printf("keyNumb %d is out of range 0-%d", keyNumb, u.Kp.NumbOfKeys)
return -1, config.ErrKeyIndexOutOfRange
}
if setIdx < 0 || u.Kp.AttrsPerKey <= setIdx {
log.Printf("setIdx %d is out of range 0-%d", setIdx, u.Kp.AttrsPerKey)
return -1, config.ErrAttributeIndexOutOfRange
}
keypadView, err := u.InterfaceMatrix()
if err != nil {
return -1, err
}
return keypadView[keyNumb][setIdx], nil
}