193 lines
4.4 KiB
Go
193 lines
4.4 KiB
Go
package nkode
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
m "go-nkode/core/model"
|
|
"go-nkode/hashset"
|
|
"go-nkode/util"
|
|
)
|
|
|
|
type UserInterface struct {
|
|
IdxInterface m.IdxInterface
|
|
KeypadSize m.KeypadSize
|
|
}
|
|
|
|
func NewUserInterface(keypadSize m.KeypadSize) (*UserInterface, error) {
|
|
idxInterface := util.IdentityArray(keypadSize.TotalAttrs())
|
|
userInterface := UserInterface{
|
|
IdxInterface: idxInterface,
|
|
KeypadSize: keypadSize,
|
|
}
|
|
err := userInterface.RandomShuffle()
|
|
if 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 := util.MatrixTranspose(keypadView)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for idx, set := range setView {
|
|
err := util.FisherYatesShuffle(&set)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
setView[idx] = set
|
|
}
|
|
|
|
keypadView, err = util.MatrixTranspose(setView)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u.IdxInterface = util.MatrixToList(keypadView)
|
|
return nil
|
|
}
|
|
|
|
func (u *UserInterface) InterfaceMatrix() ([][]int, error) {
|
|
return util.ListToMatrix(u.IdxInterface, u.KeypadSize.AttrsPerKey)
|
|
}
|
|
|
|
func (u *UserInterface) SetViewMatrix() ([][]int, error) {
|
|
keypadView, err := u.InterfaceMatrix()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return util.MatrixTranspose(keypadView)
|
|
}
|
|
|
|
func (u *UserInterface) DisperseInterface() error {
|
|
if !u.KeypadSize.IsDispersable() {
|
|
return errors.New("interface is not dispersable")
|
|
}
|
|
|
|
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 := util.ListToMatrix(u.IdxInterface, u.KeypadSize.AttrsPerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = util.FisherYatesShuffle[[]int](&userInterfaceMatrix)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u.IdxInterface = util.MatrixToList(userInterfaceMatrix)
|
|
return nil
|
|
}
|
|
|
|
func (u *UserInterface) randomAttributeRotation() error {
|
|
userInterface, err := u.InterfaceMatrix()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
transposeUserInterface, err := util.MatrixTranspose(userInterface)
|
|
|
|
attrRotation, err := util.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 = util.MatrixTranspose(transposeUserInterface)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u.IdxInterface = util.MatrixToList(userInterface)
|
|
return nil
|
|
}
|
|
|
|
func (u *UserInterface) AttributeAdjacencyGraph() (map[int]hashset.Set[int], error) {
|
|
interfaceKeypad, err := u.InterfaceMatrix()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
graph := make(map[int]hashset.Set[int])
|
|
|
|
for _, key := range interfaceKeypad {
|
|
keySet := hashset.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.KeypadSize.AttrsPerKey / 2
|
|
if u.KeypadSize.AttrsPerKey&1 == 1 {
|
|
numbOfSelectedSets += util.Choice[int]([]int{0, 1})
|
|
}
|
|
setIdxs, err := util.RandomPermutation(u.KeypadSize.AttrsPerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
selectedSets := hashset.NewSetFromSlice[int](setIdxs[:numbOfSelectedSets])
|
|
|
|
keypadSetView, err := u.SetViewMatrix()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
interfaceBySet := make([][]int, u.KeypadSize.AttrsPerKey)
|
|
for idx, attrs := range keypadSetView {
|
|
if selectedSets.Contains(idx) {
|
|
err = util.FisherYatesShuffle[int](&attrs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
interfaceBySet[idx] = attrs
|
|
}
|
|
keypadView, err := util.MatrixTranspose(interfaceBySet)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u.IdxInterface = util.MatrixToList(keypadView)
|
|
return nil
|
|
}
|
|
|
|
func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) {
|
|
if keyNumb < 0 || u.KeypadSize.NumbOfKeys <= keyNumb {
|
|
return -1, errors.New(fmt.Sprintf("keyNumb %d is out of range 0-%d", keyNumb, u.KeypadSize.NumbOfKeys))
|
|
}
|
|
|
|
if setIdx < 0 || u.KeypadSize.AttrsPerKey <= setIdx {
|
|
return -1, errors.New(fmt.Sprintf("setIdx %d is out of range 0-%d", setIdx, u.KeypadSize.AttrsPerKey))
|
|
}
|
|
keypadView, err := u.InterfaceMatrix()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
return keypadView[keyNumb][setIdx], nil
|
|
}
|