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 }