;license:MIT ;(c) 2018-2020 by 4am & qkumba ; ; text rank - an implementation of the Quicksilver search rank algorithm ; ; Public functions ; - ReloadSearchIndex ; - ResetTextRank ; - FindTitleInCache ; - TextRankCallback (as okvs_iter_values callback) ; ; Public variables ; - InputLength ; [byte] number of characters typed in search mode ; - InputBuffer ; [25 bytes] characters typed in search mode ; ; Zero page variables ; - SelectedIndex ; [byte] index in gSearchStore of currently selected game in search mode ; - MatchCount ; [byte] number of games that match InputBuffer ; - BestMatchScore ; [byte] raw ranking score (0-100) of current best match (updated during TextRankCallback) ; - BestMatchIndex ; [byte] index in gSearchStore of current best match (updated during TextRankCallback) MaxInputLength = 26 InputLength !byte 0 InputBuffer !text " " ;------------------------------------------------------------------------------ ; ReloadSearchIndex ; ; Load indexes to support search UI ; ; in: none ; out: gSearchStore populated ;------------------------------------------------------------------------------ ReloadSearchIndex jsr LoadIndexedFile ; load appropriate search cache into $B000 !word gSearchCache !word kSearchCacheRecord ReloadSearchIndexOnly jsr LoadIndexedFile ; load appropriate search index into $6000 SearchIndexHandle !word gSearchIndex !word kSearchIndexRecord rts FindTitleInCache ldx InputLength cpx #5 bcs @nomatch lda #$20 sta InputBuffer, x +LDADDR gSearchCache +ST16 PTR ldx #$FF -- inx ldy #0 - lda (PTR), y beq @nomatch cmp InputBuffer, x beq @matchchar iny iny iny bne - ; always branches @matchchar iny lda (PTR), y pha iny lda (PTR), y bpl @foundindex sta PTR+1 pla sta PTR cpx InputLength bcc -- @nomatch sec rts @foundindex sta BestMatchIndex+1 pla sta BestMatchIndex clc rts ;------------------------------------------------------------------------------ ; ResetTextRank ; reset the Match variables to allow re-scanning (e.g. because of backspace) ; in: nothing ; out: X, MatchCount, BestMatchScore, BestMatchIndex zeroed ;------------------------------------------------------------------------------ ResetTextRank ldx #0 stx MatchCount stx BestMatchScore dex stx BestMatchIndex stx BestMatchIndex+1 rts ;------------------------------------------------------------------------------ ; TextRankCallback ; callback called by okvs_iter_values on gSearchStore ; to calculate a ranking score for a single game display name ; against the current InputBuffer ; in: A/Y contains address of game display name ; $WINDEX contains 0-based index of the current record in gSearchStore (word) ; out: all registers and flags clobbered ; MatchCount possibly incremented (if this game was a match at all) ; BestMatchScore and BestMatchIndex possibly updated (if this game ; was the best match so far) ;------------------------------------------------------------------------------ TextRankCallback +ST16 zpstring ; A/Y = address of this game display name +LDADDR InputLength +ST16 zpword ldy #0 lda (zpstring),y tax dex cpx InputLength bcc ++ sta gamelength sty runningscore sty runningscore+1 iny sty startat - sty i lda (zpword),y jsr tolower sta tmp ldy startat -- lda (zpstring),y jsr tolower cmp tmp beq + cpy gamelength iny bcc -- ++ rts ; no match :( + ldx #80 cpy startat beq + ldx #10 cpy #1 beq + dey lda (zpstring),y iny cmp #' ' bne + ldx #90 + txa clc adc runningscore sta runningscore bcc + inc runningscore+1 + tya ldy i cpy InputLength bcs + iny sta startat inc startat cmp gamelength bcc - rts ; no match :( + lda runningscore ldx runningscore+1 ldy gamelength jsr @div sta tmp lda runningscore ldx runningscore+1 ldy InputLength jsr @div clc adc tmp lsr adc #0 ; round fractions up pha ldy #1 lda (zpstring),y jsr tolower sta firstletter pla ldx InputBuffer cpx firstletter bne + cmp #85 bcs + adc #15 + cmp BestMatchScore bcc + beq + sta BestMatchScore lda WINDEX sta BestMatchIndex lda WINDEX+1 sta BestMatchIndex+1 inc MatchCount + rts @div sta num1 stx num1+1 sty num2 lda #0 sta remainder sta remainder+1 ldx #16 - asl num1 rol num1+1 rol remainder rol remainder+1 lda remainder sec sbc num2 bcc + sta remainder dec remainder+1 inc num1 + dex bne - lda num1 rts tolower cmp #$41 bcc + cmp #$5B bcs + ora #$20 + rts