가상 키보드 텍스트 입력


22

기존 키보드가없는 최신 게임 콘솔 및 기타 장치에서 텍스트 입력은 악몽입니다. 가상 키보드에서 몇 개의 버튼과 조이스틱으로 입력 해야하는 것은 성가신 일이며 가능한 한 적은 움직임 / 버튼 누름을 만들고 싶습니다.

사용할 키보드는 다음과 같습니다.

+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
+---+---+---+---+---+---+---+---+---+---+
| q | w | e | r | t | y | u | i | o | p |
+---+---+---+---+---+---+---+---+---+---+
| a | s | d | f | g | h | j | k | l | - |
+---+---+---+---+---+---+---+---+---+---+
| z | x | c | v | b | n | m | _ | @ | . |
+---+---+---+---+---+---+---+---+---+---+

다음과 같은 작업을 사용할 수 있습니다.

  • L: 키보드에서 왼쪽으로 한 칸 이동 (랩)
  • R: 키보드에서 오른쪽으로 한 칸 이동 (포장)
  • U: 키보드에서 한 칸 위로 이동 (랩)
  • D: 키보드에서 한 칸 아래로 이동 (랩)
  • Y: 공백을 삽입
  • B: 삽입 포인터를 한 칸 왼쪽으로 이동합니다 (포인터가 시작 부분에 있으면 아무 것도 수행하지 않음).
  • F: 삽입 포인터를 한 칸 오른쪽으로 이동합니다 (포인터가 끝에 있으면 아무 것도 수행하지 않음).
  • C: 토글 캡 잠금
  • A: 선택한 문자를 삽입 포인터의 위치에 삽입

위의 키보드와 명령 (일치 [a-zA-Z0-9 _@.-]*)을 사용하여 입력 할 수있는 ASCII 문자 만 포함 된 입력 문자열이 제공되면 출력 문자열을 생성하는 일련의 명령을 출력합니다. 커서의 초기 위치는 1키 (왼쪽 상단)에 있으며 Caps Lock은 처음에는 꺼져 있습니다.

채점

주어진 문자열에 대해 순진한 접근 방식은 문자열의 각 문자에 대해 가장 짧은 경로로 키보드의 문자를 탐색하고 필요한 경우 대문자 잠금을 토글하고 문자를 선택하는 것입니다. 이러한 순진한 접근 방식은 length 명령을 생성합니다 (length of input string) + (sum of Manhattan distances on keyboard between consecutive non-space characters) + (number of times the string alternates between lowercase and uppercase characters) + (1 if string starts with an uppercase letter else 0). 예를 들어,의 순진한 접근 101초래 ALARA길이 5 명령 및 Noob 5초래 DDDRRRRRCAUURRRCAADDLLLLAYUUUA, 길이 30 명령을 사용합니다.

그러나 귀하의 제출물은 순진한 접근법보다 더 나은 일을 추구합니다. 각 입력 문자열에 대해 제출물은 순진한 접근 방식이 제출 한 명령 수에서 제출물로 출력되는 명령 수와 동일한 점수를받습니다. 전체 점수는 개별 점수의 합계입니다.

규칙

  • 제출은 Cloud9 무료 가상 작업 공간 에서 실행됩니다 . 작업 공간에는 512MB의 RAM, 2GB의 디스크 공간, 2.50GHz에서 Intel (R) Xeon (R) CPU 8 개 (전체 CPU 정보, 여기서 실행 가능 cat /proc/cpuinfo, 여기 에서 찾을 수 있음 )가 있으며 64 비트 Ubuntu 14.04가 실행 중입니다. 신뢰할 수 있는. 제출을 실행하고 점수를 매기기 위해 테스트 작업 영역 에 대한 액세스를 요청 하거나 점수를 매길 수 있습니다.
  • 제출은 테스트 사례마다 한 번씩 실행됩니다. 실행 사이의 저장 상태는 금지되어 있습니다. 제출은 필요한 경우 입력 파일을 읽는 것을 제외하고 소스 파일 이외의 파일 (실행간에 수정 될 수 없음)을 쓰거나 읽을 수 없습니다.
  • 제출은 각 테스트 사례에 대해 1 분의 런타임으로 제한됩니다. 제출물은 여러 솔루션을 출력 할 수 있지만 할당 된 시간 내에 마지막으로 유효한 솔루션 만 스코어링에 사용됩니다. 할당 된 시간 내에 유효한 솔루션을 출력하지 않으면 해당 테스트 케이스에서 점수가 0이됩니다.
  • 제출을 호출하는 방법과 표준 Ubuntu 14.04 설치에 포함되어 있지 않은 설치해야하는 도구 / 라이브러리에 대한 지침을 포함하십시오.
  • 승자가 가장 큰 점수로 제출됩니다. 동점 일 경우 알고리즘 복잡성이 더 우수한 제출물이 이길 수 있습니다. 동점이 여전히 해결되지 않으면 점수 및 알고리즘 복잡성에 도달 한 첫 번째 제출물이 승리합니다.
  • 제출물이 테스트 사례에 맞게 최적화되지 않을 수 있습니다. 필요하다고 생각되면 테스트 케이스를 변경할 권리가 있습니다.

테스트 사례

체재: input string => naive score

(이들에 오류가 있으면 정정 사항을 적어주십시오)

101 => 5
quip => 12
PPCG => 15
Mego => 25
Noob 5 => 26
penguin => 27
867-5309 => 32
2_sPoOkY_4_mE => 60
The Nineteenth Byte => 76
penguins@SouthPole.org => 95
8xM3R__5ltZgrkJ.-W b => 98
correcthorsebatterystaple => 104
verylongRUNSOFCAPSandnocaps => 118
This is an English sentence. => 122
WNtza.akjzSP2GI0V9X .0epmUQ-mo => 131
Programming Puzzles and Code Golf => 140

5
나는 -27 ... 없어요
Leaky Nun

1
@ Mego : 나는 그의 솔루션이 순진한 것보다 나쁘다고 말하고 있다고 생각 합니다. : P
El'endia Starman

2
동의합니다. 게임 콘솔 키보드가 빠릅니다 .
Rɪᴋᴇʀ

프로그램이 1 분 이내에 종료되지 않고 해당 시간 내에 하나 이상의 솔루션을 인쇄하면 어떻게됩니까? 종료하지 않으면 페널티가 있습니까?
mIllIbyte

@mIllIbyte 제한 시간 내에 인쇄 된 마지막 유효 (즉, 올바른 텍스트로 표시) 명령이 사용됩니다. 유효한 명령이 인쇄되지 않으면 점수는 0입니다.
Mego

답변:


2

기음

점수는 193입니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LEFT 'L'
#define RIGHT 'R'
#define CAPS 'C'
#define UP 'U'
#define DOWN 'D'
#define SPACE 'Y'
#define CURSORLEFT 'B'
#define CURSORRIGHT 'F'
#define APPLY 'A'
#define TABLEX 10
#define TABLEY 4
#define casediff(A,B) (isupper(A)*islower(B)+islower(A)*isupper(B))
typedef struct {int x; int y;} coord;
coord letters[300];
#define initLetter(letter, X, Y) \
letters[letter].x=X, letters[letter].y=Y
#define initAllLetters(); \
initLetter('1',0,0);\
initLetter('1',0,0);\
initLetter('2',1,0);\
initLetter('2',1,0);\
initLetter('3',2,0);\
initLetter('3',2,0);\
initLetter('4',3,0);\
initLetter('4',3,0);\
initLetter('5',4,0);\
initLetter('5',4,0);\
initLetter('6',5,0);\
initLetter('6',5,0);\
initLetter('7',6,0);\
initLetter('7',6,0);\
initLetter('8',7,0);\
initLetter('8',7,0);\
initLetter('9',8,0);\
initLetter('9',8,0);\
initLetter('0',9,0);\
initLetter('0',9,0);\
initLetter('Q',0,1);\
initLetter('q',0,1);\
initLetter('W',1,1);\
initLetter('w',1,1);\
initLetter('E',2,1);\
initLetter('e',2,1);\
initLetter('R',3,1);\
initLetter('r',3,1);\
initLetter('T',4,1);\
initLetter('t',4,1);\
initLetter('Y',5,1);\
initLetter('y',5,1);\
initLetter('U',6,1);\
initLetter('u',6,1);\
initLetter('I',7,1);\
initLetter('i',7,1);\
initLetter('O',8,1);\
initLetter('o',8,1);\
initLetter('P',9,1);\
initLetter('p',9,1);\
initLetter('A',0,2);\
initLetter('a',0,2);\
initLetter('S',1,2);\
initLetter('s',1,2);\
initLetter('D',2,2);\
initLetter('d',2,2);\
initLetter('F',3,2);\
initLetter('f',3,2);\
initLetter('G',4,2);\
initLetter('g',4,2);\
initLetter('H',5,2);\
initLetter('h',5,2);\
initLetter('J',6,2);\
initLetter('j',6,2);\
initLetter('K',7,2);\
initLetter('k',7,2);\
initLetter('L',8,2);\
initLetter('l',8,2);\
initLetter('-',9,2);\
initLetter('-',9,2);\
initLetter('Z',0,3);\
initLetter('z',0,3);\
initLetter('X',1,3);\
initLetter('x',1,3);\
initLetter('C',2,3);\
initLetter('c',2,3);\
initLetter('V',3,3);\
initLetter('v',3,3);\
initLetter('B',4,3);\
initLetter('b',4,3);\
initLetter('N',5,3);\
initLetter('n',5,3);\
initLetter('M',6,3);\
initLetter('m',6,3);\
initLetter('_',7,3);\
initLetter('_',7,3);\
initLetter('@',8,3);\
initLetter('@',8,3);\
initLetter('.',9,3);\
initLetter('.',9,3);
typedef struct {int length; char instr[300];} movement;
movecasefold(char*instr,coord A, coord B){
    register int i=0;int j;
    if(A.x<B.x)
     if(B.x-A.x<=TABLEX/2)
      for(;B.x-A.x!=i;)instr[i++]=RIGHT;
     else
      for(;TABLEX-B.x+A.x!=i;)instr[i++]=LEFT;
    else if(A.x>B.x)
     if(A.x-B.x<=TABLEX/2)
      for(;A.x-B.x!=i;)instr[i++]=LEFT;
     else
      for(;TABLEX-A.x+B.x!=i;)instr[i++]=RIGHT;
    j=i;
    if(A.y<B.y)
     if(B.y-A.y<=TABLEY/2)
      for(;B.y-A.y!=i-j;)instr[i++]=DOWN;
     else
      for(;TABLEY-B.y+A.y!=i-j;)instr[i++]=UP;
    else if(A.y>B.y)
     if(A.y-B.y<=TABLEY/2)
      for(;A.y-B.y!=i-j;)instr[i++]=UP;
     else
      for(;TABLEY-A.y+B.y!=i-j;)instr[i++]=DOWN;
    instr[i]='\0';
    return i;
}
char sentence[50], oldcase, oldletter;
int sentencelength;
typedef struct {
int sentencetoorder[50];
int ordertosentence[50];
int length;
} order;
ordercopy(order*a, order b){
register int i;
for(i=0;++i<sentencelength;) a->sentencetoorder[i]=b.sentencetoorder[i], a->ordertosentence[i]=b.ordertosentence[i];
a->length=b.length;
}
order currentOrder;
movetwo(char*instr,int A, int B){
    register int j; int i=0;
    if(A<B)
    { for(j=A+1;j<B;j++)
      if(currentOrder.sentencetoorder[j]<currentOrder.sentencetoorder[B])
       instr[i++]=CURSORRIGHT;
    }
    else
    { for(j=A;j>B;j--)
      if(currentOrder.sentencetoorder[j]<currentOrder.sentencetoorder[B])
       instr[i++]=CURSORLEFT;
    }
    if(sentence[B]==' '){
        instr[i++]=SPACE;
        instr[i]='\0';
        return i;
    }
    i+=movecasefold(instr+i,letters[oldletter],letters[sentence[B]]);
    oldletter=sentence[B];
    if(casediff(oldcase,sentence[B]))oldcase=sentence[B],instr[i++]=CAPS;
    instr[i++]=APPLY;
    instr[i]='\0';
    return i;
}
moveall(char*instr){
    int j;int i = 0;
    oldcase='a';
    oldletter='1';
    for(j=0;++j<sentencelength;)
        i+=movetwo(instr+i,currentOrder.ordertosentence[j-1],currentOrder.ordertosentence[j]);
    return i;
}
iteration();
main(){
initAllLetters();
gets(sentence+1);*sentence='1';sentencelength=strlen(sentence);
int i;
for(i=0;++i<sentencelength;)currentOrder.sentencetoorder[i]=currentOrder.ordertosentence[i]=i;  
char instr[300];
currentOrder.length=moveall(instr);
puts(instr);
while(iteration());
}
#define inside(item, start, stop) (((start)<=(item))&((item)<(stop)))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
iteration(){
char instr[300];
register int i;
int newstart, start, l;
static order oldorder, neworder;
ordercopy(&oldorder,currentOrder);
ordercopy(&neworder,currentOrder);
for(l=0;++l<sentencelength-1;)
for(start=0;++start<sentencelength-l;)
for(newstart=0;++newstart<sentencelength-l;)
if(start!=newstart){
 for(i=0;++i<sentencelength;)
  if(inside(i,start,start+l))currentOrder.ordertosentence[i-start+newstart]=oldorder.ordertosentence[i];
  else if(inside(i,min(start,newstart),max(start+l,newstart+l)))currentOrder.ordertosentence[newstart<start?i+l:(i-l)]=oldorder.ordertosentence[i];
  else currentOrder.ordertosentence[i]=oldorder.ordertosentence[i];
 for(i=0;++i<sentencelength;) currentOrder.sentencetoorder[currentOrder.ordertosentence[i]]=i;
  currentOrder.length=moveall(instr);
 if(currentOrder.length<neworder.length){
  puts(instr);
  ordercopy(&neworder, currentOrder);
 }
}
ordercopy(&currentOrder, neworder);
return neworder.length<oldorder.length;
}

"gcc virtualKeyboard.c"로 컴파일하십시오. "./a.out"인수없이 실행하십시오. stdin에서 입력을 읽고 stdout에 출력을 씁니다.


지연 죄송합니다-당신의 점수는 193입니다.
Mego

1

C99

여기 해결책에 대한 나의 시도가 있습니다. 62 점을 얻었습니다.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define COORDINATES_ARRAY_SIZE 256
#define MOVEMENT_ARRAY_LEN 1024

#define KEYBOARD_WIDTH 10
#define KEYBOARD_HEIGHT 4

#define DIRECTION_BIT 0x40

#define INITIAL_CHAR '1'

#define SPACE_WEIGHT_INCREMENT 2
#define SPACE_WEIGHT_MAX 10
#define CURSOR_WEIGHT_INCREMENT 2
#define CURSOR_WEIGHT_MAX 10

const char keyboard[KEYBOARD_HEIGHT][KEYBOARD_WIDTH] = {
    {'1','2','3','4','5','6','7','8','9','0'},
    {'q','w','e','r','t','y','u','i','o','p'},
    {'a','s','d','f','g','h','j','k','l','-'},
    {'z','x','c','v','b','n','m','_','@','.'}
};

typedef enum {
    right,
    left,
    up,
    down
} dir;

//iirc it is an omptimization to use int over byte or short despite only using values <10
typedef struct {
    int x;
    int y;
} coordinates;

typedef struct {
    int xmove;
    int ymove;
    dir xdir;
    dir ydir;
} movedata;

void generateCoords(coordinates*);
unsigned int nearestNeighbor(coordinates*, char*, char*, char*, char*, int, int, int, int, int, int, int);
int calcDistance(coordinates*, char, char, movedata*);

int main(int argc, char **argv){
    coordinates coords[COORDINATES_ARRAY_SIZE];
    char moves[MOVEMENT_ARRAY_LEN];
    unsigned int temp, min = 0;
    min--; //largest possible int

    if(argc != 2){
        printf("Invalid Arguments. Usage: virtualKeyboard <string>\n");

    }else{
        int len = strlen(argv[1]);
        int moveCursor, capsLock;
        char *workingString =  malloc(len * sizeof(char));
        generateCoords(coords);
        movedata data;
        for(int spaceWeight = 1; spaceWeight < SPACE_WEIGHT_MAX; spaceWeight += SPACE_WEIGHT_INCREMENT){
            for(int cursorWeight = 1; cursorWeight < CURSOR_WEIGHT_MAX; cursorWeight+= CURSOR_WEIGHT_INCREMENT){
                for(int i = 0; i<len; i++){
                    //zero out arrays
                    moveCursor = 0;
                    capsLock = 0;
                    memset(moves, 0, MOVEMENT_ARRAY_LEN);
                    memset(workingString, 0, len);
                    workingString[0] = argv[1][i];
                    //add initial moves
                    temp = calcDistance(coords, INITIAL_CHAR, argv[1][i], &data);

                    for(int j = 0; j < data.xmove; j++){
                        moves[moveCursor] = data.xdir == right ? 'R' : 'L';
                        moveCursor++;
                    }
                    for(int j = 0; j < data.ymove; j++){
                        moves[moveCursor] = data.ydir == up ? 'U' : 'D';
                        moveCursor++;
                    }
                    if((capsLock==0) != (isupper(argv[1][i])==0)){
                        moves[moveCursor] = 'C';
                        capsLock = capsLock == 0 ? 1 : 0;
                        moveCursor++;
                        temp++;
                    }
                    moves[moveCursor] = 'A';
                    temp++;
                    temp += nearestNeighbor(coords, moves, argv[1], argv[1], workingString, i ,len, len, 1, capsLock, cursorWeight, spaceWeight);
                    if(temp < min){
                        printf("%s\t%s\t%i\n", moves, workingString, temp);
                        min = temp;
                    }

                }
            }
        }
        free(workingString);
    }
    return 0;
}

//optimization so it only searches through the matrix once
void generateCoords(coordinates* coords){
    for(int i = 0; i < KEYBOARD_HEIGHT; i++){
        for(int j = 0; j < KEYBOARD_WIDTH; j++){
            coords[(int)keyboard[i][j]].y = i;
            coords[(int)keyboard[i][j]].x = j;
        }
    }
}

int calcCursorMoves(char* og, char* workingString, char added, int cursor, int len){
    char* inUseWS = calloc(len, sizeof(char));
    char* inUseOG = calloc(len, sizeof(char));
    int indexToAdd = 0, newCursor = cursor;
    for(int i = 0; i < len; i++){
        for(int j = 0; j < len; j++){
            if(workingString[j] != -1 && og[i] == workingString[j] 
                    && inUseOG[i] == 0 && inUseWS[j] == 0){
                inUseOG[i] = 1;
                inUseWS[j] = i+1; // set in use to corresponding working string
                break;
            }
            if(workingString[j] == 0){
                inUseWS[j] = -1; //append -1 to end
                break; //nothing more to see here   
            }
        }
    }
    for(int i = 0; i < len; i++){
        if(og[i] == added && inUseOG[i] == 0){
            indexToAdd = i;
            break;
        }
    }
    for(int i = 0; i < len; i++){
        if(i==0 && indexToAdd < inUseWS[i]-1){
            newCursor = i;
            break;

        }
        if(inUseWS[i]-1 < indexToAdd && (indexToAdd < inUseWS[i+1]-1 || inUseWS[i+1] == -1)){
            newCursor = i+1;
            break;
        }
        if(workingString[i+1] == 0){
            newCursor = i+1;
            break;
        }

    }
    free(inUseWS);
    free(inUseOG);
    return newCursor - cursor;  
}

int calcDistance(coordinates* coords, char from, char to, movedata* data){
    if(to == ' ')
        return 0;
    from = tolower(from);
    to = tolower(to);
    data->xmove = coords[(int)from].x - coords[(int)to].x;
    data->ymove = coords[(int)from].y - coords[(int)to].y;  
    data->xdir = data->xmove >= 0 ? left : right;
    data->ydir = data->ymove >= 0 ? up : down;
    data->xmove = abs(data->xmove);
    data->ymove = abs(data->ymove);
    //wraparound
    if(data->xmove > 5){
        data->xmove = 10 - data->xmove;
        data->xdir = data->xdir == right ? left : right;
    }   
    if(data->ymove > 2){
        data->ymove = 4 - data->ymove;
        data->ydir = data->ydir == up ? down : up;
    }
    return data->xmove + data->ymove;
}

//assumes array is longer than current string
void insertAt(char* str, char toIns, int index){
    char* temp = malloc(strlen(str) + 1);
    strncpy(temp, str, index);
    temp[index] = toIns;
    strcpy(temp+index+1, str+index);
    strcpy(str, temp);  
    free(temp);
}

unsigned int nearestNeighbor(coordinates* coords, char* moves, char* og, 
        char* input, char* workingString, int index, int lenOG, int len,  
        int cursor, int capsLock, int cursorWeight, int spaceWeight){
    if(len  == 1){
        return 0;
    }
    movedata data, bestData;
    char bestChar = '\0';
    unsigned int bestCursor = -1, bestIndex = -1, bestDist = -1;
    unsigned int dist = -1, cursorDist = -1, best = -1;
    char newString[len-1] ;
    memset(newString, 0, len-1);
    strncpy(newString, input, index);
    strcpy(newString+index, input+index+1);
//  printf("%s\t", newString);
    for(int i = 0; i < len-1; i++){
        dist = calcDistance(coords, input[index], newString[i], &data);
        cursorDist = calcCursorMoves(og, workingString, newString[i], cursor, lenOG);
        if(dist + cursorWeight * abs(cursorDist) + spaceWeight * (newString[i] == ' ') + ((capsLock==0) != (isupper(newString[i])==0)) < best){
    //      printf("%c %c %i %i\n", workingString[cursor], newString[i], cursorDist, cursor);
            bestDist = cursorDist;
            bestCursor = cursor + cursorDist;
            best = dist + cursorWeight * abs(cursorDist) + spaceWeight * (newString[i] == ' ') + ((capsLock==0) != (isupper(newString[i])==0));
            bestChar = newString[i];
            bestIndex = i;
            memcpy(&bestData, &data, sizeof(data));
        }
    }
    //append moves
    int i;
    for(i = 0; i < MOVEMENT_ARRAY_LEN && moves[i]!=0; i++);
    if(bestChar != ' '){
        for(int j = 0; j < bestData.xmove; j++){
            moves[i] = bestData.xdir == right ? 'R' : 'L';
            i++;
        }
        for(int j = 0; j < bestData.ymove; j++){
            moves[i] = bestData.ydir == up ? 'U' : 'D';
            i++;
        }
        for(int j = 0; j < abs(bestDist); j++){
            moves[i] = bestDist > 0 ? 'B' : 'F'; 
            i++;
        }
        if((capsLock==0) != (isupper(bestChar)==0)){
            moves[i] = 'C';
            capsLock = capsLock == 0 ? 1 : 0;
            i++;
        }
        moves[i] = 'A';
    } else {
        moves[i] = 'Y';
    }
    //remove weight
    best -= cursorWeight * abs(bestDist);
    best -= spaceWeight * (bestChar==' ');
    insertAt(workingString, bestChar, bestCursor);
    int max = nearestNeighbor(coords, moves, og, newString, workingString, 
             bestIndex, lenOG, len-1, bestCursor+1, capsLock, cursorWeight, spaceWeight);
    //the 1 is for the actual click
    return max + best + 1 + abs(bestDist);
}

작은 단어에는 제대로 작동하는 것 같았고 큰 단어는 수동으로 테스트하기에 너무 커서 큰 단어도 제대로 작동한다고 가정했습니다.

"gcc -std = gnu99"로 컴파일
사용법은 "virtualKeyboard"string ""


1
이것은 많은 입력에서 유효한 명령 시퀀스를 생성하지 못합니다. 예를 들어,에 대한 제 1 출력 Noob 5IS RRRRRUCALCAYRRRRARRRRDBBBAA생산 N33b @, 및 제 2 출력은 LLDAAYRRRRAUBBARBBBCA생성되는 4oo3 e. 프로그램이 처음 세 가지 테스트 사례에 대해서만 유효한 명령 시퀀스 만 인쇄하기 때문에 현재 점수는 5입니다.
Mego
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.