Swipe Type Converter


27

การปฏิวัติต่อไปในการพิมพ์บนแล็ปท็อปได้รับการปล่อยตัวในแรกของเดือนเมษายน 2014 โดย SwiftKey อย่างไรก็ตามฉันต้องการเป็นคนแรกที่เขียน nano clone ที่เป็น swiping แต่เนื่องจากฉันไม่สามารถหา swipe-text ที่ดีในไลบรารี่ของ real-text ได้และฉันไม่สามารถรอพวกเขาได้ฉันถามที่นี่

งาน

เขียนโปรแกรมที่ใช้ในการกวาดนิ้ว - ข้อความและผลลัพธ์เทียบเท่าข้อความจริง ตัวอย่าง:

Input: hgrerhjklo
Output: hello

เมื่อผู้ใช้ทำ:

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างอื่น ๆ :

Input: wertyuioiuytrtjklkjhgfd
Output: world

Input: poiuytrtyuioiugrewsasdfgbhnmkijnbg
Output: programming

Input: poiuygfdzxcvhjklkjhgres
Output: puzzles

Input: cvhjioiugfde
Output: code

Input: ghiolkjhgf
Output: golf

กฎระเบียบ

  • โปรแกรมจะใช้คำว่า swiped หนึ่งคำใน stdin หรือ argv
  • ตัวอักษรตัวแรกและตัวสุดท้ายของอินพุต swiped จะเท่ากับตัวอักษรตัวแรกและตัวสุดท้ายของคำจริง
  • คุณสามารถสันนิษฐานได้ว่าผู้ใช้จะสร้างเส้นตรงที่สมเหตุสมผล แต่คุณสามารถใช้ข้อมูลตัวอย่างเพื่อตรวจสอบสิ่งนี้ (ฉันทำข้อมูลตัวอย่างและฉันจะสร้างข้อมูลทดสอบสุดท้าย)
  • สำหรับอินพุตที่ไม่ชัดเจนคุณสามารถเลือกเอาต์พุตอย่างใดอย่างหนึ่ง แต่ฉันจะพยายามกำจัดความกำกวมทั้งหมดจากข้อมูลทดสอบ
  • คำนี้จะอยู่ในรายการคำนี้ (แต่กวาด) รายการคำจะอยู่ในไดเรกทอรีปัจจุบันและสามารถอ่านได้ (คั่นด้วยการขึ้นบรรทัดใหม่จะมีชื่อว่าwordlistไม่มีส่วนขยาย)
  • การปัดจะมีตัวอักษรตัวพิมพ์เล็กเท่านั้น
  • การปัดอาจมีอักขระที่ซ้ำกันหากผู้ใช้หยุดชั่วคราวบนคีย์
  • โปรแกรมจะต้องส่งออกใน stdout (กรณีไม่สำคัญ)
  • โปรแกรมจะต้องส่งคืน0เป็นรหัสส่งคืน
  • คุณต้องจัดเตรียมคำสั่ง run คำสั่งการคอมไพล์ (หากจำเป็น) ชื่อและพา ธ อินพุตที่จะใช้
  • ใช้ช่องโหว่มาตรฐาน (อาจไม่ช่วยได้)
  • ไม่อนุญาตให้ใช้ไลบรารีที่ไม่ได้สร้างขึ้น
  • แนะนำให้ใช้โซลูชันที่กำหนดขึ้นไม่ใช่กอล์ฟ
  • ไม่มีการเขียนไฟล์เครือข่าย ฯลฯ
  • รหัสของคุณจะต้องทำงานในหนึ่งวินาทีหรือน้อยกว่า (รหัสของคุณจะทำงานหนึ่งครั้งต่อคำ)
  • การให้คะแนนรันบนโปรเซสเซอร์ Intel i7 Haswell โดยมีรหัสเสมือน 4 ตัว (รหัสจริง 2 ตัว) ดังนั้นคุณสามารถใช้เธรดหากคุณต้อง
  • ความยาวโค้ดสูงสุด 5,000 ไบต์
  • ภาษาที่คุณใช้ต้องมีรุ่นฟรี (ไม่ใช่รุ่นทดลอง) สำหรับ Linux (Arch Linux หากมีความสำคัญ)

เกณฑ์การชนะ

  • ผู้ชนะคือทางออกที่แม่นยำที่สุด (ทำคะแนนโดยโปรแกรมควบคุมโดยใช้รายการทดสอบที่ให้มา)
  • ความนิยมคือเบรกเกอร์
  • ตารางคะแนนจะอัปเดตทุกสองสามวัน
  • การขอเวลานอกและการขัดข้องนับเป็นความล้มเหลว
  • ความท้าทายนี้จะเริ่มขึ้นสองสัปดาห์หรือมากกว่านั้นขึ้นอยู่กับความนิยม
  • การให้คะแนนสุดท้ายจะใช้รายการคำแบบสุ่มที่ต่างกัน (ความยาวเท่ากันจากรายการคำเดียวกัน)

อื่น ๆ

กระดานคะแนนปัจจุบัน

รายการทดสอบ ( บันทึก ):

Three Pass Optimizer:Errors: 0/250       Fails: 7/250        Passes: 243/250     Timeouts: 0/250     
Corner Sim:         Errors: 0/250       Fails: 9/250        Passes: 241/250     Timeouts: 0/250     
Discrete Fréchet Distance:Errors: 0/250       Fails: 17/250       Passes: 233/250     Timeouts: 0/250     
Turnaround:         Errors: 0/250       Fails: 18/250       Passes: 232/250     Timeouts: 0/250     
Direction Checker:  Errors: 0/250       Fails: 19/250       Passes: 231/250     Timeouts: 0/250     
Regex Solver:       Errors: 0/250       Fails: 63/250       Passes: 187/250     Timeouts: 0/250

testlist2 ( บันทึก ):

Corner Sim:         Errors: 0/250       Fails: 10/250       Passes: 240/250     Timeouts: 0/250     
Three Pass Optimizer:Errors: 2/250       Fails: 14/250       Passes: 234/250     Timeouts: 0/250     
Turnaround:         Errors: 0/250       Fails: 16/250       Passes: 234/250     Timeouts: 0/250     
Direction Checker:  Errors: 0/250       Fails: 17/250       Passes: 233/250     Timeouts: 0/250     
Discrete Fréchet Distance:Errors: 0/250       Fails: 18/250       Passes: 232/250     Timeouts: 0/250     
Regex Solver:       Errors: 0/250       Fails: 67/250       Passes: 183/250     Timeouts: 0/250

รอบชิงชนะเลิศ

รายการทดสอบ ( บันทึก ):

Corner Sim:         Errors: 0/250       Fails: 14/250       Passes: 236/250     Timeouts: 0/250     
Three Pass Optimizer:Errors: 0/250       Fails: 18/250       Passes: 232/250     Timeouts: 0/250     
Direction Checker:  Errors: 0/250       Fails: 20/250       Passes: 230/250     Timeouts: 0/250     
Turnaround:         Errors: 0/250       Fails: 23/250       Passes: 227/250     Timeouts: 0/250     
Discrete Fréchet Distance:Errors: 0/250       Fails: 30/250       Passes: 220/250     Timeouts: 0/250     
Regex Solver:       Errors: 0/250       Fails: 55/250       Passes: 195/250     Timeouts: 0/250

ทำได้ดีสำหรับทุกคนและ hgfdsasdertyuiopoiuy swertyuiopoijnhg!


"ทางออก" คืออะไร รหัสอยู่ที่ไหน
ลูกบิดประตู

ขอให้เรายังคงอภิปรายนี้ในการแชท
เครื่องมือเพิ่มประสิทธิภาพ


@Optimizer ไม่แน่ใจเกี่ยวกับกรณีอื่น ๆ แต่ " พี oiuytres SE R ES s d fghui o iugfd x CGU ฉันไมโครกรัม XS sdfghjk ลิตร ku Y " ที่มีตัวอักษรทุกของ "ขัดแย้ง" ในการสั่งซื้อยกเว้น, ซึ่งไม่เป็นสองเท่า l
es1024

1
@ ตัววัดประสิทธิภาพดีฉันคิดว่าสิ่งที่คุณส่งมาจะเอาชนะได้ แต่มันก็อยู่ด้านล่าง ดูเหมือนว่าฉันสามารถยอมรับมันได้ดังนั้น ... ฉันควร (ฉันดูเหมือนจะไม่ได้รับการตอบรับจากตัวแทน)? ฉันต้องการยอมรับคนอื่น แต่นั่นไม่ได้ปฏิบัติตามกฎ (เว้นแต่คุณจะมีความคิดที่ดี)
matsjoyce

คำตอบ:


12

เครื่องมือเพิ่มประสิทธิภาพ JavaScript, ES6, Three Pass, 112 187 235 240 241 243 และ231 234 ครั้ง

ตัวกรอง pass สามตัวซึ่งเป็นตัวเลขแรกที่สำคัญในลำดับการกดแป้นและจากนั้นผ่านลำดับผ่านตัวกรองทั้งสาม:

  1. RegEx ที่เกิดขึ้นอย่างหลวมออกจากคีย์วิกฤติและคีย์ช่วยเหลือ สิ่งนี้ให้ผลลัพธ์ที่ถูกต้องสำหรับปุ่มส่วนใหญ่ (ประมาณ 150)
  2. RegEx ที่เข้มงวดทำจากคีย์ที่สำคัญ สิ่งนี้ให้ผลลัพธ์ที่ถูกต้องสำหรับลำดับ 85 พิเศษ
  3. ตัวกรองที่สามเพื่อค้นหาความคลุมเครือในคำตอบที่ใกล้ชิด วิธีนี้ใช้ได้กับกรณีที่ไม่ชัดเจน 40%

รหัส

keyboard = {
  x: {},
  y: ['  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'],
};
for (var i in keyboard.y)
  for (var y of keyboard.y[i])
    keyboard.x[y] = +i*7;
p = C => (x=keyboard.x[C],{x, y: keyboard.y[x/7].indexOf(C)})
angle = (L, C, R) => (
  p0 = p(L), p1 = p(C), p2 = p(R),
  a = Math.pow(p1.x-p0.x,2) + Math.pow(p1.y-p0.y,2),
  b = Math.pow(p1.x-p2.x,2) + Math.pow(p1.y-p2.y,2),
  c = Math.pow(p2.x-p0.x,2) + Math.pow(p2.y-p0.y,2),
  Math.acos((a+b-c) / Math.sqrt(4*a*b))/Math.PI*180
)
corner = (L, C, R, N, W) => {
  if (skip) {
    skip = false;
    return [];
  } 
  ngl = angle(L, C, R);
  if (ngl < 80) return [C + "{1,3}"]
  if (ngl < 115 && p(L).x != p(R).x && p(L).x != p(C) && p(R).x != p(C).x && Math.abs(p(L).y - p(R).y) < 5) return [C + "{0,3}"]
  if (ngl < 138) {
    if (N && Math.abs(ngl - angle(C, R, N)) < 6) {
      skip = true;
      return [L + "{0,3}", "([" + C + "]{0,3}|[" + R + "]{0,3})?", N + "{0,3}"]
    }
    return [C + "{0,3}"]
  }
  return ["([" + L + "]{0,3}|[" + C + "]{0,3}|[" + R + "]{0,3})?"]
}
f = S => {
  for (W = [S[0] + "{1,2}"],i = 1; i < S.length - 1; i++)
    W.push(...corner(S[i - 1], S[i], S[i + 1], S[i + 2], W))
  return [
    new RegExp("^" + W.join("") + S[S.length - 1] + "{1,3}$"),
    new RegExp("^" + W.filter(C=>!~C.indexOf("[")).join("") + S[S.length - 1] + "{1,3}$")
  ]
}
thirdPass = (F, C) => {
  if (!F[0]) return null
  F = F.filter((s,i)=>!F[i - 1] || F[i - 1] != s)
  FF = F.map(T=>[...T].filter((c,i)=>!T[i - 1] || T[i - 1] != c).join(""))
  if (FF.length == 1) return F[0];
  if (FF.length < 6 && FF[0][2] && FF[1][2] && FF[0][0] == FF[1][0] && FF[0][1] == FF[1][1])
    if (Math.abs(F[0].length - F[1].length) < 1)
      for (i=0;i<Math.min(F[0].length, FF[1].length);i++) {
        if (C.indexOf(FF[0][i]) < C.indexOf(FF[1][i])) return F[0]
        else if (C.indexOf(FF[0][i]) > C.indexOf(FF[1][i])) return F[1]
      }
  return F[0]
}
var skip = false;
SwiftKey = C => (
  C = [...C].filter((c,i)=>!C[i - 1] || C[i - 1] != c).join(""),
  skip = false, matched = [], secondPass = [], L = C.length, reg = f(C),
  words.forEach(W=>W.match(reg[0])&&matched.push(W)),
  words.forEach(W=>W.match(reg[1])&&secondPass.push(W)),
  matched = matched.sort((a,b)=>Math.abs(L-a.length)>Math.abs(L-b.length)),
  secondPass = secondPass.sort((a,b)=>Math.abs(L-a.length)>Math.abs(L-b.length)),
  first = matched[0], second = secondPass[0], third = thirdPass(secondPass.length? secondPass: matched, C),
  second && second.length >= first.length - 1? first != third ? third: second: third.length >= first.length ? third: first
)

// For use by js shell of latest firefox
print(SwiftKey(readline()));

รหัสถือว่าตัวแปรที่เรียกว่าwordsมีอยู่ซึ่งเป็นอาร์เรย์ของคำทั้งหมดจากหน้านี้

ดูรหัสการปฏิบัติที่นี่

ดูกรณีทดสอบที่ใช้งานจริงที่นี่

ลิงก์ทั้งสองข้างต้นใช้งานได้เฉพาะกับ Firefox รุ่นล่าสุด (33 ขึ้นไป) (เนื่องจาก ES6)


ได้! ฉันปอกเปลือกออกด้วยเปลือกหอย คุณสามารถใช้keypos.csvไฟล์ที่ถูกต้องได้ทันที ฟังก์ชั่น IO มีวางจำหน่ายแล้วที่developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/…
matsjoyce

ไม่เป็นไร แต่ swipes นั้นทำขึ้นจากมุมคีย์บอร์ดของฉันดังนั้นมันจึงเป็นทางเลือกของคุณ (ดูเหมือนจะไม่ส่งผลกระทบต่อคะแนนของคุณ!)
matsjoyce


240 รอบโดดเด่น! ฉันคิดว่าความคลุมเครือจะป้องกันผลลัพธ์ที่ดีเช่นนั้น ฉันจะสงสัยว่าสิ่งนี้จะทำงานในชุดทดสอบสุดท้ายได้อย่างไร
Emil

@Emil - ใช่ฉันกำลังรอที่จะเห็นเช่นกัน
เครื่องมือเพิ่มประสิทธิภาพ

9

Ruby, Regex Solver - 30 140 176 180 182 187 และ179 183 รอบ

ฉันจะหาคะแนนในภายหลัง นี่คือโซลูชันที่ไร้เดียงสามากที่ไม่คำนึงถึงรูปแบบแป้นพิมพ์:

words = File.readlines('wordlist').map(&:chomp)

swipe = ARGV.shift
puts words.select {|word| word[0] == swipe[0] &&
                          word[-1] == swipe[-1]}
          .select {|word|
              chars = [word[0]]
              (1..word.size-1).each {|i| chars << word[i] if word[i] != word[i-1]}
              swipe[Regexp.new('^'+chars.join('.*')+'$')]
          }.sort_by {|word| word.size}[-1]

ใช้อินพุตจาก ARGV และพิมพ์ผลลัพธ์ ฉันแค่กรองรายการคำด้วยตัวอักษรตัวแรกและตัวสุดท้ายและพวกเขากำลังลองคำที่เหลือทั้งหมดกับอินพุต (กำจัดตัวอักษรที่ซ้ำกันและใช้ regex เช่น^g.*u.*e.*s$คำว่า "guess") และคืนค่าตัวแรกถ้ามี เป็นโซลูชั่นที่หลากหลาย

เรียกใช้เช่น

ruby regex-solver.rb cvhjioiugfde

ใครก็ตามอย่าลังเลที่จะนำขั้นตอนนี้กลับมาใช้ใหม่เป็นตัวกรองแรก - ฉันเชื่อว่ามันจะไม่ทิ้งคำที่ถูกต้องดังนั้นการตรวจสอบเบื้องต้นนี้จะช่วยลดพื้นที่การค้นหาสำหรับอัลกอริธึมที่ดีขึ้นอย่างมาก

แก้ไข: ทำตามคำแนะนำของ OP ตอนนี้ฉันกำลังเลือกผู้สมัครที่ยาวที่สุดซึ่งดูเหมือนจะเป็นวิธีแก้ปัญหาที่เหมาะสม

ขอบคุณ es1024 ที่เตือนฉันเกี่ยวกับตัวอักษรที่ซ้ำกัน


เสร็จสิ้น บันทึกของคุณเป็นที่github.com/matsjoyce/codegolf-swipe-type/blob/master/logs/...ผมคิดว่าปัญหาก็คือว่ามันเลือกจากการแก้ปัญหาที่เป็นไปได้สุ่มซึ่งอาจจะดีขึ้นโดยการเลือกที่ยาวที่สุดหรือสิ่งอื่น
matsjoyce

ผมคิดว่านี่อาจจะโยนออกคำที่ถูกต้องทั้งหมดที่มีตัวอักษรสองตัวเหมือนกันถัดจากแต่ละอื่น ๆ เช่นparadoxicallyเป็นlเพียงครั้งเดียวจะปรากฏในการป้อนข้อมูลมากกว่าสองเท่าเรียกร้องโดย regex ไม่
es1024

@ es1024 อ่าขอบคุณเมื่อฉันเสนออัลกอริทึมนี้กลับไปที่ sandbox เป็นครั้งแรกฉันได้รับรู้จริง ๆ แต่ลืมไปเมื่อวานนี้ จะแก้ไขในภายหลัง
Martin Ender

7

C ++, ระยะFréchetไม่ต่อเนื่อง - 201 220 222 232 และ 232 รอบ

สำหรับฉันปัญหามากเรียกว่าระยะทางFréchetซึ่งน่าเสียดายที่คำนวณยากมาก

เพื่อความสนุกฉันได้ลองใช้วิธีแก้ปัญหาโดยใช้การประมาณแบบไม่ต่อเนื่องที่อธิบายโดย Thomas Eiter และ Heikki Mannila ในการคำนวณระยะทางFréchet (1994) โดยสิ้นเชิง

ตอนแรกฉันใช้วิธีเดียวกันกับคำอื่นในการกรองคำทั้งหมดในรายการซึ่งเป็นลำดับของการป้อนข้อมูล (เช่นการบัญชีสำหรับเหตุการณ์ที่เกิดขึ้นตามลำดับหลายตัวของอักขระเดียวกัน) จากนั้นฉันเติมเส้นโค้งรูปหลายเหลี่ยมจากตัวอักษรถึงตัวอักษรของทุกคำที่มีจุดกึ่งกลางและจับคู่กับเส้นโค้งอินพุต ในที่สุดฉันก็หารทุกระยะด้วยความยาวของคำและจดคะแนนขั้นต่ำ

จนถึงตอนนี้วิธีการใช้งานไม่ได้ดีอย่างที่ฉันหวังไว้ (มันจดจำตัวอย่างโค้ดเป็น "chide") แต่นี่อาจเป็นผลมาจากข้อผิดพลาดที่ฉันยังไม่พบ อื่นแนวคิดอื่นจะใช้รูปแบบอื่นของระยะทางfréchet ("เฉลี่ย" แทน "ความยาวสายจูงสุนัขสูงสุด")

แก้ไข:ตอนนี้ฉันกำลังใช้การประมาณ "ความยาวสายจูงสุนัขโดยเฉลี่ย" ซึ่งหมายความว่าฉันกำลังค้นหาการแมปที่สั่งซื้อระหว่างเส้นทางทั้งสองซึ่งจะลดผลรวมของระยะทางทั้งหมดและหารด้วยระยะทางในภายหลัง

หากตัวอักษรเดียวกันปรากฏขึ้นสองครั้งหรือบ่อยกว่านั้นในพจนานุกรมคำฉันใส่เพียงหนึ่งโหนดในเส้นทาง

#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include<algorithm>
#include<utility>
#include<cmath>

using namespace std;

const double RESOLUTION = 3.2;

double dist(const pair<double, double>& a, const pair<double, double>& b) {
    return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
}

double helper(const vector<pair<double, double> >& a,
        const vector<pair<double, double> >& b,
        vector<vector<double> >& dp,
        int i,
        int j) {
    if (dp[i][j] > -1)
        return dp[i][j];
    else if (i == 0 && j == 0)
        dp[i][j] = dist(a[0], b[0]);
    else if (i > 0 && j == 0)
        dp[i][j] = helper(a, b, dp, i - 1, 0) +
                   dist(a[i], b[0]);
    else if (i == 0 && j > 0)
        dp[i][j] = helper(a, b, dp, 0, j - 1) +
                   dist(a[0], b[j]);
    else if (i > 0 && j > 0)
        dp[i][j] = min(min(helper(a, b, dp, i - 1, j),
                           helper(a, b, dp, i - 1, j - 1)),
                       helper(a, b, dp, i, j - 1)) +
                   dist(a[i], b[j]);
    return dp[i][j];
}

double discretefrechet(const vector<pair<double, double> >& a, const vector<pair<double, double> >& b) {
    vector<vector<double> > dp = vector<vector<double> >(a.size(), vector<double>(b.size(), -1.));
    return helper(a, b, dp, a.size() - 1, b.size() - 1);
}

bool issubsequence(string& a, string& b) {
    // Accounts for repetitions of the same character: hallo subsequence of halo
    int i = 0, j = 0;
    while (i != a.size() && j != b.size()) {
        while (a[i] == b[j])
            ++i;
        ++j;
    }
    return (i == a.size());
}

int main() {
    string swipedword;
    cin >> swipedword;

    ifstream fin;
    fin.open("wordlist");
    map<string, double> candidatedistance = map<string, double>();
    string readword;
    while (fin >> readword) {
        if (issubsequence(readword, swipedword) && readword[0] == swipedword[0] && readword[readword.size() - 1] == swipedword[swipedword.size() - 1]) {
            candidatedistance[readword] = -1.;
        }
    }
    fin.close();

    ifstream fin2;
    fin2.open("keypos.csv");
    map<char, pair<double, double> > keypositions = map<char, pair<double, double> >();
    char rc, comma;
    double rx, ry;
    while (fin2 >> rc >> comma >> rx >> comma >> ry) {
        keypositions[rc] = pair<double, double>(rx, ry);
    }
    fin2.close();

    vector<pair<double, double> > swipedpath = vector<pair<double, double> >();
    for (int i = 0; i != swipedword.size(); ++i) {
        swipedpath.push_back(keypositions[swipedword[i]]);
    }

    for (map<string, double>::iterator thispair = candidatedistance.begin(); thispair != candidatedistance.end(); ++thispair) {
        string thisword = thispair->first;
        vector<pair<double, double> > thispath = vector<pair<double, double> >();
        for (int i = 0; i != thisword.size() - 1; ++i) {
            pair<double, double> linestart = keypositions[thisword[i]];
            pair<double, double> lineend = keypositions[thisword[i + 1]];
            double linelength = dist(linestart, lineend);
            if (thispath.empty() || linestart.first != thispath[thispath.size() - 1].first || linestart.second != thispath[thispath.size() - 1].second)
                thispath.push_back(linestart);
            int segmentnumber = linelength / RESOLUTION;
            for (int j = 1; j < segmentnumber; ++j) {
                thispath.push_back(pair<double, double>(linestart.first + (lineend.first - linestart.first) * ((double)j) / ((double)segmentnumber),
                                    linestart.second + (lineend.second - lineend.second) * ((double)j) / ((double)segmentnumber)));
            }
        }
        pair<double, double> lastpoint = keypositions[thisword[thisword.size() - 1]];
        if (thispath.empty() || lastpoint.first != thispath[thispath.size() - 1].first || lastpoint.second != thispath[thispath.size() - 1].second)
        thispath.push_back(lastpoint);

        thispair->second = discretefrechet(thispath, swipedpath) / (double)(thispath.size());
    }

    double bestscore = 1e9;
    string bestword = "";
    for (map<string, double>::iterator thispair = candidatedistance.begin(); thispair != candidatedistance.end(); ++thispair) {
        double score = thispair->second;
        if (score < bestscore) {
            bestscore = score;
            bestword = thispair->first;
        }
        // cout << thispair->first << ": " << score << endl;
    }
    cout << bestword << endl;

    return 0;
}

ฉันรวบรวมรหัสด้วยเสียงดังกราว แต่ก็g++ ./thiscode.cpp -o ./thiscodeควรทำงานได้ดี


1
ใช่ ในที่สุดใครบางคนได้เพิ่มโซลูชันด้วยชื่ออัลกอริทึมไขมันใหญ่! บันทึกของคุณอยู่ที่github.com/matsjoyce/codegolf-swipe-type/blob/master/logs/ …
matsjoyce

1
ลองค่อนข้างเรียกว่าอัลกอริทึมการเขียนโปรแกรมแบบไดนามิกง่ายสำหรับปัญหาวิทยาศาสตร์คอมพิวเตอร์อ้วน
camelNeck

ด้วยเหตุผลบางอย่างนี้ดูเหมือนว่าจะล้มเหลวสำหรับการป้อนข้อมูลของprogrammijng- pangมันทำให้ฉัน
Riking

มันแปลกมาก ฉันได้รับprogrammingอย่างที่ควรจะเป็น คุณช่วยลบความคิดเห็นในบรรทัด// cout << thispair->first << ": " << score << endl;และวางคะแนนที่ได้หรือไม่?
camelNeck

6

Python 2, Turnarounds, 224 226 230 232 และ230 234 ผ่าน

นี่เป็นวิธีการที่ค่อนข้างตรงไปตรงมา:

  • ค้นหาจุดที่การไหลของตัวอักษรเปลี่ยนทิศทาง (รวมถึงจุดเริ่มต้นและจุดสิ้นสุด)
  • เอาท์พุทคำที่ยาวที่สุดที่มีจุดเปลี่ยนเหล่านี้ทั้งหมด
import sys, csv, re

wordlistfile = open('wordlist', 'r')
wordlist = wordlistfile.read().split('\n')

layout = 'qwertyuiop asdfghjkl  zxcvbnm'
keypos = dict((l, (2*(i%11)+i/11, i/11)) for i,l in enumerate(layout))

#read input from command line argument
input = sys.argv[1]

#remove repeated letters
input = ''.join(x for i,x in enumerate(input) if i==0 or x!=input[i-1])

#find positions of letters on keyboard
xpos = map(lambda l: keypos[l][0], input)
ypos = map(lambda l: keypos[l][1], input)

#check where the direction changes (neglect slight changes in x, e.g. 'edx')
xpivot = [(t-p)*(n-t)<-1.1 for p,t,n in zip(xpos[:-2], xpos[1:-1], xpos[2:])]
ypivot = [(t-p)*(n-t)<0 for p,t,n in zip(ypos[:-2], ypos[1:-1], ypos[2:])]
pivot = [xp or yp for xp,yp in zip(xpivot, ypivot)]

#the first and last letters are always pivots
pivot = [True] + pivot + [True]

#build regex
regex = ''.join(x + ('+' if p else '*') for x,p in zip(input, pivot))
regexobj = re.compile(regex + '$')

#find all words that match the regex and output the longest one
words = [w for w in wordlist if regexobj.match(w)]
output = max(words, key=len) if words else input
print output

เรียกใช้เป็น

python turnarounds.py tyuytrghn

การแก้ปัญหาไม่แข็งแกร่งมาก การกดแป้นผิดครั้งเดียวจะทำให้มันล้มเหลว อย่างไรก็ตามเนื่องจากชุดกรณีทดสอบมีการสะกดผิดน้อยมากจึงทำงานได้ค่อนข้างดีทำให้สับสนในบางกรณีที่เลือกคำที่ยาวเกินไป

แก้ไข:ฉันเปลี่ยนมันเล็กน้อยเพื่อไม่ใช้ไฟล์ตำแหน่งคีย์ที่ให้ไว้ แต่เค้าโครงที่เรียบง่าย สิ่งนี้ทำให้อัลกอริทึมของฉันง่ายขึ้นเพราะในไฟล์คีย์จะไม่เว้นระยะเท่ากัน ฉันสามารถบรรลุผลลัพธ์ที่ดียิ่งขึ้นเล็กน้อยโดยการรวมตัวแบ่งส่วนเสริมสำหรับกรณีที่ไม่ชัดเจน แต่นั่นจะเป็นการเพิ่มประสิทธิภาพมากเกินไปสำหรับชุดทดสอบนี้โดยเฉพาะ ความล้มเหลวบางอย่างยังคงอยู่ซึ่งไม่ได้คลุมเครือจริง ๆ แต่ฉันไม่ได้ใช้อัลกอริธึมง่ายๆเพราะมันจะพิจารณาเฉพาะการเปลี่ยนทิศทางมากกว่า 90 องศาเท่านั้น


ทำได้ดี! ผู้นำคนปัจจุบัน! หากคุณต้องการที่จะดูบันทึก goto github.com/matsjoyce/codegolf-swipe-type/blob/master/logs/
......

@ matsjoyce: ฉันได้เพิ่มความคิดเห็นคำถามที่ชี้ให้เห็นถึงข้อผิดพลาดการสะกดสองฉันคิดว่าฉันได้พบ :)
Emil

ใช่ขอบคุณฉันแค่ให้ตรวจสอบอีกครั้ง แต่ฉันไม่แน่ใจว่าจะทำอย่างไรกับกรณีที่คลุมเครือ
matsjoyce

@matsjoyce: ความคลุมเครือบางอย่างสามารถแก้ไขได้โดยเลือกเส้นทางที่เป็นไปได้อื่น ๆ บนแป้นพิมพ์ เช่นbratsอาจจะเป็นที่ไม่สามารถจะสับสนกับ'bgrdsasdrtrds' breastsอย่างไรก็ตามฉันก็ไม่รังเกียจถ้าคุณทิ้งมันไว้เหมือนเดิม
Emil

จริงที่จะทำงาน ฉันแค่กังวลว่าหากชุดนี้ทำ 'ดีที่สุด' และชุดการให้คะแนนสุดท้ายนั้นไม่ได้รับการพิจารณาอย่างถี่ถ้วนการแก้ปัญหาบางอย่างอาจไม่สามารถทำได้เช่นกัน
matsjoyce

6

PHP, Direction Checker, 203 213 216 229 231 และ229 233 ผ่าน

สิ่งนี้เริ่มต้นด้วยการส่งผ่านพจนานุกรมอย่างง่าย ๆ เพื่อรับรายการคำที่มีตัวอักษรทั้งหมดอยู่ในอินพุต (ที่มาร์ตินทำที่นี่ ) และตรวจสอบl.*แทนที่จะทำซ้ำl.*l.*เมื่อlใด

คำที่ยาวที่สุดที่นี่จะถูกบันทึกในตัวแปร

จากนั้นทำการตรวจสอบอีกครั้งโดยขึ้นอยู่กับปุ่มที่จุดที่การปัดเปลี่ยนทิศทาง (+ / 0 ถึง - หรือ - / 0 ถึง + ใน x หรือ y) รายการคำที่เป็นไปได้จะถูกตรวจสอบกับรายการอักขระนี้และคำที่ไม่ตรงกันจะถูกตัดออก วิธีการนี้อาศัยการเลี้ยวที่คมชัดในการปัดเพื่อความแม่นยำ

คำที่เหลืออยู่ที่ยาวที่สุดจะถูกเอาท์พุทหรือถ้าไม่มีคำใด ๆ จะถูกเอาออกคำที่ยาวที่สุดจากก่อนหน้านี้จะถูกเอาท์พุทแทน

แก้ไข:เพิ่มอักขระทั้งหมดในบรรทัดแนวนอนซึ่งนำไปสู่การเปลี่ยนทิศทางเป็นค่าที่เป็นไปได้ในการตรวจสอบ

ต้องการ PHP 5.4 (หรือแทนที่ทั้งหมด[..]ด้วยarray(..))

<?php
function get_dir($a, $b){
    $c = [0, 0];
    if($a[0] - $b[0] < -1.4) $c[0] = 1;
    else if($a[0] - $b[0] > 1.4) $c[0] = -1;
    if($a[1] < $b[1]) $c[1] = 1;
    else if($a[1] > $b[1]) $c[1] = -1;
    return $c;
}
function load_dict(){
    return explode(PHP_EOL, file_get_contents('wordlist'));
}

$coord = [];
$f = fopen('keypos.csv', 'r');
while(fscanf($f, "%c, %f, %f", $c, $x, $y)){
    $coord[$c] = [$x, $y];  
}
fclose($f);

$dict = load_dict();
$in = $argv[1];
$possib = [];

foreach($dict as $c){
    if($c[0] == $in[0]){
        $q = strlen($c);
        $r = strlen($in);
        $last = '';
        $fail = false;
        $i = $j = 0;
        for($i = 0; $i < $q; ++$i){
            if($last == $c[$i]) continue;
            if($j >= $r){
                $fail = true;
                break;
            }
            while($c[$i] != $in[$j++])
                if($j >= $r){
                    $fail = true; 
                    break;
                }
            if($fail) break;
            $last = $c[$i];
        }
        if(!$fail) 
            $possib[] = $c;
    }
}

$longest = '';
foreach($possib as $p){
    if(strlen($p) > strlen($longest))
        $longest = $p;
}

$dir = [[0, 0]];
$cdir = [0, 0];
$check = '/^' . $in[0] . '.*?';
$olst = []; $p = 1;

$len = strlen($in);
for($i = 1; $i < $len; ++$i){
    $dir[$i] = get_dir($coord[$in[$i - 1]], $coord[$in[$i]]);
    $olddir = $cdir;
    $newdir = $dir[$i];
    $xc = $olddir[0] && $newdir[0] && $newdir[0] != $olddir[0];
    $yc = $olddir[1] && $newdir[1] && $newdir[1] != $olddir[1];
    if($xc || $yc){ // separate dir from current dir
        if($yc && !$xc && $dir[$i - 1][1] == 0){
            $tmp = '';
            for($j = $i - 1; $j >= 0 && $dir[$j][1] == 0; --$j){
                $tmp = '(' . $in[$j-1] . '.*?)?' . $tmp;
            }
            $olst[] = range($p, $p + (($i - 1) - $j));
            $p += ($i - 1) - $j + 1;
            $check .= $tmp . '(' . $in[$i - 1] . '.*?)?';
        }else{
            $check .= $in[$i - 1] . '.*?';
        }
        $cdir = $dir[$i];
    }else{
        if(!$cdir[0]) $cdir[0] = $dir[$i][0]; 
        if(!$cdir[1]) $cdir[1] = $dir[$i][1]; 
    }
}
$check .= substr($in, -1) . '$/';
$olstc = count($olst);
$res = [];
foreach($possib as $p){
    if(preg_match($check, $p, $match)){
        if($olstc){
            $chk = array_fill(0, $olstc, 0);
            for($i = 0; $i < $olstc; ++$i){
                foreach($olst[$i] as $j){
                    if(isset($match[$j]) && $match[$j]){
                        ++$chk[$i];
                    }
                }
                // give extra weight to the last element of a horizontal run
                if(@$match[$olst[$i][count($olst[$i])-1]])
                    $chk[$i] += 0.5;
            }
            if(!in_array(0, $chk)){
                $res[$p] = array_sum($chk);
            }
        }else{
            $res[$p] = 1;
        }
    }
}
$possib = array_keys($res, @max($res));
$newlong = '';
foreach($possib as $p){
    if(strlen($p) > strlen($newlong))
        $newlong = $p;
}
if(strlen($newlong) == 0) echo $longest;
else echo $newlong;

@ matsjoyce พลาดกระสุนที่จุดในขณะที่อ่านคำถาม ตอนนี้โค้ดใช้ตำแหน่งจากkeypos.csv
es1024

@ es1024 แม้ว่าจะไม่ได้เป็นส่วนหนึ่งของกรณีทดสอบ 250 รายการ แต่คำศัพท์นั้นมี 238 คำที่มีตัวอักษรสามตัวติดต่อกัน (จนถึงตอนนี้สิ่งที่ฉันตรวจสอบทั้งหมดคือคำที่ลงท้ายด้วยsss) - ฉันไม่คิดว่าการคัดลอกซ้ำ
Martin Ender

หากคุณต้องการบันทึกของคุณที่github.com/matsjoyce/codegolf-swipe-type/blob/master/logs/…
matsjoyce

3

Python 3, Corner Simulator, 241 และ 240 pass

ขั้นตอนวิธีการ:

  • คัดลอกซ้ำ (ลบการทำงานที่ต่อเนื่องของตัวอักษรเดียวกัน) อินพุตและคำทั้งหมดในรายการคำ (ใช้พจนานุกรมเพื่อให้ได้คำเดิมกลับมา)
  • ลบคำทั้งหมดที่ไม่ได้เริ่มต้นและจบด้วยการเริ่มต้นและสิ้นสุดของการปัดนิ้ว (ผ่านครั้งแรก)
  • ทำ regex จากทุกมุมที่มากกว่า 80 องศาจากนั้นลบคำทั้งหมดที่ไม่ตรงกับนี้ (ผ่านครั้งที่สอง)
  • Regex แต่ละคำ (เช่น Regex Solver) กับการปัดแล้วแบ่งการปัดเป็นชุดของเส้นตรงตามหลักวิชาและตรวจสอบว่าพวกเขาตรงและอาจมีการผลิตโดยนิ้วเคลื่อนไปตามบรรทัดนั้น ( significant_letterฟังก์ชั่นที่สาม)
  • จัดเรียงคำตามความใกล้เคียงกับเส้นตรง
  • จากนั้นใช้ความยาวเป็นตัวแบ่งไทเบรก
  • จากนั้นใช้ระยะทาง Levenshtein เป็นตัวยึดไท่สุดท้าย
  • คำที่ส่งออก!

รหัส:

# Corner Sim

from math import atan, degrees, pi, factorial, cos, radians
import csv
import re
import sys

keys = {}
key_size = 1.5
for line in open("keypos.csv"):
    k, x, y = map(str.strip, line.split(","))
    keys[k] = float(x), float(y)


def deduplicate(s):
    return s[0] + "".join(s[i + 1] for i in range(len(s) - 1) if s[i + 1] != s[i])


def angle(coord1, coord2):
    x1, y1, x2, y2 = coord1 + coord2
    dx, dy = x2 - x1, y1 - y2
    t = abs(atan(dx/dy)) if dy else pi / 2
    if dx >= 0 and dy >= 0: a = t
    elif dx >= 0 and dy < 0: a = pi - t
    elif dx < 0 and dy >= 0: a = 2 * pi - t
    else: a = t + pi
    return degrees(a)


def significant_letter(swipe):
    if len(swipe) <= 2: return 0
    x1, y1, x2, y2 = keys[swipe[0]] + keys[swipe[-1]]
    m = 0 if x2 == x1 else (y2 - y1) / (x2 - x1)
    y = lambda x: m * (x - x1) + y1
    def sim_fun(x2, y2):
        try: return (x2 / m + y2 - y1 + x1 * m) / (m + 1 / m)
        except ZeroDivisionError: return x2
    dists = []
    for i, key in enumerate(swipe[1:-1]):
        sx, bx = min(x1, x2), max(x1, x2)
        pos_x = max(min(sim_fun(*keys[key]), bx), sx)
        sy, by = min(y1, y2), max(y1, y2)
        pos_y = max(min(y(pos_x), by), sy)
        keyx, keyy = keys[key]
        dist = ((keyx - pos_x) ** 2 + (keyy - pos_y) ** 2) ** 0.5
        a = angle((keyx, keyy), (pos_x, pos_y))
        if 90 <= a <= 180: a = 180 - a
        elif 180 <= a <= 270: a = a - 180
        elif 270 <= a <= 360: a = 360 - a
        if a > 45: a = 90 - a
        h = key_size / 2 / cos(radians(a))
        dists.append((max(dist - h, 0), i + 1, key))
    return sorted(dists, reverse=True)[0][0]


def closeness2(s, t):
    # https://en.wikipedia.org/wiki/Levenshtein_distance
    if s == t: return 0
    if not len(s): return len(t)
    if not len(t): return len(s)
    v0 = list(range(len(t) + 1))
    v1 = list(range(len(t) + 1))
    for i in range(len(s)):
        v1[0] = i + 1
        for j in range(len(t)):
            cost = 0 if s[i] == t[j] else 1
            v1[j + 1] = min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost)
        for j in range(len(v0)):
            v0[j] = v1[j]
    return v1[len(t)] / len(t)


def possible(swipe, w, s=False):
    m = re.match("^" + "(.*)".join("({})".format(i) for i in w) + "$", swipe)
    if not m or s:
        return bool(m)
    return closeness1(swipe, w) < 0.8


def closeness1(swipe, w):
    m = re.match("^" + "(.*)".join("({})".format(i) for i in w) + "$", swipe)
    unsigpatches = []
    groups = m.groups()
    for i in range(1, len(groups), 2):
        unsigpatches.append(groups[i - 1] + groups[i] + groups[i + 1])
    if debug: print(unsigpatches)
    sig = max(map(significant_letter, unsigpatches))
    if debug: print(sig)
    return sig


def find_closest(swipes):
    level1, level2, level3, level4 = swipes
    if debug: print("Loading words...")
    words = {deduplicate(i.lower()): i.lower() for i in open("wordlist").read().split("\n") if i[0] == level1[0] and i[-1] == level1[-1]}
    if debug: print("Done first filter (start and end):", words)
    r = re.compile("^" + ".*".join(level4) + "$")
    pos_words2 = list(filter(lambda x: bool(r.match(x)), words))
    if debug: print("Done second filter (sharpest points):", pos_words2)
    pos_words = pos_words2 or words
    pos_words = list(filter(lambda x: possible(level1, x), pos_words)) or list(filter(lambda x: possible(level1, x, s=True), pos_words))
    if debug: print("Done third filter (word regex):", pos_words)
    sorted_pos_words = sorted((closeness1(level1, x), -len(x), closeness2(level1, x), x)
                              for x in pos_words)
    if debug: print("Closeness matching (to", level2 + "):", sorted_pos_words)
    return words[sorted_pos_words[0][3]]


def get_corners(swipe):
    corners = [[swipe[0]] for i in range(4)]
    last_dir = last_char = None
    for i in range(len(swipe) - 1):
        dir = angle(keys[swipe[i]], keys[swipe[i + 1]])
        if last_dir is not None:
            d = abs(last_dir - dir)
            a_diff = min(360 - d, d)
            corners[0].append(last_char)
            if debug: print(swipe[i], dir, last_dir, a_diff, end=" ")
            if a_diff >= 55:
                if debug: print("C", end=" ")
                corners[1].append(last_char)
            if a_diff >= 65:
                if debug: print("M", end=" ")
                corners[2].append(last_char)
            if a_diff >= 80:
                if debug: print("S", end=" ")
                corners[3].append(last_char)
            if debug: print()
        last_dir, last_char = dir, swipe[i + 1]
    tostr = lambda x: deduplicate("".join(x + [swipe[-1]]).lower())
    return list(map(tostr, corners))


if __name__ == "__main__":
    debug = "-d" in sys.argv
    if debug: sys.argv.remove("-d")
    swipe = deduplicate(sys.argv[1] if len(sys.argv) > 1 else input()).lower()
    corners = get_corners(swipe)
    if debug: print(corners)
    print(find_closest(corners))

ทำงานด้วย python3 entries/corner_sim.py


นี่เป็นคำตอบที่ถูกต้อง ไม่จำเป็นต้องสร้างคำตอบให้กับฉัน
เครื่องมือเพิ่มประสิทธิภาพ

@Optimizer ดีการสนทนาเมตาดูเหมือนจะชอบยอมรับคำตอบของคุณดังนั้นฉันดี
matsjoyce

หลังจากอ่านเมตาอภิปรายเท่านั้นฉันก็โอเคกับการตัดสินใจของคุณ แต่มันก็ดี (ดีกว่า) :)
เครื่องมือเพิ่มประสิทธิภาพ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.