package entities import ( "github.com/DonovanKelly/sugar-n-spice/set" "go-nkode/config" "go-nkode/pkg/nkode-core/security" "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]set.Set[int], error) { interfaceKeypad, err := u.InterfaceMatrix() if err != nil { return nil, err } graph := make(map[int]set.Set[int]) for _, key := range interfaceKeypad { keySet := set.NewSetFromSlice(key) for _, attr := range key { attrAdjacency := keySet.Copy() attrAdjacency.Remove(attr) graph[attr] = attrAdjacency } } return graph, nil } func (u *UserInterface) LoginShuffle() error { if err := u.shuffleKeys(); err != nil { return err } keypadSet1, err := u.InterfaceMatrix() if err = u.shuffleKeys(); err != nil { return err } keypadSet2, err := u.InterfaceMatrix() numbOfSelectedSets := u.Kp.AttrsPerKey / 2 setIdxs, err := security.RandomPermutation(u.Kp.AttrsPerKey) if err != nil { return err } selectedSets := set.NewSetFromSlice[int](setIdxs[:numbOfSelectedSets]) for keyIdx, key := range keypadSet1 { for idx := range key { if selectedSets.Contains(idx) { keypadSet1[keyIdx][idx] = keypadSet2[keyIdx][idx] } } } u.IdxInterface = security.MatrixToList(keypadSet1) 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 }