Making a Hangman

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
td1801
Prole
Posts: 7
Joined: Sat Jul 05, 2014 1:35 pm
Location: Haute Normandie, France

Making a Hangman

Post by td1801 »

Hi !
I'm new here, I'm not a programmer and I'm french. So I guess It will be hard for me to understand everything ! If you can't understand one of my sentence, I'll try my best to explain it to you.
Anyway yesterday I started to do a Hangman game with löve, and I was surprised (and proud :P ) to achieve to do a "working" program. But I can't think of a way to do one thing : the error counter. I tried to increment the error counter when a key is pressed and the character isn't one of the word but it increment the variable too much. I don't know where that come from or how I could resolve this.. :|
Here is the .love :https://www.mediafire.com/?53s7crw5h97999e
And here's my code, that I tried my best to comment :

Code: Select all

 --HANGMAN 03-07-2014


function dictionnaire() --Choose a word and return it's length and a string.
	local rowIndex =0
	local wordList = {}
--The list of words used in the hangman
	dictionnaire = [[abricot
absent
boule
boisson
bombardier
copain
captif
constitution
dent
fleurs
gourmand]]
--Selecting a random word
	local line = math.random(1,11)
	for row in dictionnaire:gmatch ("[^\n]+") do
		rowIndex = rowIndex+1
		wordList[rowIndex] = row
	end
	
	word = wordList[line]
	length = string.len(word)
	return word, length
end

function love.keypressed(key)
     if key and key:match( '%a' ) then character = key end
end

function love.load () --Initialise the variables 
	character = "*"
	victoryCount = 0 
	characterTable = {}
	math.randomseed(os.time())
	word, length = dictionnaire()
--CONVERT TABLE INTO _
	for i=0,length do
		i = i+1
		characterTable[i-1] = "_"
	end
	life = 11 
end

function love.update ()

-- Check if the key pressed is in the word
	if character ~= "*" then
		local i = 0
		local o = 0
		for letter in word:gmatch ("%a") do
			i=i+1		
			if letter == character then
				characterTable[i]= character
			elseif letter ~= character and character ~= "*" then ---Here is the problem..
				life = life -1
			end
		end
		victoryCount = 0
		for letter in word:gmatch ("%a") do --Check the number of correct letters
			o = o + 1 
			if characterTable[o] == letter then
				victoryCount = victoryCount+1
			end

		end

		character = "*"
	end
--Make the table into a string
	characterString = table.concat(characterTable, " ")

function love.draw ()
	love.graphics.print (word,10,1)
	love.graphics.print (characterString,10,12)
	love.graphics.print (victoryCount,10,24)
	love.graphics.print (life,300,24)
	if victoryCount == #word then
		love.graphics.print ("Victory :D",10,34)
	end
	if life <= 0 then
		love.graphics.print ("Defeat",10,44)
	end
end
Thank you for reading this !
User avatar
SneakySnake
Citizen
Posts: 94
Joined: Fri May 31, 2013 2:01 pm
Contact:

Re: Making a Hangman

Post by SneakySnake »

You are decreasing life for each character that does not match the guessed letter.
That's not how hangman works.

In hangman, if your guess hits a letter, it's revealed.
If it does not hit any letters, your life decreases.

Code: Select all

local hit

for letter in word:gmatch ("%a") do
    i = i + 1
    if letter == character then
        characterTable[i] = character
        -- Our guess has hit a letter
        hit = true
    end
end

-- If we haven't hit a letter, we missed, so we decrease life
if not hit then
    life = life - 1
end

User avatar
td1801
Prole
Posts: 7
Joined: Sat Jul 05, 2014 1:35 pm
Location: Haute Normandie, France

Re: Making a Hangman

Post by td1801 »

Thank you for your answer, of course your solution works ! But I have to say that I'm not really seeing any difference in the logic ?
In both case if the letter wasn't good, it decrease life ? Well nevermind, I'll think more deeply about that. Thank you again :)
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Making a Hangman

Post by Robin »

td1801 wrote:In both case if the letter wasn't good, it decrease life ?
This might help you:

In your original: for every letter, if it isn't good, decrease a life.

In SneakySnake's version: if there exists at least one letter that isn't good, decrease a life.

I'm guessing you don't have a background in formal logic either, because that can be counter-intuitive at first, but it'll "click" eventually, if you keep at it. :)
Help us help you: attach a .love.
User avatar
td1801
Prole
Posts: 7
Joined: Sat Jul 05, 2014 1:35 pm
Location: Haute Normandie, France

Re: Making a Hangman

Post by td1801 »

Ok, thank you very much. I just understood, It was simple in fact x)
User avatar
td1801
Prole
Posts: 7
Joined: Sat Jul 05, 2014 1:35 pm
Location: Haute Normandie, France

Re: Making a Hangman

Post by td1801 »

So I'm making a double post, because I have another problem. I searched the forum but I didn't find goods keywords I guess ("function" "string" "update" and "error" are not very precise one x)) ! Because of that I wasn't sure that it needed another post ? And since it's not only an addition to my precedent post, I think it's not against the guidelines ? If it is, i'm sorry ^^

Anyway my problem is that when I call a function I get an error message :
"attempt to call global "dictionnaire" : a string value
But a string is exactly what I want ^^

My function :

Code: Select all

function dictionnaire() --Choose a word and return it's length and a string.
	local rowIndex =0
	local wordList = {}
	dictionnaire = [[
aaa
bbb
word
stuff
]]

	local line = math.random(1,3)
	for row in dictionnaire:gmatch ("[^\n]+") do
		rowIndex = rowIndex+1
		wordList[rowIndex] = row
	end
	
	word = wordList[line]
	length = string.len(word)
	return word, length
end
and where I call it

Code: Select all

function love.update()
	--[[...]]--
	if 	prgmEnd == true and character == "return" then
		character = "*"
		victoryCount = 0 
		errorCount = 0
		characterTable = {}
		errorTable = {}
		math.randomseed(os.time())
		word, length = dictionnaire() -- "attempt to call global "dictionnaire" : a string value "
		timer1 = 0
		timer2 = 0
		timer3 = 0
		timer4 = 0
		timer5 = 0

		for i=0,length do
			i = i+1
			characterTable[i-1] = "_"
		end		
		character = "*"
		prgmEnd = false
	end 
end
I made some test and I think the problem is that I call my function in the update Callback ? But why ?
My .love : http://www.mediafire.com/download/asbmv ... man03.love
Thank you !
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Making a Hangman

Post by Robin »

You gave the function and the string the same name, and that doesn't work. If you replace the line

Code: Select all

dictionnaire = [[
by

Code: Select all

local dictionnaire = [[
it should work. (The string dictionnaire is now local to that function, and so doesn't overwrite the global dictionnaire.)
Help us help you: attach a .love.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Making a Hangman

Post by micha »

The problem is that, inside the function dictionnaire, you overwrite the variable "dictionnaire". Here:

Code: Select all

function dictionnaire() --Choose a word and return it's length and a string.
-- [...]
   dictionnaire = [[
aaa
bbb
word
stuff
]]
-- [...]
end
That means, the first time you call the function, everything is fine, but inside, you change "dictionnaire" and when you call it a second time, it is a string.
You can solve the problem by renaming one of the two things, the function or the string.

One practical advice: I highly suggest renaming the function so that the name tells you, what it is doing. How about "pickRandomWord()"?

And another small thing you can improve: Rather than saving all of the words in one long string, separated by new-line-characters, you can better store it in a table. The function can then be shortened a bit:

Code: Select all

function pickRandomWord()
  local dictionnaire = {'aaa','bbb','word','stuff'}
  local index = love.math.random(1,#dictionnaire)
  local word = dictionnaire[index]
  local length = #word
  return word,length
end
Or even shorter (and less readable)

Code: Select all

function pickRandomWord()
  local dictionnaire = {'aaa','bbb','word','stuff'}
  local word = dictionnaire[love.math.random(1,#dictionnaire)]
  return word, #word
end
Robin was faster.
User avatar
td1801
Prole
Posts: 7
Joined: Sat Jul 05, 2014 1:35 pm
Location: Haute Normandie, France

Re: Making a Hangman

Post by td1801 »

Thank both of you so much :)
Now it's working perfectly ! (And I'm so proud of this little crappy things that I'm finding myself strange !)
micha wrote:One practical advice: I highly suggest renaming the function so that the name tells you, what it is doing. How about "pickRandomWord()"?
Thank you for the advice ! That's definetely less confusing !
micha wrote:And another small thing you can improve: Rather than saving all of the words in one long string, separated by new-line-characters, you can better store it in a table.
Yep, But I chose the string because it was easier to add word :) (And it have learned me some useful things !)
Post Reply

Who is online

Users browsing this forum: No registered users and 13 guests