linotype 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +104 -0
- data/Rakefile +1 -0
- data/lib/linotype/board.rb +37 -0
- data/lib/linotype/dictionary/dictionary.rb +27 -0
- data/lib/linotype/dictionary/words.txt +235886 -0
- data/lib/linotype/game.rb +107 -0
- data/lib/linotype/move.rb +84 -0
- data/lib/linotype/player.rb +5 -0
- data/lib/linotype/tile.rb +63 -0
- data/lib/linotype/version.rb +3 -0
- data/lib/linotype.rb +11 -0
- data/linotype.gemspec +21 -0
- metadata +68 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sean Devine
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Linotype
|
2
|
+
|
3
|
+
Linotype is a simple ruby implementation of the [Letterpress for iOS](http://www.atebits.com/letterpress/) game mechanic. Letterpress was created by [Loren Brichter](http://twitter.com/lorenb) and is [sold on iTunes](https://itunes.apple.com/us/app/letterpress-word-game/id526619424?ls=1&mt=8). Linotype is meant to be used to write other programs such as simple player command line games, cheating/simulation programs, web-based versions, or whatever else you can think of. My goal is that the community will submit pull requests to this project so that programs can share a common engine.
|
4
|
+
|
5
|
+
The project was inspired by this [tweet by Andy Baio](https://twitter.com/waxpancake/statuses/261966416507465728).
|
6
|
+
|
7
|
+
The project was started by [@barelyknown](http://twitter.com/barelyknown).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
$ gem install linotype
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
The library provides a very simple interface using built in Ruby objects. The goal of the design is to use object oriented design strategies internally but to keep the public interface very simple to make it easy to use and extend.
|
16
|
+
|
17
|
+
Here's a basic rundown of the primary public methods:
|
18
|
+
|
19
|
+
> game = Linotype::Game.new
|
20
|
+
|
21
|
+
> game.board
|
22
|
+
=> [
|
23
|
+
[ {:letter=>"I", :row=>0, :column=>0, :covered_by=>nil, :defended=>false},
|
24
|
+
{:letter=>"E", :row=>0, :column=>1, :covered_by=>nil, :defended=>false},
|
25
|
+
{:letter=>"X", :row=>0, :column=>2, :covered_by=>nil, :defended=>false},
|
26
|
+
{:letter=>"A", :row=>0, :column=>3, :covered_by=>nil, :defended=>false},
|
27
|
+
{:letter=>"C", :row=>0, :column=>4, :covered_by=>nil, :defended=>false}
|
28
|
+
],
|
29
|
+
[ {:letter=>"R", :row=>1, :column=>0, :covered_by=>nil, :defended=>false},
|
30
|
+
{:letter=>"F", :row=>1, :column=>1, :covered_by=>nil, :defended=>false},
|
31
|
+
{:letter=>"D", :row=>1, :column=>2, :covered_by=>nil, :defended=>false},
|
32
|
+
{:letter=>"S", :row=>1, :column=>3, :covered_by=>nil, :defended=>false},
|
33
|
+
{:letter=>"B", :row=>1, :column=>4, :covered_by=>nil, :defended=>false}
|
34
|
+
],
|
35
|
+
[ {:letter=>"B", :row=>2, :column=>0, :covered_by=>nil, :defended=>false},
|
36
|
+
{:letter=>"L", :row=>2, :column=>1, :covered_by=>nil, :defended=>false},
|
37
|
+
{:letter=>"K", :row=>2, :column=>2, :covered_by=>nil, :defended=>false},
|
38
|
+
{:letter=>"Q", :row=>2, :column=>3, :covered_by=>nil, :defended=>false},
|
39
|
+
{:letter=>"P", :row=>2, :column=>4, :covered_by=>nil, :defended=>false}
|
40
|
+
],
|
41
|
+
[ {:letter=>"S", :row=>3, :column=>0, :covered_by=>nil, :defended=>false},
|
42
|
+
{:letter=>"O", :row=>3, :column=>1, :covered_by=>nil, :defended=>false},
|
43
|
+
{:letter=>"K", :row=>3, :column=>2, :covered_by=>nil, :defended=>false},
|
44
|
+
{:letter=>"P", :row=>3, :column=>3, :covered_by=>nil, :defended=>false},
|
45
|
+
{:letter=>"W", :row=>3, :column=>4, :covered_by=>nil, :defended=>false}
|
46
|
+
],
|
47
|
+
[ {:letter=>"L", :row=>4, :column=>0, :covered_by=>nil, :defended=>false},
|
48
|
+
{:letter=>"U", :row=>4, :column=>1, :covered_by=>nil, :defended=>false},
|
49
|
+
{:letter=>"J", :row=>4, :column=>2, :covered_by=>nil, :defended=>false},
|
50
|
+
{:letter=>"Y", :row=>4, :column=>3, :covered_by=>nil, :defended=>false},
|
51
|
+
{:letter=>"D", :row=>4, :column=>4, :covered_by=>nil, :defended=>false}
|
52
|
+
]
|
53
|
+
]
|
54
|
+
|
55
|
+
> game.play({ row: 3, column: 1 }, {row: 3, column: 0})
|
56
|
+
=> true
|
57
|
+
|
58
|
+
> game.moves
|
59
|
+
=> [{:player=>1, :word=>"OS", :valid=>true, :invalid_reason=>nil, :player_sequence=>1, :total_sequence=>1}
|
60
|
+
|
61
|
+
> game.scores
|
62
|
+
=> {1=>2, 2=>0}
|
63
|
+
|
64
|
+
> game.play({ row: 1, column: 0 }, {row: 1, column: 1})
|
65
|
+
=> false
|
66
|
+
|
67
|
+
> game.moves.last
|
68
|
+
=> {:player=>2, :word=>"RF", :valid=>false, :invalid_reason=>"is not in dictionary", :player_sequence=>1, :total_sequence=>1}
|
69
|
+
|
70
|
+
# pass by playing a nil move
|
71
|
+
> game.play
|
72
|
+
=> true
|
73
|
+
|
74
|
+
> game.play
|
75
|
+
=> true
|
76
|
+
|
77
|
+
> game.over?
|
78
|
+
=> true
|
79
|
+
|
80
|
+
> game.winner
|
81
|
+
=> 1
|
82
|
+
|
83
|
+
|
84
|
+
## Dictionary
|
85
|
+
The default dictionary is based on the standard `words` file provide UNIX systems. On Mac OS X this file is located at `/usr/share/dict/words`. This probably isn't the right dictionary for the game, but it's something to start with. It probably makes sense to enable custom dictionaries at the game level by passing in an argument when the game is initialized. But, it'll be easy to extend from here.
|
86
|
+
|
87
|
+
## Feature Ideas
|
88
|
+
|
89
|
+
* Game board loading from string
|
90
|
+
* Game board loading from iOS screen shot
|
91
|
+
* Word suggestions
|
92
|
+
* Game simulation with strategy suggestion
|
93
|
+
* One player command line game
|
94
|
+
* Vowel/consonant ratio setting for random boards
|
95
|
+
* Built in dictionaries for different languages or topics
|
96
|
+
|
97
|
+
## Contributing
|
98
|
+
|
99
|
+
1. Fork it
|
100
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
101
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
102
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
103
|
+
5. Create new Pull Request
|
104
|
+
6. Thanks <3
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Linotype
|
2
|
+
class Board
|
3
|
+
|
4
|
+
attr_accessor :tiles
|
5
|
+
attr_reader :game
|
6
|
+
|
7
|
+
def initialize(game, args={})
|
8
|
+
@game = game
|
9
|
+
@tiles = args[:tiles].collect { |row| row.collect { |tile| Tile.new(self, tile) } }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_random(game, rows=5, columns=5)
|
13
|
+
new(game, tiles: rows.times.collect { columns.times.collect { ('A'..'Z').to_a[rand(0..25)] } })
|
14
|
+
end
|
15
|
+
|
16
|
+
def row_count
|
17
|
+
@row_count ||= tiles.count
|
18
|
+
end
|
19
|
+
|
20
|
+
def column_count
|
21
|
+
@column_count ||= tiles.first.count
|
22
|
+
end
|
23
|
+
|
24
|
+
def row(tile)
|
25
|
+
row_number = 0
|
26
|
+
tiles.each do |row|
|
27
|
+
return row_number if row.include?(tile)
|
28
|
+
row_number += 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def column(tile)
|
33
|
+
tiles[row(tile)].index(tile)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Linotype
|
4
|
+
class Dictionary
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def loaded
|
8
|
+
@loaded ||= new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :words
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@words = Set.new(File.open(words_path).readlines.collect { |word| word.upcase.chomp })
|
16
|
+
end
|
17
|
+
|
18
|
+
def words_path
|
19
|
+
File.dirname(__FILE__) + "/words.txt"
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?(word)
|
23
|
+
words.include?(word.upcase)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|