Author Topic: Hangman  (Read 6670 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Hangman
« Reply #15 on: June 18, 2019, 06:45:19 pm »
A quick suggestion from me:

Code: [Select]
FUNCTION getBoxLetter$
    DIM m, mx, my, mb, i, K$
    DO
        K$ = UCASE$(INKEY$)
        WHILE _MOUSEINPUT: WEND
        _LIMIT 30 'Add this line into the program to reduce CPU usage as you have an endless loop here which doesn't play nice with other programs.
    LOOP UNTIL LEN(K$) <> 0 OR _MOUSEBUTTON(1)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Hangman
« Reply #16 on: June 18, 2019, 08:20:53 pm »
I don't want to reinvent a whole hangman program, but here's a little idea which you guys might want to incorporate into the games you're creating -- a means to rate difficulty settings.

Take this little program as a quick demo:

Code: QB64: [Select]
  1. DIM SHARED Words(100000) AS STRING
  2. DIM SHARED WordCount(100000) AS LONG
  3. DIM SHARED Difficulty(100000) AS LONG
  4. CONST MinLength = 4, MaxLength = 10
  5.  
  6. SCREEN _NEWIMAGE(800, 600, 32)
  7.  
  8. File$ = "kjv10.txt" 'the King James Version 10 of the bible, from Project Gutenberg
  9.  
  10. PRINT "Processing book..."
  11.  
  12. LoadLists File$
  13. PRINT "There are a total of"; WordCount(0); " words in our book."
  14.  
  15. FilterLists
  16. PRINT "After we filter to exclude words too short, or too long, we have"; WordCount(0); " words left."
  17.  
  18. SortByWord
  19. SortByFrequency
  20.  
  21. FOR i = 1 TO WordCount(0)
  22.     PRINT Words(i); WordCount(i),
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30. SUB LoadLists (File$)
  31.     DIM i AS LONG, u AS LONG
  32.     IF _FILEEXISTS(File$) THEN
  33.         OPEN File$ FOR BINARY AS #1
  34.         FileLength = LOF(1)
  35.         temp$ = SPACE$(FileLength)
  36.         GET #1, 1, temp$
  37.         CLOSE
  38.     ELSE
  39.         temp$ = "The user was too lazy to provide us any word lists to choose from, so this is the default choices which were insterted into the program by Steve, just because he wanted something to work with, even if the end user might be a smart ass like Pete pretends to be sometimes."
  40.     END IF
  41.     book$ = _TRIM$(UCASE$(temp$))
  42.     l = 0
  43.     DO
  44.         l = 0
  45.         l1 = INSTR(oldl, book$, CHR$(32))
  46.         l2 = INSTR(oldl, book$, CHR$(13)) 'CR
  47.         l3 = INSTR(oldl, book$, CHR$(10)) 'LF
  48.         IF l1 > 0 AND l1 < l2 AND l1 < l3 THEN l = l1: GOTO skipcheck
  49.         IF l2 > 0 AND l2 < l3 THEN l = l2: GOTO skipcheck
  50.         IF l3 > 0 THEN l = l3
  51.         skipcheck:
  52.         IF l = 0 THEN EXIT DO
  53.         word$ = UCASE$(MID$(book$, oldl, l - oldl))
  54.         i = 1
  55.         DO UNTIL i > LEN(word$)
  56.             IF ASC(word$, i) < 65 OR ASC(word$, i) > 90 THEN
  57.                 word$ = LEFT$(word$, i - 1) + MID$(word$, i + 1)
  58.             ELSE
  59.                 i = i + 1
  60.             END IF
  61.         LOOP
  62.         newword = -1
  63.         FOR i = 1 TO u
  64.             IF word$ = Words(i) THEN
  65.                 newword = 0: EXIT FOR
  66.             END IF
  67.         NEXT
  68.         IF newword THEN
  69.             u = u + 1
  70.             Words(u) = word$: WordCount(u) = 1
  71.         ELSE
  72.             WordCount(i) = WordCount(i) + 1
  73.         END IF
  74.         oldl = l + 1
  75.         DO UNTIL MID$(word$, oldl) <> CHR$(32) AND MID$(word$, oldl) <> CHR$(13) AND MID$(word$, oldl) <> CHR$(10)
  76.             oldl = oldl + 1
  77.         LOOP
  78.     LOOP
  79.     WordCount(0) = u
  80.  
  81. SUB FilterLists
  82.     FOR i = 1 TO WordCount(0)
  83.         l = LEN(Words(i))
  84.         IF l < MinLength OR l > MaxLength THEN
  85.             'it doesn't fit our length criteria to be a "good word"
  86.         ELSE
  87.             goodword = goodword + 1
  88.             Words(goodword) = Words(i)
  89.             WordCount(goodword) = WordCount(i)
  90.         END IF
  91.     NEXT
  92.     WordCount(0) = goodword
  93.  
  94.  
  95. SUB SortByWord
  96.     DIM gap AS LONG
  97.     'This is the routine I tend to use personally and promote.
  98.     'It's short, simple, and easy to implement into code.
  99.  
  100.     gap = WordCount(0)
  101.     index = WordCount(0)
  102.     DO
  103.         gap = INT(gap / 1.247330925103979)
  104.         IF gap < 1 THEN gap = 1
  105.         i = 1
  106.         swapped = 0
  107.         DO
  108.             IF Words(i) > Words(i + gap) THEN
  109.                 SWAP Words(i), Words(i + gap)
  110.                 SWAP WordCount(i), WordCount(i + gap)
  111.                 swapped = -1
  112.             END IF
  113.             i = i + 1
  114.         LOOP UNTIL i + gap > index
  115.     LOOP UNTIL gap = 1 AND swapped = 0
  116.  
  117. SUB SortByFrequency
  118.     DIM gap AS LONG
  119.     'This is the routine I tend to use personally and promote.
  120.     'It's short, simple, and easy to implement into code.
  121.  
  122.     gap = WordCount(0)
  123.     index = WordCount(0)
  124.     DO
  125.         gap = INT(gap / 1.247330925103979)
  126.         IF gap < 1 THEN gap = 1
  127.         i = 1
  128.         swapped = 0
  129.         DO
  130.             IF WordCount(i) > WordCount(i + gap) THEN
  131.                 SWAP Words(i), Words(i + gap)
  132.                 SWAP WordCount(i), WordCount(i + gap)
  133.                 swapped = -1
  134.             END IF
  135.             i = i + 1
  136.         LOOP UNTIL i + gap > index
  137.     LOOP UNTIL gap = 1 AND swapped = 0
  138.  

So this loads a whole book for us, and then uses it to create a word list from all the words in the book, while also counting the word frequency.  It then sorts our words by alphabetical order and frequency for us.

At this point, all one would need is to come up with a formula they like to generate various difficulty settings.

Personally, I'd go for something like:  Frequency (guessing a word that appears once in a book is going to be a lot harder than guessing a word which appears thousands of times), modified by length of the word (very short words are hard to guess just because there's so many of them to choose from, and very long words are hard to guess just from lack of general familiarity with them), with a modifier for the number of letters used in the word.  (Subdermatoglyphic is a rare word, with a ton of letters, but it has 17 unique letters!  There's not a lot of letters which you can actually guess and not have appear in it, in a game of hangman.)

So just choose a formula you like for a range of difficulty, and then you can make your game customizable so the user can play a Trivial, Easy, Average, Hard, or Impossible game...   ;)

* kjv10.txt (Filesize: 4.23 MB, Downloads: 152)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hangman
« Reply #17 on: June 18, 2019, 09:32:55 pm »
Hi TempodiBasic,

This is brilliant!
Code: QB64: [Select]
  1.         ELSEIF INSTR("àèìòù", K$) THEN
  2.             getBoxLetter$ = MID$("…Š¢£", INSTR("àèìòù", K$), 1)
  3.         END IF
  4.  
I was suspecting there was such a shortening of code.


Hi Steve,

You may be onto something with your word value analysis. It could be more motivating to challenge someone to go for higher levels of play and more word practice. One trick is to get a good formula that does motivate and another is to not make using it so complicated it takes away from playing the game, probably that is the coder's job.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hangman
« Reply #18 on: June 18, 2019, 10:31:56 pm »
OK Steve, you have me thinking.

I wouldn't mind reinventing hangman in the least.

I am wondering how common some of the words are in the King James Version of the Bible to whoever the audience is who would be playing the game, or what ever source you get the word list. There is something to add to formula, how common are the words?

Then there is letter frequencies as you mentioned, along with letter amounts and repetitions there are letter frequencies ie e is my number one vowel, s constanent non vowel... which gets me wondering how an AI would play the game? It would start making a list of words that have e in 2nd position and s in 5th...
How popular letters are is very important for the guessing strategy.

Kind of difficult to narrow all this down to a formula but I guess the AI player is a digression if not distraction.

Maybe look at it a different way, how many guesses should some particular word take? and score it like golf that word is a par 6, oh and that word is a par 9! So collect a set of words that is a par 80 or 100 and the game is on!


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Hangman
« Reply #19 on: June 18, 2019, 11:11:41 pm »
I was thinking more of a simple 5-star type system...

Word Length — Base Difficulty
4-6 letters — 10 points
7-10 letters — 15 points
11+ letters — 20 points

Frequency — Point Modifier
1 time — 2.5
2-5 times — 2
5-10 times — 1.5
11 - 25 times — 1
25 - 100 times — 0.9
101 - 500 times — 0.75
501+ times — 0.5

Difficulty Formula would be:  Base Difficulty * Point Modifier * 26 / Unique Letter Count

So JESUS would be: 10 * 0.5 * 26 / 4 = 32.5

I’d want to run all the words through the formula to see the min/max range, but a simple percentage distribution should give you a nice set of difficulty levels. 

Bottom 20% are Trivial (1 star words)
21-40% are Easy (2 star words)
41 - 60% are Average
61 - 80% are Hard
81%+ are Impossible (5 star words)

Instead of a par system where you try and predict how many guesses a person will need, instead it’s just a simple formula to divide the words into multiple difficult lists.
« Last Edit: June 18, 2019, 11:13:54 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hangman
« Reply #20 on: June 19, 2019, 10:13:14 am »
Quote
I’d want to run all the words through the formula to see the min/max range, but a simple percentage distribution should give you a nice set of difficulty levels.


Hi Steve,

Yes I am very interested in seeing / playing the lists this idea might generate.

I don't see accounting for letter frequency stats which is what people usually base their Hangman strategy on, at least until they have a few letters showing. If the word is made up rare letters like z's and q's it is going to be hard to get them guessed.
 

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hangman
« Reply #21 on: June 19, 2019, 11:45:01 am »
Letter frequencies from Internet lookup:
Quote
E   11.1607%   56.88   M   3.0129%   15.36
A   8.4966%   43.31   H   3.0034%   15.31
R   7.5809%   38.64   G   2.4705%   12.59
I   7.5448%   38.45   B   2.0720%   10.56
O   7.1635%   36.51   F   1.8121%   9.24
T   6.9509%   35.43   Y   1.7779%   9.06
N   6.6544%   33.92   W   1.2899%   6.57
S   5.7351%   29.23   K   1.1016%   5.61
L   5.4893%   27.98   V   1.0074%   5.13
C   4.5388%   23.13   X   0.2902%   1.48
U   3.6308%   18.51   Z   0.2722%   1.39
D   3.3844%   17.25   J   0.1965%   1.00
P   3.1671%   16.14   Q   0.1962%   (1)


ref https://www3.nd.edu/~busiforc/handouts/cryptography/letterfrequencies.html

"EARIOTNSLCUDPMHGBFYWKVXZJQ"  try this string of letters in a Hangman with File Loader

Just go down the string of letters until about S (if not hanged before that).
« Last Edit: June 19, 2019, 11:48:25 am by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Hangman
« Reply #22 on: June 19, 2019, 02:21:14 pm »
For letter frequency, if you’re interested, just use the value of scrabble tiles.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hangman
« Reply #23 on: June 19, 2019, 03:34:16 pm »
Hi TempodiBasic,

One tiny, tiny little detail in your last code:
Code: QB64: [Select]
  1.             IF place AND k$ <> " " THEN       'notice and k$ <> " "  a space!
  2.                 LB(place).Show = 0
  3.                 Letters$ = MID$(Letters$, 1, place - 1) + " " + MID$(Letters$, place + 1)
  4.                 '                                        not "-" should be space " "
  5.                 ' so to blank out letters that are selected, I change from"-" to a space " "
  6.  
« Last Edit: June 19, 2019, 03:36:10 pm by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Hangman
« Reply #24 on: June 19, 2019, 05:48:40 pm »
Yep
you're right but I haven't notice that because I see well "-", but the final choice is to cancel and not to mask the choisen letters, so " "!
Programming isn't difficult, only it's  consuming time and coffee