[Question]
  [
*Note:* There are some rude words in this question.
There's an implicit puzzle posed in this [classic Monty Python sketch](https://www.youtube.com/watch?v=-gwXJsWHupg) (you can also ready the [script](http://www.montypython.net/scripts/wood.php) online). 
Various phrases are described as being 'woody' or 'tinny', and one is described as being 'PVC'.
Given a phrase, respond with its type according to the following lists:
### `woody`:
```
gone
sausage
seemly
prodding
vacuum
bound
vole
caribou
intercourse
pert
thighs
botty
erogenous zone
ocelot
wasp
yowling
```
### `tinny`:
```
litter bin
newspaper
antelope
recidivist
tit
simpkins
```
### `PVC`:
```
leap
```
---
## Rules
* If the input belongs to one of the above lists, the output should be `woody`, `tinny` or `PVC`, accordingly.
* All input is lower case.
* Any behaviour is acceptable for phrases which are not listed above.
* The fewest bytes in the answer wins.
  
[Answer]
# [Python 2](https://docs.python.org/2/), ~~99~~ ~~73~~ ~~65~~ ~~64~~ 63 bytes
```
lambda s:'PVC'*('ea'in s)or'wtoiondnyy'[s[-2:]in'instperit'::2]
```
[Try it online!](https://tio.run/##XZGxTsQwDIZ3nqKb75BYOlZi4gUYEAzHDWnj61mkdhQnV5WXL4EBYqbo/@M432/HLV@F@/3y@L4Ht4zedTrA8@sT3B8AHRB3epQEaxYS9rxtcNLTQz@cieul5oiJMgxDf95jIs7wJuK3Ae5@VHc5wCyMcPzT6oq62VqIS9haJybxnnhuvZubSllaZ5TC3pRIMI0nl6gWtVY9ME1SkprKmiO3Ol9pvqr9LGfDiElmZCnaff6LKBMGMe1Wp7HVm6yhiQcvxGymFihXzm6sY26eMa4aXWVtTVcTBYmGIOFEnm6kNhQZqbTEj7rEX4q6d8OA7ht6/wI "Python 2 – Try It Online")
Alternatives also with 63 bytes:
```
lambda s:'PVC'*('ea'in s)or'wtoiondnyy'[s[-6::5]in'dtenmsr'::2]
lambda s:'PVC'*('ea'in s)or'wtoiondnyy'[s[::5]in'lrinaosit'::2]
```
[Answer]
# [Python 2](https://docs.python.org/2/), 62 bytes
```
lambda n:'wtPoiVonCdn yy'[hash(n)%97%78%28%15%2+('ea'in n)::3]
```
[Try it online!](https://tio.run/##LZA9bsMwDIX3nIKLoBjNErdFEgOZeoFOXdIMiqXYRGVSEOUY7uVdS@nEj396Twxz6pnq5X7@XrwZbtYANXpKn4xfTB@WYJ71pTfSb6lSp4M6HFV9VPt3Vb9stTMaCahqmtfrMnG0Ame4aO9M0DvQHlNyEW5IOSM3STDBxZwYSs5zcJmja9HiAyXlLGEJgkP4QZLMHVMZFDOK6Z7o3ODnTCGytUhd5odpx3HIdOORbCmxLwutibgWM@KqHVseo5TO6ugp3GPXy3M5pfK2i9w54lHg998Ct6vtMj4ZKZ@cefJZ/rrZ3DlCvgKsRynXaDYAIa56oNX@TRpQokHBNjd3cC@xqpY/ "Python 2 – Try It Online")
## How?
This submission uses the fact that the `hash` function is stable for strings in Python 2. Each valid input has a valid output. The brute-forced repeated modulo `%97%78%28%15%2` returns `1` for all *tinny* and *PVC* words and `0` for *woody* words. By adding the value of `('ea' in n)` to it, we get `2` instead of `1` for the input 'leap'. Here is a table of all values:
```
+----------------+----------------------+----------------+-------------+-------+
| word           | hash                 | %97%78%28%15%2 | +('ea'in n) | type  |
+----------------+----------------------+----------------+-------------+-------+
| leap           | 5971033325577305778  | 1              | 2           | PVC   |
+----------------+----------------------+----------------+-------------+-------+
| litter bin     | 2393495108601941061  | 1              | 1           | tinny |
| newspaper      | 1961680444266253688  | 1              | 1           | tinny |
| antelope       | -2930683648135325182 | 1              | 1           | tinny |
| recidivist     | -1480015990384891890 | 1              | 1           | tinny |
| tit            | -1495230934635649112 | 1              | 1           | tinny |
| simpkins       | 672871834662484926   | 1              | 1           | tinny |
+----------------+----------------------+----------------+-------------+-------+
| gone           | 3644900746337488769  | 0              | 0           | woody |
| sausage        | 4880706293475915938  | 0              | 0           | woody |
| seemly         | -8112698809316686755 | 0              | 0           | woody |
| prodding       | 7325980211772477495  | 0              | 0           | woody |
| vacuum         | -5283515051184812457 | 0              | 0           | woody |
| bound          | -6522768127315073267 | 0              | 0           | woody |
| vole           | -7823607590901614336 | 0              | 0           | woody |
| caribou        | -3644594841083815940 | 0              | 0           | woody |
| intercourse    | 2499732157679168166  | 0              | 0           | woody |
| pert           | 4142553773863848247  | 0              | 0           | woody |
| thighs         | -3490317966011085195 | 0              | 0           | woody |
| botty          | -6522767127163072681 | 0              | 0           | woody |
| erogenous zone | 7046120593231489339  | 0              | 0           | woody |
| ocelot         | -6961879712146820842 | 0              | 0           | woody |
| wasp           | -3668927459619339511 | 0              | 0           | woody |
| yowling        | 6823632481520320220  | 0              | 0           | woody |
+----------------+----------------------+----------------+-------------+-------+
```
The type to return is now extracted from the string `'wtPoiVonCdn yy'` by taking every third character, starting at the calculated index.
[Answer]
# JavaScript (ES6), Chrome/Edge, 54 bytes
Because the behavior of `parseInt()` on large inputs with a radix of 36 is [implementation-dependent](https://www.ecma-international.org/ecma-262/6.0/#sec-parseint-string-radix), this one doesn't work with SpiderMonkey (Firefox).
```
s=>[,'PVC',,'Tinny'][parseInt(s+383,36)%69%7]||'Woody'
```
[Try it online!](https://tio.run/##bZIxT8MwEIV3fkVVqXIjAkukQoXKwsTGgGAIHVznmh44d5bPSRXU/x5MxQDoNut7Ovu9d363gxUXMaQr4gam/WaSzX1dmqeXB1OW5hmJRrOtg40Cj5SWclndVmW1Khar9eJmezqZV@ZmNJNjEvZw7bldmvoMt6a4u/jN98t5ywTzoviPxfZiW1UB6PyoCCFy0yC1ijRY1/edIuy4p0YbyGcFOxsxjygKUoLouM@taNYgJgWnA7YHUW2lpEWEyC0Q9zL71GtjB561p45WgoJHPvqfyv5I5o3q86q1lXlMOexsh6TcSHCUYHNgRbO5JM9BMx7BYYMDitoTalSwCx9IoprP31W1Dva7hukL "JavaScript (Node.js) – Try It Online")
### How?
The hash function returns **3** for Tinny words, **1** for PVC and either **0**, **4**, **5** or **6** for Woody words. The words marked with an asterisk are implicitly truncated because *space* is considered as an invalid character by **parseInt()**.
```
word           | +383           | base 36 -> decimal    | mod 69 | mod 7
---------------+----------------+-----------------------+--------+------
gone           | gone383        |           36318994131 |   54   |   5
sausage        | sausage383     |      2874302392811475 |   42   |   0
seemly         | seemly383      |        80120017777107 |    6   |   6
prodding       | prodding383    |     94214834629477200 |   12   |   5
vacuum         | vacuum383      |        88266035564499 |   60   |   4
bound          | bound383       |          916101808275 |    6   |   6
vole           | vole383        |           68967369939 |   39   |   4
caribou        | caribou383     |      1249086300450771 |   63   |   0
intercourse    | intercourse383 | 3.183324871563264e+21 |   11   |   4
pert           | pert383        |           55312791699 |   21   |   0
thighs         | thighs383      |        83184557510739 |    6   |   6
botty          | botty383       |          916052399571 |   63   |   0
erogenous zone | erogenous (*)  |        41664605989780 |    7   |   0
ocelot         | ocelot383      |        68678794158483 |   39   |   4
wasp           | wasp383        |           70309896339 |   63   |   0
yowling        | yowling383     |      3523299657958227 |   39   |   4
---------------+----------------+-----------------------+--------+------
litter bin     | litter (*)     |            1301413923 |   24   |   3
newspaper      | newspaper383   |   3081816298632183000 |    3   |   3
antelope       | antelope383    |     38980419895881940 |   24   |   3
recidivist     | recidivist383  | 129824740122576960000 |    3   |   3
tit            | tit383         |            1785109395 |   45   |   3
simpkins       | simpkins383    |    104264583727840850 |   24   |   3
---------------+----------------+-----------------------+--------+------
leap           | leap383        |           46576922259 |   57   |   1
```
---
# Previous version, ~~59~~ 57 bytes
```
s=>['Woody','Tinny','PVC'][82178>>parseInt(s,35)%50%26&3]
```
[Try it online!](https://tio.run/##bZIxTwMxDIV3fkVVqeROKghaFSqhdmFiY0AwHDekOfdqSO0ozrU6/vyRVgyAPCV6n@w8P@fDHqy4iCFdETcwbFeDrNaVeWNuejM1L0h0Op9fH01dLWe398v1Otgo8ESpkOl8UU4WN5PZ3eW8HhyTsIdrz21hqnOL2pQPF7/1bTFumWBclv9lsZ3YViUAe98rIERuGqRWQQfrum6vgA131GgF@a7IzkbMJQpBShAddzkLzRrEpMhph@1OVFspaSNC5BaIOxl96bGxA8/aU0crQZF7PvqfyP4g807VedvayjymPOxog6R0JDhKsHlghdkckuegGY/gsMEDipoTaqrgPnwiiWo@f1HVOthTDMM3 "JavaScript (Node.js) – Try It Online")
### How?
Below are the different steps of the function for each input. The result of the first modulo is an approximation within the precision of JS numbers and is mathematically invalid for *intercourse*.
```
input          | base-35 -> dec.   | %50 | %26 | 00000000010100000100000010
---------------+-------------------+-----+-----+---------------------------
gone           |            716219 |  19 |  19 |      00------------------>
sausage        |       52042888324 |  24 |  24 | 00----------------------->
seemly         |        1492249219 |  19 |  19 |      00------------------>
prodding       |     1659396207121 |  21 |  21 |    00-------------------->
vacuum         |        1643736697 |  47 |  21 |    00-------------------->
bound          |          17573443 |  43 |  17 |        00---------------->
vole           |           1359274 |  24 |  24 | 00----------------------->
caribou        |       22625709220 |  20 |  20 |     00------------------->
intercourse    | 51532867489988450 |  48 |  22 |   00--------------------->
pert           |           1089999 |  49 |  23 |  00---------------------->
thighs         |        1549436973 |  23 |  23 |  00---------------------->
botty          |          17572449 |  49 |  23 |  00---------------------->
erogenous zone |    33308397234728 |  28 |   2 |                       00->
ocelot         |        1279159344 |  44 |  18 |       00----------------->
wasp           |           1385255 |   5 |   5 |                    00---->
yowling        |       63810499496 |  46 |  20 |     00------------------->
litter bin     |        1131250042 |  42 |  16 |         01--------------->
newspaper      |    52754217228642 |  42 |  16 |         01--------------->
antelope       |      687218151914 |  14 |  14 |           01------------->
recidivist     |  2160354371100934 |  34 |   8 |                 01------->
tit            |             36184 |  34 |   8 |                 01------->
simpkins       |     1835782971008 |   8 |   8 |                 01------->
leap           |            917900 |   0 |   0 |                         10
```
[Answer]
## [Retina](https://github.com/m-ender/retina/wiki/The-Language), ~~39~~ ~~38~~ 36 bytes
*Saved 1 byte by using three substitution pairs as in Adám's answer.*
```
L#-3$0`ea
PVC
.p.|is?t
tinny
$
woody
```
[Try it online!](https://tio.run/##Fc6xagMxEATQfr7CEAfSxCTkA1KkSJPCVWqvdYu8RLcrtNIdMv73i64aBobHFK6i9L49v3xftp@n14/j24UJ598vnPLpIf5ZMRbaccRqNvVti6YMp@YURzLPqSMXmybRiIVCazOu1nTCYokRqMioEK1cgrXijMxlsDeJNx/TWju4WGS15of7zlvgZBUreUa3Ne10kjqEw1UUyqtnGgpoqMkyo3CQSRbx/W@Fy5z/RB2JKf8D "Retina – Try It Online")
I got the `.p.|is*t` regex from [Peter Norvig's regex golfer](http://nbviewer.jupyter.org/url/norvig.com/ipython/xkcd1313-part2.ipynb).
[Answer]
# Java 8, ~~81~~ ~~80~~ 67 bytes
```
s->s.charAt(2)<98?"PVC":s.matches(".*(.p.|is?t).*")?"tinny":"woody"
```
[Regex from *@MatrinEnder*'s Retina answer.](https://codegolf.stackexchange.com/a/157257/52210)
[Try it online.](https://tio.run/##rZJNb9wgEIbv/RUjTnaWkCqn1pvNKuq5UaVW7aHqgcXEJsGAmLF33Ta/fTv2eiNVSm@VQDAwvDzz8agHfRmTDY/109F4jQgftQu/3gC4QDY/aGPhfjIBPlN2oQFTLBss13z@zJMHkiZn4B4CbOCIl7eoTKvzHRXX5c37d1vx6esHUaHqNJnWYiHURaGS@u1wS6W6EOVWkAthFJXYx1iP4rg@Cad@51l40R@iq6FjwgXi@w9dnuiuruDb9LCarYeYz5iHSjQxWIm6R93wam3nR5lyrGu@l4M2fd/JXexDLYforTQ6OzblnAET@4xWJptJUuuaFtmVaJQ2x8aG2CP8nOSjsT6S3GtMcox7z9JCYfKOCiFFWc5YAGSRisOcOc7oiGQ7FXtSiVnJh2K5OYf0ZcrJayGxLsPBzgUZ7B6TZkCpGdhzNWW2xtVucMjMjiS6Lj25gP8BiMt4wpnfCW91Eq/0wVyn2eWMXP7VRNli74lbJSjz8vthtREViPVLuEwAbnNQ3oaGWkZxq9XN9dv15Aji38yH1Ul/AXs@/gE)
**Original answer: ~~81~~ 80 bytes**
```
s->"anetisilire".contains(s.substring(0,2))?"tinny":s.charAt(2)<98?"PVC":"woody"
```
[Try it online.](https://tio.run/##rZJNb9swDIbv@xWETjaiukVOW9KsGHZeMWDDdhh2UGTWUStLhkg59ob@9ox2nAIDutsACxYl6uXDj0fTm6vYYXisn07WGyL4ZFz4/QbABcb0YCzC/WQCfOHkQgO2WDZUbuX8WZZ8xIadhXsIsIMTXb1XJiA7ct4lVJWNgUWXCqoo72kWKG70uizvFLsQRrWhyh5M@sDFurx99/ZOff72UW3UMcZ6VKftOUqX916iLMH66GpoRXYh@vHTlGfU62v4Pj3czNZDTBfmYaOaGFCTyWQa@SO2ftRdinUt97o3NudW72MOte6jR21NcmLquRw25kSoO0ys@eCaA4kr86gxxQZDzAS/Jvlo0UfWR0OdHuPRi7SqqPOOC6VVWc5YAIzExTCXUco7EmNbxcxVJ6zsQ7HcXFL6OhXqtZREV@Bg74IOeKTOCKA2AuyltTqhdbXrHQmzY02u7Z6kFf8BSFp0xpnfKY@mU68Mxdyn2eWCXP41UQkpe5a5CZV9iT6sdmoDavuSrhCA2w2Vx9DwQVDcanW7vtlOjqD@zTyszvoL2PPpDw)
**Explanation:**
```
s->                  // Method with String as both parameter and return-type
  "anetisilire".contains(s.substring(0,2))?
                     //  If the first two letters of the input are present in "anetisilire"
    "tinny"          //   Output "tinny"
   :s.charAt(2)<98?  //  Else-if the third character of the input is an 'a'
    "PVC"            //   Output "PVC"
   :                 //  Else:
    "woody"          //   Output "woody"
```
**Additional explanation:**
```
litter bin:  anetisi(li)re
newspaper:   a(ne)tisilire
antelope:    (an)etisilire
recidivist:  anetisili(re)
tit:         ane(ti)silire
simpkins:    aneti(si)lire
```
1. None of the first two letters of the `woody` words are present in this String above, nor is `le` from `leap`.
2. None of the `woody` words has an `a` as third letter, so that is used to get `leap` to `PVC` if it's not a `tinny` word.
3. Everything else is a word from the `woody` list.
[Answer]
# [Haskell](https://www.haskell.org/), 61 bytes
```
f(a:b:_)|b=='i'||elem a"ran"="tinny"|a=='l'="PVC"|1>0="woody"
```
[Try it online!](https://tio.run/##TY67asQwEEX7fIWYxrsQQtIuKE3qQKo0IYSxPWsPK2mEHmsc/O@OSCFZlc694urMGG9kzL5fT3jpLz/nrde6427byJBVCAEdaEjs3Aobls50Gj4@32B7eX3WsIiMK@wW2SmtLPp3dfKBXVJP6np@UOV8KZjEEfzDo4KIOeJ0YCJr1oo@yDiym2pwxyFnW7GX7MZWimlLAwYudeWiQWGQHGJ74ymkCmnmaY6H6ZSaCAWZyEmO6veoLwMZaRMLRl9hlcUc1Q2nYqB6djVytESPxaImWCyN@PZDoIFHvnM8iHK7R7b@xq5pG0IP6nv/Aw "Haskell – Try It Online")
Uses this hand-found logic:
* Words with second letter `i` or first letter `r`, `a`, or `n` are `tinny`
* Any other word starting with `l` (`leap`) is `PVC`
* Anything else is `woody`
Lynn saved a byte by checking `leap` by its first letter.
[Answer]
# [QuadS](https://tio.run/##KyxNTCn@//9RV/Oj3q1cqYlcegV6NZnF9iVcKlwBYc5cJZl5eZVc5fn5KZX//@ekJhYAAA "QuadS – Try It Online"), ~~34~~ 32 bytes
Shamelessly uses [Martin Ender's system](https://codegolf.stackexchange.com/a/157257/43319), including the regex from [Peter Norvig's regex golfer](http://nbviewer.jupyter.org/url/norvig.com/ipython/xkcd1313-part2.ipynb).
```
⊃⍵
ea
.p.|is?t
$
PVC
tinny
woody
```
[Try it online!](https://tio.run/##KyxNTCn@//9RV/Oj3q1cqYlcegV6NZnF9iVcKlwBYc5cJZl5eZVc5fn5KZX//@ekJhYAAA "QuadS – Try It Online")
`⊃⍵` pick the first occurrence of 
`ea` "ea"  
`.p.|is?t` "p" surrounded by letters OR "i" and "t" with an optional "s" between them  
`$` end of input 
… but substituting the matches with the corresponding one of the following:
`PVC`  
`tinny`  
`woody`
---
The equivalent 43-byte [Dyalog APL](https://www.dyalog.com/) function is:
```
⊃'ea' '.p.|is?t' '$'⎕S'PVC' 'tinny' 'woody'
```
Try all the cases online!
[Answer]
# [C (gcc)](https://gcc.gnu.org/), ~~81~~ ~~80~~ 79 bytes
-1 byte thanks to @ceilingcat.
```
h;f(char*s){puts(index("HzYfPW",h=*s^s[1]*4&127)?"Tinny":h<120?"Woody":"PVC");}
```
[Try it online!](https://tio.run/##VVJNT@MwED3Hv8KyBEqCKxGEdiUK4rCXPXJAoFXblYzjJBapbXmcloLy27vjOmHBF7/5eDPPnpGLVsrjsVs2ueyEL6H4cEOAXJtaveXs9/uf5uGZ8e6uhL@wqjbl9Xl19bO4Z4/amAO76W6rq8t79mxtjRZ7ePrFiuV43Fld0zaX1kCgsTAtA6dfzRI41SZQU5APkjmPuMnZ2pzB2izwrA3jNBRLkpGssZ7mMVnTO3q5xOuWGrwuLgqSIfuTfraorgFzkAorvYnsrMlnOJKRkFhmK7TJT32zr5L28RGrDfJjhLXWKMYjAjGAaGdDqW1/SNh5W9fatMnaCTkM24Rf7GDqyW37iSqF1xhIBgpRXtrBwxR1yoeEQqfbDuZCIUzdlLetMnYA@v4pzUrV24m2F@ASOth9H2WN8QPIt0eGOLf/j@x1QBn0RZvENGoPTqCUZAoU2Vs3NfNK6lrvNMw69QRAb92rNhAbfm/ndjI1Y70S7iSIZG0@LQynpz/ntPoRB4T@tFY4@XhzOrvjXnGKxTAVXePxHw "C (gcc) – Try It Online")
The first order of business was to find some hash function that would separate the words into their categories. After some fiddling about I stumbled upon `(s[0] ^ (s[1] << 2)) & 0x7f`, where the 0x7f is of course there to bring it down to printable ASCII levels. This produced the following information (the tables are sorted, but not the resulting strings):
```
Woody:
----
erogenous zone  - 45
prodding        8 56
yowling         E 69
vole            J 74
intercourse     Q 81
thighs          T 84
gone            [ 91
botty           ^ 94
bound           ^ 94
ocelot          c 99
pert            d 100
caribou         g 103
seemly          g 103
vacuum          r 114
wasp            s 115
sausage         w 119
[wg8r^JgQdT^-csE
Tinny:
----
litter bin      H 72
tit             P 80
simpkins        W 87
antelope        Y 89
recidivist      f 102
newspaper       z 122
HzYfPW
PVC:
----
leap            x 120
x
```
The hash collisions don't matter, since they are confided to the same category. We only have to check if the resulting hash is in the Tinny hashes string ("HzYfPW"), since the Woody hashes are all below the PVC hash (120). If 120 or higher, and not a Tinny word, it must be PVC. If not a Tinny word, and the hash is below 120, then it must be a good, woody sort of word.
[Answer]
# [Stax](https://github.com/tomtheisen/stax), 30 25 [bytes](https://github.com/tomtheisen/stax/blob/master/docs/packed.md#packed-stax)
```
ï═H♣║GÇX→ΩM+@╢^j╬♪►╨╝ô╤c\
```
[Run and debug it](https://staxlang.xyz/#p=8bcd45689de6f00f3920ac0ff2b4d49ad3ef75a57a119a4ede&i=gone%0Asausage%0Aseemly%0Aprodding%0Avacuum%0Abound%0Avole%0Acaribou%0Aintercourse%0Apert%0Athighs%0Abotty%0Aerogenous+zone%0Aocelot%0Awasp%0Ayowling%0Alitter+bin%0Anewspaper%0Aantelope%0Arecidivist%0Atit%0Asimpkins%0Aleap&a=1&m=2)
The commented ascii representation is this. I didn't invent this algorithm. It's shamelessly ripped off [Jonathan Allen's python solution](https://codegolf.stackexchange.com/a/157816/527).
```
9@                  10th character, modularly indexed
`#!z"pi0$L+%v9`X    store "tinny pvc woody" in the x register
3(                  keep only the first 3 characters ("tin")
#                   how many times the 10th char occurs in tin? (a)
y.eaI               index of "ea" in the input or -1 (b)
+                   a + b (one of -1, 0, or 1)
xj@                 modularly indexed word in x
```
[Run this one](https://staxlang.xyz/#c=9%40%09%09%0910th+character,+modularly+indexed%0A%60%23%21z%22pi0%24L%2B%25v9%60Y%09store+%22tinny+pvc+woody%22+in+the+y+register%0A3%28%09%09%09keep+only+the+first+3+characters+%28%22tin%22%29%0A%23+++++++++%09%09how+many+times+the+10th+char+occurs+in+tin%3F+%28a%29%0Ay.eaI%09%09%09index+of+%22ea%22+in+the+input+or+-1+%28b%29%0A%2B%09%09%09a+%2B+b+%28one+of+-1,+0,+or+1%29%0Ayj%40%09%09%09modularly+indexed+word+in+y&i=gone%0Asausage%0Aseemly%0Aprodding%0Avacuum%0Abound%0Avole%0Acaribou%0Aintercourse%0Apert%0Athighs%0Abotty%0Aerogenous+zone%0Aocelot%0Awasp%0Ayowling%0Alitter+bin%0Anewspaper%0Aantelope%0Arecidivist%0Atit%0Asimpkins%0Aleap&a=1&m=2)
[Answer]
# x86 32-bit machine code, 39 bytes
Hexdump:
```
69 01 47 6f 61 2c c7 02 50 56 43 00 3a c4 74 16
c7 02 77 6f 6f 64 85 c0 78 06 c7 02 74 69 6e 6e
66 c7 42 04 79 00 c3
```
The hash function is multiplication by a "magic" number `0x2c616f47`. There are only 6 numbers that can be used with this code.
First of all, it writes `PVC` to the output. This will be overwritten, if needed.
After hashing, it checks for the PVC word; the check is `al = ah` - I chose it because it's a small 2-byte instruction. Then, it writes either `wood` or `tinn`, depending on the sign of the hashed result. Then, it writes `y`.
Assembly code:
```
    imul eax, [ecx], 0x2c616f47;
    mov dword ptr [edx], 'CVP';
    cmp al, ah;
    je done;
    mov dword ptr [edx], 'doow';
    test eax, eax;
    js skip;
    mov dword ptr [edx], 'nnit';
skip:
    mov word ptr [edx + 4], 'y';
done:
    ret;
```
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~27~~ 26 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
```
⁵ịe“Ṗµ»_⁼“ḣG»$ị“©LẈḊ¶$Ḍ»Ḳ¤
```
A monadic link accepting and returning lists of characters.
**[Try it online!](https://tio.run/##JY2xTsQwDIZfheGkLrzHLbwBQiikVs6QxlHSXFUmjuVOwMzEBgsSE9KhQm8K4kHSFwlOb7E//7b//xq07nOeNvs0PsJ095K@n@M@jpfT5lCm4XUZxwXveIjvZ@lnl4aH@LVIw1Mc0/AZ3/Lf4Xc73X8scz6vFBmoTisvghdqJoBG9wzWUV2jUYxrIUNoGK4omLoIpMutFA5ZYkLTgpMUnC@6Bddya1eoVn5@a9tiCY4UGAr@5PYYSxI0ldNOeMutp04fIw103go2YhZsrsmWBwcSa1yjn/2xVI@NvUFTcjQIW138Aw "Jelly – Try It Online")**
### How?
```
⁵ịe“Ṗµ»_⁼“ḣG»$ị“©LẈḊ¶$Ḍ»Ḳ¤ - Link: list of characters, W   e.g. "gone"  "leap"  "newspaper"
⁵                          - literal ten                  10
 ị                         - index into (1-based & modular)     'o'     'e'     'n'
   “Ṗµ»                    - compression of characters    "int"
  e                        - exists in?                          0       0       1
              $            - last two links as a monad
          “ḣG»             -   compression of characters  "leap"
         ⁼                 -   equal?                            0       1       0
        _                  - subtract                            0      -1       1
                         ¤ - nilad followed by link(s) as a nilad:
                “©LẈḊ¶$Ḍ»  -   compression of characters  "tinny PVC woody"
                         Ḳ -   split at spaces            ["tinny","PVC","woody"]
               ị           - index into (1-based & modular)     "woody" "PVC"   "tinny"
```
[Answer]
# [Haskell](https://www.haskell.org/), 75 bytes
*-2 bytes thanks to Laikoni.*
```
f"leap"="PVC"
f s|take 2s`elem`words"li ne ti si an re"="tinny"|1>0="woody"
```
[Try it online!](https://tio.run/##TZGxasQwDIb3ewrhqYVS2u7p0rnQqUspnC5REhFHMpZzIeXePTU32PHk75f4/YFHtIm83/feecLgGvf1/eFOPdgt4UTwZmfyNJ9XjZ05zyAEicEYUCBS3k8ssrnb6/tL41bVbnP7jCzQwIzhEx5CZEnwDP3jCfL5ATeokLvDEzjDxXA4MNHst4IhatexDCW4Yrssc8GLLtLVofra1GLkPC6cNSi2ukSrO4FiKpBGHkY7VKdURSjqQKKLwd9RX1vyWitWtFBg09Uf1T2nbAAXlhIJrRYwW5QEs6XXUF@I1HLHV7aDKNe78Rwmlqp9/0b43f8B "Haskell – Try It Online")
RIP `enklact`.
[Answer]
# [Dirty](https://github.com/Ourous/dirty), ~~73~~ ~~57~~ 54 bytes
```
⇖'le'⇗≐∀⭦)Ẃ'nar'⇗{=]}⭨'i'=]'woody'‼␛['tinny'‼␛('PVC'‼␛
```
[Try it online!](https://tio.run/##S8ksKqn8//9R@zT1nFT1R@3TH3VOeNTR8GjtMs2Hu5rU8xKLQILVtrG1j9auUM9Ut41VL8/PT6lUf9Sw59GE2dHqJZl5eTCehnpAmDOU/f//f6Wc1MQCJQA "Dirty – Try It Online")
**Explained:**
*For a similar older version (I'll update it when I stop golfing it)*
```
␛‼'CVP'⇨⇖'leap'⇗≡⊭◌⬅Ẃ'nar'⇗{=]}1ẁ'i'=]'woody'‼␛['tinny'‼␛
```
The body of this is made up of:
```
⇖            put the input into the left stack
 'leap'      push the string "leap"
       ⇗     put that string into the right stack
        ≡    are the left and right stacks equal
         ⊭   logically negate
          ◌  skip next instruction if true
           ⬅ change direction to leftwards
```
If we end up going left, then we have:
```
       ⇨⇖'leap'⇗≡⊭◌ does stuff to the stacks, but isn't relevant
  'CVP'              push the string "PVC" (reversed, because we're going left)
 ‼                   print the string on the main stack
␛                    exit the program (this should wrap into the other exit, but that isn't working yet)
```
Otherwise, this checks if the string starts with any of "nar":
```
Ẃ           wipe the right stack
 'nar'      push the string "nar"
       ⇗    move string to right stack
        {
         =  compare the top of the left and right stacks
          ] goto matching bracket if true
        }   consuming loop while the right stack is true
```
We then check if the second letter is "i":
```
1        push the number 1
 ẁ       drop ^ number of elements off of the left stack
  'i'    push "i"
     =   are the top of the left and middle stacks equal
       ] goto matching bracket if true
```
If they all fall through, we run into
```
'woody'   push the string "woody"
       ‼  print the string on the main stack
        ␛ exit the program
```
If we ended up jumping, we wrap around to
```
[          matching bracket for the goto
 'tinny'   push the string "tinny"
        ‼  print the string on the main stack
         ␛ exit the program
```
[Answer]
## C# 97 Bytes
```
string t(string w)=>w[0]!='p'&new[]{10,9,8,3}.Contains(w.Length)?"tinny":w[0]=='l'?"pvc":"woody";
```
I went looking for a pattern in the length of the strings and found they are unique except for lengths 4 and 8. So I special case those by looking at the first characters. Oh well, it's still shorter than some answers. :)
[Answer]
# [Python](https://docs.python.org/3/), 59 bytes
```
lambda w:"wtPoiVonCdn yy"[(w*4)[9]in"tin"or(w[2]<"b")*2::3]
```
**[Try it online!](https://tio.run/##LVDLboMwEDy3X2H5AkRp1TwuQW0u/YGeekk5GDCwqtm1bBOLRvl2apscVjP7mlmtnt1AeFi6j59FibFuBfMl9@6L4Jvws0U2z/yS@82xuJwqQO5CkMn9ZV@985oXm31ZHqqlI8OctI4BsjzrCWW2ZZkVkxX9SqUc1RyZNtS2gH3kV9FM0xhZTRO2qUQqLTTCQChGCuikaWgyNnW0NC6iG6Af7LrsXNKWhnqJNFn29ziBGqkojXthdcSZvHrYK3BBmdWAMUPprRZBPSYieCrSScPIBlq4gl1tIYGFUf8CJn8lhc6K8vlJm3Brzm9v5Xl3vLOXM7vt7vw1fGcULo8P2rIuYVEUyz8 "Python 3 – Try It Online")**
Uses the indexing from [ovs's Python answer](https://codegolf.stackexchange.com/a/157284/53748) but a simpler and shorter choice function:
If the tenth letter of the word, `w`, with wrapping (`(w*4)[9]` - where `w*4` repeats `w` four times) is a letter in the word **tin** (`in"tin"`) then the word is ***tinny***, otherwise if the third letter (`w[2]`) is an **a** (`<'b'`) then the word is ***PVC*** otherwise the word is ***woody***.
...this 59 does the same job:
```
lambda w:"wtPoiVonCdn yy"[[(w*4)[9]in"tin",2][w[2]<"b"]::3]
```
[Answer]
# C, 107 bytes
```
k;f(char*s){for(k=0;*s;)k+=*s++;k%=100;puts(k-18?(k-5)*(k-81)*(k-56)*(k-78)*(k-37)?"woody":"tinny":"PVC");}
```
[Try it online!](https://tio.run/##fVDLasMwELz7K4yh4AeBmJLG1IQc@gM99a7IsrPY1gqtFOOGfLurmrasL9Vhhxmtdmckd52Uy9LXbSqvwuaU3Vu0aX/a1znVWV@cciqKun86lft9bbyjtN@V1TnUQ5aHWpUrHF5WOFYrPB@zczIhNnPymjjQ@hvfP96SrH4soF08CtBpFt2jOJw2TTrUKlz@UhKeRLdRlBqHmQnGYtOA7ph0E9L7kQkX9LrhDTjwmVJYCC1MCdaUlegt8T6jrGPUXaG70maNc9yastgpjZ7iz20slGpAPmoSZBidcRp@Iq3S@t3JHw0dA7jgML6AZs@0msiI4JJpIiQZ0PDtVklo4Aa0CQOcEYymB03/OVBitRw9li8)
[Answer]
## Batch, 145 bytes
```
@set/ps=
@if %s%==leap echo PVC&exit/b
@for %%s in (a n r)do @if %s:~,1%==%%s echo tinny&exit/b
@if %s:~1,1%==i echo tinny&exit/b
@echo woody
```
Takes input on STDIN. Explanation: After checking for `leap`, tinny words either begin with one of the letters `a`, `n` or `r` or their second letter is `i`.
[Answer]
## [CJam](https://sourceforge.net/p/cjam), 35 bytes
```
1b_856%338<\418=-"woodytinnyPVC"5/=
```
[Try it online!](https://tio.run/##FcxBSwMxEIbh@/yKUvAoS6mVPdiT9@LJkyLZZEhHszMxM9klir99TU8fL3w8/tPN2/dl@N0O08d4erw7Hsent4fDeL7fryKhGTG3l9fn/Wk4b@/8N2xRGEFdVRf7Is6pQS4SAnGExflaZ5ikcoBFEoJ3hXoCsWHxUosiZCwGdqV41X41a4BFIrJU3f3cePGYxGB1mqHJmm50IuvCbiIGxlWz6wq4ribJCAU9BVpIO0wGSnP@IlZI6PI/ "CJam – Try It Online")
I completely forgot that I had started a brute force search for short expressions to hash the woody and tinny strings into two classes. I just found the console window where the search ran and it turns out it actually found something...
### Explanation
```
1b     e# Sum the code points of the input string.
       e# The result is unique for each input, except "pert" and "wasp" which
       e# both sum to 443. But they're both woody, so that's fine.
_      e# Duplicate.
856%   e# Take the sum modulo 856.
338<   e# Check whether the result is less than 338. That's true for all
       e# tinny words.
\      e# Swap with the other copy of the sum.
418=   e# Check whether the sum is equal to 418, which identifies "leap".
-      e# Subtract. Gives -1 for "leap", 1 for tinny words and 0 for woody words.
"woodytinnyPVC"5/
       e# Create the list ["woody" "tinny" "PVC"].
       e# Select the correct string.
```
[Answer]
# Excel, 81 bytes
```
=IF(ISNUMBER(FIND(LEFT(A1,2),"anetisilire")),"tinny",IF(A1="leap","PVC","woody"))
```
Using the 'anetisilire' method.
[Answer]
# [Japt](https://github.com/ETHproductions/japt/), ~~36~~ 34 bytes
Uses a RegEx from Martin's Retina solution.
```
g2 ¶'a?"PVC":`wÅnyy`ë2Uè`?t|.pe
```
[Try it](https://ethproductions.github.io/japt/?v=1.4.5&code=ZzIgtidhPyJQVkMiOmB3kcUIbnl5YOsyVehgiT90fC5wZQ==&input=ImxlYXAi) | [Check all test cases](https://ethproductions.github.io/japt/?v=1.4.5&code=rmcyILYnYT8iUFZDIjpgd5HFCG55eWDrMlroYIk/dHwucGU=&input=WyJnb25lIiwic2F1c2FnZSIsInNlZW1seSIsInByb2RkaW5nIiwidmFjdXVtIiwiYm91bmQiLCJ2b2xlIiwiY2FyaWJvdSIsImludGVyY291cnNlIiwicGVydCIsInRoaWdocyIsImJvdHR5IiwiZXJvZ2Vub3VzIHpvbmUiLCJvY2Vsb3QiLCJ3YXNwIiwieW93bGluZyIsImxpdHRlciBiaW4iLCJuZXdzcGFwZXIiLCJhbnRlbG9wZSIsInJlY2lkaXZpc3QiLCJ0aXQiLCJzaW1wa2lucyIsImxlYXAiXQ==)
[Answer]
# JavaScript, ~~60~~, 50
**EDIT** I saw all the other regex answers. I guess I'm just blind. Anyway, here's one using the same regex
```
i=="leap"?"PVC":/.p.|is*t/.test(i)?"tinny":"woody"
```
Also, now, it beats the other JS answer
Snippet:
```
let test = i => i=="leap"?"PVC":/.p.|is*t/.test(i)?"tinny":"woody"
let woody = `gone
sausage
seemly
prodding
vacuum
bound
vole
caribou
intercourse
pert
thighs
botty
erogenous zone
ocelot
wasp
yowling`;
console.log("THESE SHOULD BE woody");
woody.split("\n").forEach(el => console.log(test(el)));
let tinny = `litter bin
newspaper
antelope
recidivist
tit
simpkins`;
console.log("THESE SHOULD BE tinny");
tinny.split("\n").forEach(el => console.log(test(el)));
console.log("THIS SHOULD BE PVC");
console.log(test("leap"));
```
## Old answer
I didn't see any with regex yet, so I thought I'd give it a try
```
i=="leap"?"PVC":/[gyuz]|[or][tl]|as/.test(i)?"woody":"tinny"
```
Not sure if this counts as 60 or more because I didn't include a return statement. Will add a snippet when I get on my computer
**Edit: Snippet**
```
let test = i => i=="leap"?"PVC":/[gyuz]|[or][tl]|as/.test(i)?"woody":"tinny"
let woody = `gone
sausage
seemly
prodding
vacuum
bound
vole
caribou
intercourse
pert
thighs
botty
erogenous zone
ocelot
wasp
yowling`;
console.log("THESE SHOULD BE woody");
woody.split("\n").forEach(el => console.log(test(el)));
let tinny = `litter bin
newspaper
antelope
recidivist
tit
simpkins`;
console.log("THESE SHOULD BE tinny");
tinny.split("\n").forEach(el => console.log(test(el)));
console.log("THIS SHOULD BE PVC");
console.log(test("leap"));
```
]