Skip to content

Instantly share code, notes, and snippets.

@edvardm
Created August 4, 2016 15:18
Show Gist options
  • Save edvardm/0faf659da54eca0225acdade885b0afd to your computer and use it in GitHub Desktop.
Save edvardm/0faf659da54eca0225acdade885b0afd to your computer and use it in GitHub Desktop.
sanapeli.rb
# Toiminnallisuus tiiviisti: peli lukee komentoriviltä käytettyjen kirjainten
# määrän. Ohjelma arpoo sen jälkeen näin monta kirjainta. Pelaaja muodostaa
# näistä mahdollisimman monta sanaa syöttämällä joko sanan tai pisteen (.) jos
# ei enää kykene muodostamaan sanoja.
#
# Sana pisteytetään vain, jos se löytyy annetusta sanastosta. Pisteyttämiseen on
# annettu valmiiksi oma funktio. Sanan pitää olla ainakin 2 merkkiä pitkä, jotta
# siitä saa pisteitä.
#
# Kunkin syötteen jälkeen ja lopetettaessa peli kertoo, montako pistettä
# käyttäjällä on.
require 'set'
KÄDEN_KOKO = (ARGV[0] || 7).to_i
VOKAALIT = 'aeiouy'.chars # oikeastaan y on sekä vokaali että konsonantti
KONSONANTIT = ('a'..'z').reject { |mrk| VOKAALIT.include?(mrk) }
def lue_rivit(sanatiedosto)
sanat = File.readlines(sanatiedosto).map { |w| w.strip.downcase }
puts "Ladattu #{sanat.size} sanaa"
Set.new(sanat) # taulukkokin käy, mutta O(1) haku
end
def jakauma_hash
Hash.new { |h, k| h[k] = 0 }
end
def jaa_kirjaimet(lkm)
# huom! ensimmäinen versio voi hyvin tuottaa vain lkm satunnaista kirjainta
jakaja = (rand(2) + 2) # palauttaa 2 tai 3, koska rand(2) => {0, 1}
vokaaleja = lkm / jakaja
konsonantteja = lkm - vokaaleja
käsi = jakauma_hash
vokaaleja.times{ käsi[VOKAALIT.sample] += 1 }
konsonantteja.times{ käsi[KONSONANTIT.sample] += 1 }
käsi
end
def käsi_taulukko(käsi)
käsi.map { |mrk, lkm| [mrk]*lkm }.flatten
end
def näytä_käsi(käsi)
puts "Pelaajan käsi: " + käsi_taulukko(käsi).join(' ')
end
def merkkijakauma(mjono)
mjono.chars.each_with_object(jakauma_hash) { |mrk, o| o[mrk] += 1 }
end
def sana_kelvollinen?(sanasto, käsi, syöte)
syöte.size > 1 &&
sanasto.include?(syöte) &&
merkkijakauma(syöte).all? { |kirjain, lkm| käsi[kirjain] >= lkm }
end
# https://www.wikiwand.com/en/Scrabble_letter_distributions
KIRJAIN_PISTEET = {
'aeiounrtls' => 1,
'dg' => 2,
'bcmp' => 3,
'fhvwy' => 4,
'k' => 5,
'jx' => 8,
'qz' => 10
}
def kirjain_pisteet(kirjain)
pari = KIRJAIN_PISTEET.detect { |mjono, pisteet| mjono.include?(kirjain) }
if pari
pari[-1]
else
warn "kirjainta #{kirjain} ei löytynyt pistetaulukosta!"
0
end
end
def scrabble_pisteet(syöte)
pisteet = syöte.chars.inject(0) { |acc, mrk| acc + kirjain_pisteet(mrk) }
pisteet += 50 if syöte.size == KÄDEN_KOKO
pisteet
end
def laske_pisteet(sanat, syöte, käsi)
if sana_kelvollinen?(sanat, käsi, syöte)
scrabble_pisteet(syöte)
else
0
end
end
def poista_sana_kädestä(sana, käsi)
sana.each_char do |kirjain|
käsi[kirjain] -= 1 if käsi[kirjain]
end
käsi.reject! { |_, lkm| lkm == 0 }
end
def pelisilmukka(sanat, pelaajan_käsi)
löydetyt_sanat = []
summa = 0
loop do
näytä_käsi(pelaajan_käsi)
print "Kirjoita sana, tai '.' lopettaaksesi: "
syöte = STDIN.gets.strip
break if syöte == '.'
pisteet = laske_pisteet(sanat, syöte, pelaajan_käsi)
if pisteet > 0
print "Sait #{pisteet} pistettä. "
löydetyt_sanat.push(syöte)
poista_sana_kädestä(syöte, pelaajan_käsi)
summa = summa + pisteet
end
puts "Tämänhetkiset pisteesi: #{summa}"
end
summa
end
# testejä
fail 'pistelasku' unless scrabble_pisteet('car') == 5
fail 'merkkijakauma' unless merkkijakauma('foo') == {'f' => 1, 'o' => 2}
# pääohjelma
sanasto = lue_rivit('/usr/share/dict/words')
kirjaimet = jaa_kirjaimet(KÄDEN_KOKO)
alku = Time.now
lopullinen_summa = pelisilmukka(sanasto, kirjaimet)
kulunut_aika = Time.now - alku
puts "Sait #{lopullinen_summa} pistettä, aikasi oli #{kulunut_aika}s"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment