Created
August 4, 2016 15:18
-
-
Save edvardm/0faf659da54eca0225acdade885b0afd to your computer and use it in GitHub Desktop.
sanapeli.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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